diff --git a/autobuild.xml b/autobuild.xml
index f07cae8e81b8f94866f6341cae2c8002d2b9f7fb..7f18ab9abfb92de48cee48e7e7a5ad2e1bc1d01c 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -225,36 +225,6 @@
         <key>version</key>
         <string>1.57</string>
       </map>
-      <key>chardet</key>
-      <map>
-        <key>copyright</key>
-        <string>Contributors to charset (see https://github.com/chardet/chardet)</string>
-        <key>description</key>
-        <string>Python Character Encoding Library</string>
-        <key>license</key>
-        <string>LGPL</string>
-        <key>license_file</key>
-        <string>LICENSES/chardet.txt</string>
-        <key>name</key>
-        <string>chardet</string>
-        <key>platforms</key>
-        <map>
-          <key>darwin64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>0124862b6a1b88455c78a68f8b823d21</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6662/23578/chardet-3.0.4-darwin64-506651.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin64</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>3.0.4</string>
-      </map>
       <key>colladadom</key>
       <map>
         <key>copyright</key>
@@ -1465,36 +1435,6 @@
         <key>version</key>
         <string>2012.1-2</string>
       </map>
-      <key>idna</key>
-      <map>
-        <key>copyright</key>
-        <string>Copyright (c) 2013-2017, Kim Davies. All rights reserved.</string>
-        <key>description</key>
-        <string>Python Internationalized Domain Names in Applications (IDNA) Library</string>
-        <key>license</key>
-        <string>see idna.rst</string>
-        <key>license_file</key>
-        <string>LICENSES/idna.rst</string>
-        <key>name</key>
-        <string>idna</string>
-        <key>platforms</key>
-        <map>
-          <key>darwin64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>7dfe9fc4023d7d4f511dd9fac7258266</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6663/23584/idna-2.5-darwin64-506652.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin64</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>2.5</string>
-      </map>
       <key>jpeglib</key>
       <map>
         <key>copyright</key>
@@ -2173,46 +2113,6 @@
         <key>version</key>
         <string>0.0.1</string>
       </map>
-      <key>llbase</key>
-      <map>
-        <key>copyright</key>
-        <string>Copyright (c) 2010, Linden Research, Inc.</string>
-        <key>license</key>
-        <string>mit</string>
-        <key>license_file</key>
-        <string>LICENSES/llbase-license.txt</string>
-        <key>name</key>
-        <string>llbase</string>
-        <key>platforms</key>
-        <map>
-          <key>darwin64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>e18eeb0691af053b83bd46b76c6ee86a</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6299/21982/llbase-0.9.3.506286-darwin64-506286.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin64</string>
-          </map>
-          <key>windows</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>e6865670f9bca1c82fb8b91db3ea515c</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6301/21994/llbase-0.9.3.506286-windows-506286.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>windows</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>0.9.3.506286</string>
-      </map>
       <key>llca</key>
       <map>
         <key>copyright</key>
@@ -2955,52 +2855,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>version</key>
         <string>8.35.500898</string>
       </map>
-      <key>requests</key>
-      <map>
-        <key>copyright</key>
-        <string>Copyright 2016 Kenneth Reitz</string>
-        <key>description</key>
-        <string>Python HTTP Library</string>
-        <key>license</key>
-        <string>Apache</string>
-        <key>license_file</key>
-        <string>LICENSES/requests.txt</string>
-        <key>name</key>
-        <string>requests</string>
-        <key>platforms</key>
-        <map>
-          <key>darwin64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>b8d134a970261b445a3f376ba4e05ff7</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6693/23788/requests-2.18.1-darwin64-506681.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin64</string>
-          </map>
-          <key>linux64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>a92f2235991871c3d601a73cfef9b2af</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4105/11530/requests-1.0-linux64-504094.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux64</string>
-          </map>
-        </map>
-        <key>source</key>
-        <string>https://bitbucket.org/lindenlab/p64_python-requests</string>
-        <key>source_type</key>
-        <string>hg</string>
-        <key>version</key>
-        <string>2.18.1</string>
-      </map>
       <key>slvoice</key>
       <map>
         <key>copyright</key>
@@ -3211,36 +3065,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>version</key>
         <string>0.8.0.1</string>
       </map>
-      <key>urllib3</key>
-      <map>
-        <key>copyright</key>
-        <string>Copyright 2008-2016 Andrey Petrov and contributors (see CONTRIBUTORS.txt)</string>
-        <key>description</key>
-        <string>Python HTTP Library</string>
-        <key>license</key>
-        <string>MIT</string>
-        <key>license_file</key>
-        <string>LICENSES/urllib3.txt</string>
-        <key>name</key>
-        <string>urllib3</string>
-        <key>platforms</key>
-        <map>
-          <key>darwin64</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>22f64c7fbb6704d2e9519fd1cca8e49b</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/6659/23560/urllib3-1.21.1-darwin64-506648.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin64</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>1.21.1</string>
-      </map>
       <key>viewer-manager</key>
       <map>
         <key>copyright</key>
@@ -3248,7 +3072,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>description</key>
         <string>Linden Lab Viewer Management Process suite.</string>
         <key>license</key>
-        <string>Proprietary</string>
+        <string>viewerlgpl</string>
         <key>license_file</key>
         <string>LICENSE</string>
         <key>name</key>
@@ -3260,9 +3084,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f45c0a5e7b4601b355e163bf62f5718e</string>
+              <string>904caf508ec1718e1fc9cd321ad95715</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/20587/147509/viewer_manager-1.0.517052-darwin64-517052.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/24994/196128/viewer_manager-2.0.519951-darwin64-519951.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3284,9 +3108,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d2443caf062697430071d458a965f611</string>
+              <string>e7f7ed2d40c1e554d038276fef690639</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/20588/147516/viewer_manager-1.0.517052-windows-517052.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/24996/196136/viewer_manager-2.0.519951-windows-519951.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3297,7 +3121,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>1.0.517052</string>
+        <string>2.0.519951</string>
       </map>
       <key>vlc-bin</key>
       <map>
diff --git a/indra/cmake/LLBase.cmake b/indra/cmake/LLBase.cmake
deleted file mode 100644
index 76e3c688a3a0bf941d2f250c53f1d1f07375b08b..0000000000000000000000000000000000000000
--- a/indra/cmake/LLBase.cmake
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-use_prebuilt_binary(llbase)
diff --git a/indra/cmake/Requests.cmake b/indra/cmake/Requests.cmake
deleted file mode 100644
index b9c729d6970a1d160b1e60f8a4e949607eaf1223..0000000000000000000000000000000000000000
--- a/indra/cmake/Requests.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-if (DARWIN)
-   include (Prebuilt)
-   use_prebuilt_binary(requests)
-   use_prebuilt_binary(urllib3)
-   use_prebuilt_binary(chardet)
-   use_prebuilt_binary(idna)
-endif (DARWIN)
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index 79c436274743cd40f224c465e6d365cabd1160cd..87dc1b9795f518d4b4e2e0d12cb2ea6c4a2bc646 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -171,9 +171,9 @@ void LLDir_Mac::initAppDirs(const std::string &app_name,
 	if (!app_read_only_data_dir.empty())
 	{
 		mAppRODataDir = app_read_only_data_dir;
-		mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
+		mSkinBaseDir = add(mAppRODataDir, "skins");
 	}
-	mCAFile = getExpandedFilename(LL_PATH_EXECUTABLE, "../Resources", "ca-bundle.crt");
+	mCAFile = add(mAppRODataDir, "ca-bundle.crt");
 }
 
 std::string LLDir_Mac::getCurPath()
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 843294c239826d8f35b3f3cf88c9dd11b574ad6d..d4afbb15df4f7a8fd1ebd58fdbd9d8f13cc31a86 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1429,12 +1429,10 @@ static CursorRef gCursors[UI_CURSOR_COUNT];
 static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY)
 {
 	// cursors are in <Application Bundle>/Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif
-	std::string fullpath = gDirUtilp->getAppRODataDir();
-	fullpath += gDirUtilp->getDirDelimiter();
-	fullpath += "cursors_mac";
-	fullpath += gDirUtilp->getDirDelimiter();
-	fullpath += cursorIDToName(cursorid);
-	fullpath += ".tif";
+	std::string fullpath = gDirUtilp->add(
+		gDirUtilp->getAppRODataDir(),
+		"cursors_mac",
+		cursorIDToName(cursorid) + std::string(".tif"));
 
 	gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY);
 }
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 2fc722d4c3e0c0cd33778edfeb45c8a03b596ea1..e7111ebe54de7da82409f4197388aecda59ae6d4 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -16,7 +16,6 @@ include(GLOD)
 include(Hunspell)
 include(JsonCpp)
 include(LLAppearance)
-include(LLBase)
 include(LLAudio)
 include(LLCA)
 include(LLCharacter)
@@ -44,7 +43,6 @@ include(OPENAL)
 include(OpenGL)
 include(OpenSSL)
 include(PNG)
-include(Requests)
 include(TemplateCheck)
 include(UI)
 include(UnixInstall)
@@ -2056,13 +2054,7 @@ endif (LINUX)
 if (DARWIN)
   # These all get set with PROPERTIES
   set(product "Second Life")
-  # this is the setting for the Python wrapper, see SL-322 and WRAPPER line in Info-SecondLife.plist
-  if (PACKAGE)
-      set(MACOSX_WRAPPER_EXECUTABLE_NAME "SL_Launcher")
-  else (PACKAGE)
-      # force the name of the actual executable to allow running it within Xcode for debugging
-      set(MACOSX_WRAPPER_EXECUTABLE_NAME "../Resources/Second Life Viewer.app/Contents/MacOS/Second Life")
-  endif (PACKAGE)
+  set(MACOSX_EXECUTABLE_NAME "Second Life")
   set(MACOSX_BUNDLE_INFO_STRING "Second Life Viewer")
   set(MACOSX_BUNDLE_ICON_FILE "secondlife.icns")
   set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.secondlife.indra.viewer")
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index af4cf26ac6838e08e7ee9fd4352a2d79516acfb1..31b4201f470adb144a025cb614781b8f0daab896 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -5,7 +5,7 @@
 	<key>CFBundleDevelopmentRegion</key>
 	<string>English</string>
 	<key>CFBundleExecutable</key>
-	<string>${MACOSX_WRAPPER_EXECUTABLE_NAME}</string>
+	<string>${MACOSX_EXECUTABLE_NAME}</string>
 	<key>CFBundleGetInfoString</key>
 	<string>${MACOSX_BUNDLE_INFO_STRING}</string>
 	<key>CFBundleIconFile</key>
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 14c8dba39f19c2ff18f4f9f583571371c9415201..76187b49a574135284c60232bf0a315a419cd0a4 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -299,7 +299,7 @@ StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)"
 CreateDirectory	"$SMPROGRAMS\$INSTSHORTCUT"
 SetOutPath "$INSTDIR"
 CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
-				"$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+				"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
 
 
 WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Create Account.url" \
@@ -317,9 +317,9 @@ CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \
 # Other shortcuts
 SetOutPath "$INSTDIR"
 CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
-        "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+        "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
 CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \
-        "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+        "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
 CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
 				'"$INSTDIR\uninst.exe"' ''
 
@@ -327,7 +327,7 @@ CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
 WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR"
 WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}"
 WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE"
+WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$VIEWER_EXE"
 WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "Publisher" "Linden Research, Inc."
 WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLInfoAbout" "http://secondlife.com/whatis/"
 WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLUpdateInfo" "http://secondlife.com/support/downloads/"
@@ -338,10 +338,10 @@ WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninst
 WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "0x0001D500"		# ~117 MB
 
 # from FS:Ansariel
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayIcon" '"$INSTDIR\$INSTEXE"'
+WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayIcon" '"$INSTDIR\$VIEWER_EXE"'
 
 # BUG-2707 Disable SEHOP for installed viewer.
-WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE" "DisableExceptionChainValidation" 1
+WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$VIEWER_EXE" "DisableExceptionChainValidation" 1
 
 # Write URL registry info
 WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "(default)" "URL:Second Life"
@@ -358,9 +358,8 @@ WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" '"$INSTDIR\$
 # URL param must be last item passed to viewer, it ignores subsequent params to avoid parameter injection attacks.
 WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" '"$INSTDIR\$VIEWER_EXE" -url "%1"'
 
-# Only allow Launcher to be the icon
-WriteRegStr HKEY_CLASSES_ROOT "Applications\$INSTEXE" "IsHostApp" ""
-WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
+WriteRegStr HKEY_CLASSES_ROOT "Applications\$VIEWER_EXE" "IsHostApp" ""
+##WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
 
 # Write out uninstaller
 WriteUninstaller "$INSTDIR\uninst.exe"
@@ -398,8 +397,8 @@ Call un.CloseSecondLife
 DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG"
 DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
 # BUG-2707 Remove entry that disabled SEHOP
-DeleteRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE"
-DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
+DeleteRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$VIEWER_EXE"
+##DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
 DeleteRegKey HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}"
 
 # Clean up shortcuts
@@ -537,6 +536,7 @@ Function RemoveProgFilesOnInst
 
 # Remove old SecondLife.exe to invalidate any old shortcuts to it that may be in non-standard locations. See MAINT-3575
 Delete "$INSTDIR\$INSTEXE"
+Delete "$INSTDIR\$VIEWER_EXE"
 
 # Remove old shader files first so fallbacks will work. See DEV-5663
 RMDir /r "$INSTDIR\app_settings\shaders"
@@ -673,7 +673,7 @@ FunctionEnd
 ;; After install completes, launch app
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 Function .onInstSuccess
-Call CheckWindowsServPack		# Warn if not on the latest SP before asking to launch.
+        Call CheckWindowsServPack		# Warn if not on the latest SP before asking to launch.
         Push $R0
         Push $0
         ;; MAINT-7812: Only write nsis.winstall file with /marker switch
@@ -694,8 +694,21 @@ Call CheckWindowsServPack		# Warn if not on the latest SP before asking to launc
         Pop $R0
         Push $R0					# Option value, unused# 
         StrCmp $SKIP_AUTORUN "true" +2;
-# Assumes SetOutPath $INSTDIR
-	Exec '"$WINDIR\explorer.exe" "$INSTDIR\$INSTSHORTCUT.lnk"'
+        # Assumes SetOutPath $INSTDIR
+        # Run INSTEXE (our updater), passing VIEWER_EXE plus the command-line
+        # arguments built into our shortcuts. This gives the updater a chance
+        # to verify that the viewer we just installed is appropriate for the
+        # running system -- or, if not, to download and install a different
+        # viewer. For instance, if a user running 32-bit Windows installs a
+        # 64-bit viewer, it cannot run on this system. But since the updater
+        # is a 32-bit executable even in the 64-bit viewer package, the
+        # updater can detect the problem and adapt accordingly.
+        # Once everything is in order, the updater will run the specified
+        # viewer with the specified params.
+        # Quote the updater executable and the viewer executable because each
+        # must be a distinct command-line token, but DO NOT quote the language
+        # string because it must decompose into separate command-line tokens.
+        Exec '"$INSTDIR\$INSTEXE" precheck "$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
         Pop $R0
 # 
 FunctionEnd
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 687b76c224ca7e5fef0952edcf9d9ece29fc8280..c0fcdd7c798a8e67fd941a1363264fbd562551d7 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1083,26 +1083,6 @@ bool LLAppViewer::init()
 		}
 	}
 
-// don't nag developers who need to run the executable directly
-#if LL_RELEASE_FOR_DOWNLOAD
-	// MAINT-8305: If we're processing a SLURL, skip the launcher check.
-	if (gSavedSettings.getString("CmdLineLoginLocation").empty())
-	{
-		const char* PARENT = getenv("PARENT");
-		if (! (PARENT && std::string(PARENT) == "SL_Launcher"))
-		{
-			// Don't directly run this executable. Please run the launcher, which
-			// will run the viewer itself.
-			// Naturally we do not consider this bulletproof. The point is to
-			// gently remind a user who *inadvertently* finds him/herself in this
-			// situation to do things the Right Way. Anyone who intentionally
-			// bypasses this mechanism needs no reminder that s/he's shooting
-			// him/herself in the foot.
-			LLNotificationsUtil::add("RunLauncher");
-		}
-	}
-#endif
-
 #if LL_WINDOWS
 	if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion())
 	{
@@ -1150,6 +1130,23 @@ bool LLAppViewer::init()
 
 	gGLActive = FALSE;
 
+#if LL_WINDOWS
+	std::vector<std::string> updater
+		{ gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater.exe") };
+#elif LL_DARWIN
+	// explicitly run the system Python interpreter on updater.py
+	std::vector<std::string> updater
+		{ "python", gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", "updater.py") };
+#else
+	std::vector<std::string> updater
+		{ gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater") };
+#endif
+	// add LEAP mode command-line argument to whichever of these we selected
+	updater.push_back("leap");
+
+	// Run the updater. An exception from the updater should bother us.
+	LLLeap::create("updater process", updater, true);
+
 	// Iterate over --leap command-line options. But this is a bit tricky: if
 	// there's only one, it won't be an array at all.
 	LLSD LeapCommand(gSavedSettings.getLLSD("LeapCommand"));
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 7a4c41779a62820b17fff86caf808960462bbc1a..4c51873715f8083a525ad6ea7997aa9e5898ce7b 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -479,8 +479,7 @@ bool idle_startup()
 			if (!found_template)
 			{
 				message_template_path =
-					gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE,
-												   "../Resources/app_settings",
+					gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
 												   "message_template.msg");
 				found_template = LLFile::fopen(message_template_path.c_str(), "r");		/* Flawfinder: ignore */
 			}		
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index b90e09b739da99256e3f62e42ace4816e4eebcb6..88d17a31a462af9d138e2b3919add882f1ec4db0 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -770,14 +770,13 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
     {
 #ifndef VIVOXDAEMON_REMOTEHOST
         // Launch the voice daemon
-        std::string exe_path = gDirUtilp->getExecutableDir();
-        exe_path += gDirUtilp->getDirDelimiter();
+        std::string exe_path = gDirUtilp->getAppRODataDir();
 #if LL_WINDOWS
-        exe_path += "SLVoice.exe";
+        gDirUtilp->append(exe_path, "SLVoice.exe");
 #elif LL_DARWIN
-        exe_path += "../Resources/SLVoice";
+        gDirUtilp->append(exe_path, "SLVoice");
 #else
-        exe_path += "SLVoice";
+        gDirUtilp->append(exe_path, "SLVoice");
 #endif
         // See if the vivox executable exists
         llstat s;
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 541112a7659b6b969415c4ef79e87809182c079f..57da87a3ee52f843b034ba4e5bdeaf47d9751c55 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -470,7 +470,7 @@ def test_for_no_msvcrt_manifest_and_copy_action(self, src, dst):
                     pass
                 except NoMatchingAssemblyException as err:
                     pass
-                    
+
                 self.ccopy(src,dst)
             else:
                 raise Exception("Directories are not supported by test_CRT_and_copy_action()")
@@ -490,7 +490,7 @@ def construct(self):
 
             with self.prefix(src=os.path.join(pkgdir, "VMP"), dst=""):
                 # include the compiled launcher scripts so that it gets included in the file_list
-                self.path('SL_Launcher.exe')
+                self.path('updater.exe')
                 #IUM is not normally executed directly, just imported.  No exe needed.
                 self.path("InstallerUserMessage.py")
 
@@ -502,11 +502,6 @@ def construct(self):
                 self.path("*.png")
                 self.path("*.gif")
 
-            #before, we only needed llbase at build time.  With VMP, we need it at run time.
-            with self.prefix(src=os.path.join(pkgdir, "lib", "python", "llbase"), dst="llbase"):
-                self.path("*.py")
-                self.path("_cllsd.so")
-
         # Plugin host application
         self.path2basename(os.path.join(os.pardir,
                                         'llplugin', 'slplugin', self.args['configuration']),
@@ -768,7 +763,7 @@ def package_finish(self):
         substitution_strings['installer_file'] = installer_file
         
         version_vars = """
-        !define INSTEXE "SL_Launcher.exe"
+        !define INSTEXE "updater.exe"
         !define VERSION "%(version_short)s"
         !define VERSION_LONG "%(version)s"
         !define VERSION_DASHES "%(version_dashes)s"
@@ -812,7 +807,7 @@ def package_finish(self):
         # note that the enclosing setup exe is signed later, after the makensis makes it.
         # Unlike the viewer binary, the VMP filenames are invariant with respect to version, os, etc.
         for exe in (
-            "SL_Launcher.exe",
+            "updater.exe",
             ):
             self.sign(exe)
             
@@ -880,394 +875,278 @@ def is_packaging_viewer(self):
         return True
 
     def construct(self):
-        # These are the names of the top-level application and the embedded
-        # applications for the VMP and for the actual viewer, respectively.
-        # These names, without the .app suffix, determine the flyover text for
-        # their corresponding Dock icons.
-        toplevel_app, toplevel_icon = "Second Life.app",          "secondlife.icns"
-        launcher_app, launcher_icon = "Second Life Launcher.app", "secondlife.icns"
-        viewer_app,   viewer_icon   = "Second Life Viewer.app",   "secondlife.icns"
-
         # copy over the build result (this is a no-op if run within the xcode script)
-        self.path(os.path.join(self.args['configuration'], toplevel_app), dst="")
+        self.path(os.path.join(self.args['configuration'], "Second Life.app"), dst="")
 
         pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
         relpkgdir = os.path.join(pkgdir, "lib", "release")
         debpkgdir = os.path.join(pkgdir, "lib", "debug")
 
-        # -------------------- top-level Second Life.app ---------------------
-        # top-level Second Life application is only a container
         with self.prefix(src="", dst="Contents"):  # everything goes in Contents
-            # top-level Info.plist is as generated by CMake
-            Info_plist = "Info.plist"
-            ## This self.path() call reports 0 files... skip?
-            self.path(Info_plist)
-            Info_plist = self.dst_path_of(Info_plist)
-
-            # the one file in top-level MacOS directory is the trampoline to
-            # our nested launcher_app
+            # CEF framework goes inside Contents/Frameworks.
+            # Remember where we parked this car.
+            with self.prefix(src="", dst="Frameworks"):
+                CEF_framework = "Chromium Embedded Framework.framework"
+                self.path2basename(relpkgdir, CEF_framework)
+                CEF_framework = self.dst_path_of(CEF_framework)
+
             with self.prefix(dst="MacOS"):
-                toplevel_MacOS = self.get_dst_prefix()
-                trampoline = self.put_in_file("""\
-#!/bin/bash
-open "%s" --args "$@"
-""" %
-                    # up one directory from MacOS to its sibling Resources directory
-                    os.path.join('$(dirname "$0")', os.pardir, 'Resources', launcher_app),
-                    "SL_Launcher",      # write this file
-                    "trampoline")       # flag to add to list of copied files
-                # Script must be executable
-                self.run_command(["chmod", "+x", trampoline])
-
-            # Make a symlink to a nested app Frameworks directory that doesn't
-            # yet exist. We shouldn't need this; the only things that need
-            # Frameworks are nested apps under viewer_app, and they should
-            # simply find its Contents/Frameworks by relative pathnames. But
-            # empirically, we do: if we omit this symlink, CEF doesn't work --
-            # the login splash screen doesn't even display. SIIIIGH.
-            # We're passing a path that's already relative, hence symlinkf()
-            # rather than relsymlinkf().
-            self.symlinkf(os.path.join("Resources", viewer_app, "Contents", "Frameworks"))
-
-            with self.prefix(src="", dst="Resources"):
-                # top-level Resources directory should be pretty sparse
-                # need .icns file referenced by top-level Info.plist
+                # NOTE: the -S argument to strip causes it to keep
+                # enough info for annotated backtraces (i.e. function
+                # names in the crash log). 'strip' with no arguments
+                # yields a slightly smaller binary but makes crash
+                # logs mostly useless. This may be desirable for the
+                # final release. Or not.
+                if ("package" in self.args['actions'] or 
+                    "unpacked" in self.args['actions']):
+                    self.run_command(
+                        ['strip', '-S', self.dst_path_of('Second Life')])
+
+            with self.prefix(dst="Resources"):
+                # defer cross-platform file copies until we're in the
+                # nested Resources directory
+                super(DarwinManifest, self).construct()
+
+                # need .icns file referenced by Info.plist
                 with self.prefix(src=self.icon_path(), dst="") :
-                    self.path(toplevel_icon)
-
-                # ------------------- nested launcher_app --------------------
-                with self.prefix(dst=os.path.join(launcher_app, "Contents")):
-                    # Info.plist is just like top-level one...
-                    Info = plistlib.readPlist(Info_plist)
-                    # except for these replacements:
-                    Info["CFBundleExecutable"] = "SL_Launcher"
-                    Info["CFBundleIconFile"] = launcher_icon
-                    self.put_in_file(
-                        plistlib.writePlistToString(Info),
-                        os.path.basename(Info_plist),
-                        "Info.plist")
-
-                    # copy VMP libs to MacOS
-                    with self.prefix(dst="MacOS"):              
-                        #this copies over the python wrapper script,
-                        #associated utilities and required libraries, see
-                        #SL-321, SL-322, SL-323
-                        with self.prefix(src=os.path.join(pkgdir, "VMP"), dst=""):
-                            self.path("SL_Launcher")
-                            self.path("*.py")
-                            # certifi will be imported by requests; this is
-                            # our custom version to get our ca-bundle.crt
-                            self.path("certifi")
-                        with self.prefix(src=os.path.join(pkgdir, "lib", "python"), dst=""):
-                            # llbase provides our llrest service layer and llsd decoding
-                            with self.prefix("llbase"):
-                                # (Why is llbase treated specially here? What
-                                # DON'T we want to copy out of lib/python/llbase?)
-                                self.path("*.py")
-                                self.path("_cllsd.so")
-                            #requests module needed by llbase/llrest.py
-                            #this is only needed on POSIX, because in Windows
-                            #we compile it into the EXE
-                            for pypkg in "chardet", "idna", "requests", "urllib3":
-                                self.path(pypkg)
-
-                    # launcher_app/Contents/Resources
-                    with self.prefix(dst="Resources"):
-                        with self.prefix(src=self.icon_path(), dst="") :
-                            self.path(launcher_icon)
-                            with self.prefix(dst="vmp_icons"):
-                                self.path("secondlife.ico")
-                        #VMP Tkinter icons
-                        with self.prefix("vmp_icons"):
-                            self.path("*.png")
-                            self.path("*.gif")
-
-                # -------------------- nested viewer_app ---------------------
-                with self.prefix(dst=os.path.join(viewer_app, "Contents")):
-                    # Info.plist is just like top-level one...
-                    Info = plistlib.readPlist(Info_plist)
-                    # except for these replacements:
-                    # (CFBundleExecutable may be moot: SL_Launcher directly
-                    # runs the executable, instead of launching the app)
-                    Info["CFBundleExecutable"] = "Second Life"
-                    Info["CFBundleIconFile"] = viewer_icon
-                    self.put_in_file(
-                        plistlib.writePlistToString(Info),
-                        os.path.basename(Info_plist),
-                        "Info.plist")
-
-                    # CEF framework goes inside viewer_app/Contents/Frameworks.
-                    # Remember where we parked this car.
-                    with self.prefix(src="", dst="Frameworks"):
-                        CEF_framework = "Chromium Embedded Framework.framework"
-                        self.path2basename(relpkgdir, CEF_framework)
-                        CEF_framework = self.dst_path_of(CEF_framework)
-
-                    with self.prefix(dst="MacOS"):
-                        # CMake constructs the Second Life executable in the
-                        # MacOS directory belonging to the top-level Second
-                        # Life.app. Move it here.
-                        here = self.get_dst_prefix()
-                        relbase = os.path.realpath(os.path.dirname(Info_plist))
-                        self.cmakedirs(here)
-                        for f in os.listdir(toplevel_MacOS):
-                            if f == os.path.basename(trampoline):
-                                # don't move the trampoline script we just made!
-                                continue
-                            fromwhere = os.path.join(toplevel_MacOS, f)
-                            towhere   = os.path.join(here, f)
-                            print "Moving %s => %s" % \
-                                  (self.relpath(fromwhere, relbase),
-                                   self.relpath(towhere, relbase))
-                            # now do it, only without relativizing paths
-                            os.rename(fromwhere, towhere)
-
-                        # NOTE: the -S argument to strip causes it to keep
-                        # enough info for annotated backtraces (i.e. function
-                        # names in the crash log). 'strip' with no arguments
-                        # yields a slightly smaller binary but makes crash
-                        # logs mostly useless. This may be desirable for the
-                        # final release. Or not.
-                        if ("package" in self.args['actions'] or 
-                            "unpacked" in self.args['actions']):
-                            self.run_command(
-                                ['strip', '-S', self.dst_path_of('Second Life')])
-
-                    with self.prefix(dst="Resources"):
-                        # defer cross-platform file copies until we're in the right
-                        # nested Resources directory
-                        super(DarwinManifest, self).construct()
-
-                        with self.prefix(src=self.icon_path(), dst="") :
-                            self.path(viewer_icon)
-
-                        with self.prefix(src=relpkgdir, dst=""):
-                            self.path("libndofdev.dylib")
-                            self.path("libhunspell-1.3.0.dylib")   
-
-                        with self.prefix("cursors_mac"):
-                            self.path("*.tif")
-
-                        self.path("licenses-mac.txt", dst="licenses.txt")
-                        self.path("featuretable_mac.txt")
-                        self.path("SecondLife.nib")
-
-                        with self.prefix(src=pkgdir,dst=""):
-                            self.path("ca-bundle.crt")
-
-                        self.path("SecondLife.nib")
-
-                        # Translations
-                        self.path("English.lproj/language.txt")
-                        self.replace_in(src="English.lproj/InfoPlist.strings",
-                                        dst="English.lproj/InfoPlist.strings",
-                                        searchdict={'%%VERSION%%':'.'.join(self.args['version'])}
-                                        )
-                        self.path("German.lproj")
-                        self.path("Japanese.lproj")
-                        self.path("Korean.lproj")
-                        self.path("da.lproj")
-                        self.path("es.lproj")
-                        self.path("fr.lproj")
-                        self.path("hu.lproj")
-                        self.path("it.lproj")
-                        self.path("nl.lproj")
-                        self.path("pl.lproj")
-                        self.path("pt.lproj")
-                        self.path("ru.lproj")
-                        self.path("tr.lproj")
-                        self.path("uk.lproj")
-                        self.path("zh-Hans.lproj")
-
-                        def path_optional(src, dst):
-                            """
-                            For a number of our self.path() calls, not only do we want
-                            to deal with the absence of src, we also want to remember
-                            which were present. Return either an empty list (absent)
-                            or a list containing dst (present). Concatenate these
-                            return values to get a list of all libs that are present.
-                            """
-                            # This was simple before we started needing to pass
-                            # wildcards. Fortunately, self.path() ends up appending a
-                            # (source, dest) pair to self.file_list for every expanded
-                            # file processed. Remember its size before the call.
-                            oldlen = len(self.file_list)
-                            self.path(src, dst)
-                            # The dest appended to self.file_list has been prepended
-                            # with self.get_dst_prefix(). Strip it off again.
-                            added = [os.path.relpath(d, self.get_dst_prefix())
-                                     for s, d in self.file_list[oldlen:]]
-                            if not added:
-                                print "Skipping %s" % dst
-                            return added
-
-                        # dylibs is a list of all the .dylib files we expect to need
-                        # in our bundled sub-apps. For each of these we'll create a
-                        # symlink from sub-app/Contents/Resources to the real .dylib.
-                        # Need to get the llcommon dll from any of the build directories as well.
-                        libfile_parent = self.get_dst_prefix()
-                        libfile = "libllcommon.dylib"
-                        dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir,
-                                                                       "llcommon",
-                                                                       self.args['configuration'],
-                                                                       libfile),
-                                                                       os.path.join(relpkgdir, libfile)),
-                                               dst=libfile)
-
-                        for libfile in (
-                                        "libapr-1.0.dylib",
-                                        "libaprutil-1.0.dylib",
-                                        "libcollada14dom.dylib",
-                                        "libexpat.1.dylib",
-                                        "libexception_handler.dylib",
-                                        "libGLOD.dylib",
-                                        # libnghttp2.dylib is a symlink to
-                                        # libnghttp2.major.dylib, which is a symlink to
-                                        # libnghttp2.version.dylib. Get all of them.
-                                        "libnghttp2.*dylib",
-                                        ):
-                            dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
-
-                        # SLVoice and vivox lols, no symlinks needed
-                        for libfile in (
-                                        'libortp.dylib',
-                                        'libsndfile.dylib',
-                                        'libvivoxoal.dylib',
-                                        'libvivoxsdk.dylib',
-                                        'libvivoxplatform.dylib',
-                                        'SLVoice',
-                                        ):
-                            self.path2basename(relpkgdir, libfile)
-
-                        # dylibs that vary based on configuration
-                        if self.args['configuration'].lower() == 'debug':
-                            for libfile in (
-                                        "libfmodexL.dylib",
-                                        ):
-                                dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
-                        else:
-                            for libfile in (
-                                        "libfmodex.dylib",
-                                        ):
-                                dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
-
-                        # our apps
-                        executable_path = {}
-                        for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
-                                                 # plugin launcher
-                                                 (os.path.join("llplugin", "slplugin"), "SLPlugin.app"),
-                                                 ):
-                            self.path2basename(os.path.join(os.pardir,
-                                                            app_bld_dir, self.args['configuration']),
-                                               app)
-                            executable_path[app] = \
-                                self.dst_path_of(os.path.join(app, "Contents", "MacOS"))
-
-                            # our apps dependencies on shared libs
-                            # for each app, for each dylib we collected in dylibs,
-                            # create a symlink to the real copy of the dylib.
-                            with self.prefix(dst=os.path.join(app, "Contents", "Resources")):
-                                for libfile in dylibs:
-                                    self.relsymlinkf(os.path.join(libfile_parent, libfile))
-
-                        # Dullahan helper apps go inside SLPlugin.app
-                        with self.prefix(dst=os.path.join(
-                            "SLPlugin.app", "Contents", "Frameworks")):
-
-                            frameworkname = 'Chromium Embedded Framework'
-
-                            # This code constructs a relative symlink from the
-                            # target framework folder back to the real CEF framework.
-                            # It needs to be relative so that the symlink still works when
-                            # (as is normal) the user moves the app bundle out of the DMG
-                            # and into the /Applications folder. Note we pass catch=False,
-                            # letting the uncaught exception terminate the process, since
-                            # without this symlink, Second Life web media can't possibly work.
-
-                            # It might seem simpler just to symlink Frameworks back to
-                            # the parent of Chromimum Embedded Framework.framework. But
-                            # that would create a symlink cycle, which breaks our
-                            # packaging step. So make a symlink from Chromium Embedded
-                            # Framework.framework to the directory of the same name, which
-                            # is NOT an ancestor of the symlink.
-
-                            # from SLPlugin.app/Contents/Frameworks/Chromium Embedded
-                            # Framework.framework back to
-                            # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework
-                            SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False)
-
-                            # copy DullahanHelper.app
-                            self.path2basename(relpkgdir, 'DullahanHelper.app')
-
-                            # and fix that up with a Frameworks/CEF symlink too
-                            with self.prefix(dst=os.path.join(
-                                'DullahanHelper.app', 'Contents', 'Frameworks')):
-                                # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded
-                                # Framework.framework back to
-                                # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework
-                                # Since SLPlugin_framework is itself a
-                                # symlink, don't let relsymlinkf() resolve --
-                                # explicitly call relpath(symlink=True) and
-                                # create that symlink here.
-                                DullahanHelper_framework = \
-                                    self.symlinkf(self.relpath(SLPlugin_framework, symlink=True),
-                                                  catch=False)
-
-                            # change_command includes install_name_tool, the
-                            # -change subcommand and the old framework rpath
-                            # stamped into the executable. To use it with
-                            # run_command(), we must still append the new
-                            # framework path and the pathname of the
-                            # executable to change.
-                            change_command = [
-                                'install_name_tool', '-change',
-                                '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework']
-
-                            with self.prefix(dst=os.path.join(
-                                'DullahanHelper.app', 'Contents', 'MacOS')):
-                                # Now self.get_dst_prefix() is, at runtime,
-                                # @executable_path. Locate the helper app
-                                # framework (which is a symlink) from here.
-                                newpath = os.path.join(
-                                    '@executable_path',
-                                    self.relpath(DullahanHelper_framework, symlink=True),
-                                    frameworkname)
-                                # and restamp the DullahanHelper executable
-                                self.run_command(
-                                    change_command +
-                                    [newpath, self.dst_path_of('DullahanHelper')])
-
-                        # SLPlugin plugins
-                        with self.prefix(dst="llplugin"):
-                            dylibexecutable = 'media_plugin_cef.dylib'
-                            self.path2basename("../media_plugins/cef/" + self.args['configuration'],
-                                               dylibexecutable)
-
-                            # Do this install_name_tool *after* media plugin is copied over.
-                            # Locate the framework lib executable -- relative to
-                            # SLPlugin.app/Contents/MacOS, which will be our
-                            # @executable_path at runtime!
-                            newpath = os.path.join(
-                                '@executable_path',
-                                self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"],
-                                             symlink=True),
-                                frameworkname)
-                            # restamp media_plugin_cef.dylib
-                            self.run_command(
-                                change_command +
-                                [newpath, self.dst_path_of(dylibexecutable)])
+                    self.path("secondlife.icns")
+
+                # Copy in the updater script and helper modules
+                self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater")
 
-                            # copy LibVLC plugin itself
-                            self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
-                                               "media_plugin_libvlc.dylib")
+                with self.prefix(src="", dst=os.path.join("updater", "icons")):
+                    self.path2basename(self.icon_path(), "secondlife.ico")
+                    with self.prefix(src="vmp_icons", dst=""):
+                        self.path("*.png")
+                        self.path("*.gif")
 
-                            # copy LibVLC dynamic libraries
-                            with self.prefix(src=relpkgdir, dst="lib"):
-                                self.path( "libvlc*.dylib*" )
-                                # copy LibVLC plugins folder
-                                with self.prefix(src='plugins', dst=""):
-                                    self.path( "*.dylib" )
-                                    self.path( "plugins.dat" )
+                with self.prefix(src=relpkgdir, dst=""):
+                    self.path("libndofdev.dylib")
+                    self.path("libhunspell-1.3.0.dylib")   
+
+                with self.prefix("cursors_mac"):
+                    self.path("*.tif")
+
+                self.path("licenses-mac.txt", dst="licenses.txt")
+                self.path("featuretable_mac.txt")
+                self.path("SecondLife.nib")
+
+                with self.prefix(src=pkgdir,dst=""):
+                    self.path("ca-bundle.crt")
+
+                self.path("SecondLife.nib")
+
+                # Translations
+                self.path("English.lproj/language.txt")
+                self.replace_in(src="English.lproj/InfoPlist.strings",
+                                dst="English.lproj/InfoPlist.strings",
+                                searchdict={'%%VERSION%%':'.'.join(self.args['version'])}
+                                )
+                self.path("German.lproj")
+                self.path("Japanese.lproj")
+                self.path("Korean.lproj")
+                self.path("da.lproj")
+                self.path("es.lproj")
+                self.path("fr.lproj")
+                self.path("hu.lproj")
+                self.path("it.lproj")
+                self.path("nl.lproj")
+                self.path("pl.lproj")
+                self.path("pt.lproj")
+                self.path("ru.lproj")
+                self.path("tr.lproj")
+                self.path("uk.lproj")
+                self.path("zh-Hans.lproj")
+
+                def path_optional(src, dst):
+                    """
+                    For a number of our self.path() calls, not only do we want
+                    to deal with the absence of src, we also want to remember
+                    which were present. Return either an empty list (absent)
+                    or a list containing dst (present). Concatenate these
+                    return values to get a list of all libs that are present.
+                    """
+                    # This was simple before we started needing to pass
+                    # wildcards. Fortunately, self.path() ends up appending a
+                    # (source, dest) pair to self.file_list for every expanded
+                    # file processed. Remember its size before the call.
+                    oldlen = len(self.file_list)
+                    self.path(src, dst)
+                    # The dest appended to self.file_list has been prepended
+                    # with self.get_dst_prefix(). Strip it off again.
+                    added = [os.path.relpath(d, self.get_dst_prefix())
+                             for s, d in self.file_list[oldlen:]]
+                    if not added:
+                        print "Skipping %s" % dst
+                    return added
+
+                # dylibs is a list of all the .dylib files we expect to need
+                # in our bundled sub-apps. For each of these we'll create a
+                # symlink from sub-app/Contents/Resources to the real .dylib.
+                # Need to get the llcommon dll from any of the build directories as well.
+                libfile_parent = self.get_dst_prefix()
+                libfile = "libllcommon.dylib"
+                dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir,
+                                                               "llcommon",
+                                                               self.args['configuration'],
+                                                               libfile),
+                                                               os.path.join(relpkgdir, libfile)),
+                                       dst=libfile)
+
+                for libfile in (
+                                "libapr-1.0.dylib",
+                                "libaprutil-1.0.dylib",
+                                "libcollada14dom.dylib",
+                                "libexpat.1.dylib",
+                                "libexception_handler.dylib",
+                                "libGLOD.dylib",
+                                # libnghttp2.dylib is a symlink to
+                                # libnghttp2.major.dylib, which is a symlink to
+                                # libnghttp2.version.dylib. Get all of them.
+                                "libnghttp2.*dylib",
+                                ):
+                    dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
+
+                # SLVoice and vivox lols, no symlinks needed
+                for libfile in (
+                                'libortp.dylib',
+                                'libsndfile.dylib',
+                                'libvivoxoal.dylib',
+                                'libvivoxsdk.dylib',
+                                'libvivoxplatform.dylib',
+                                'SLVoice',
+                                ):
+                    self.path2basename(relpkgdir, libfile)
+
+                # dylibs that vary based on configuration
+                if self.args['configuration'].lower() == 'debug':
+                    for libfile in (
+                                "libfmodexL.dylib",
+                                ):
+                        dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
+                else:
+                    for libfile in (
+                                "libfmodex.dylib",
+                                ):
+                        dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
+
+                # our apps
+                executable_path = {}
+                for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
+                                         # plugin launcher
+                                         (os.path.join("llplugin", "slplugin"), "SLPlugin.app"),
+                                         ):
+                    self.path2basename(os.path.join(os.pardir,
+                                                    app_bld_dir, self.args['configuration']),
+                                       app)
+                    executable_path[app] = \
+                        self.dst_path_of(os.path.join(app, "Contents", "MacOS"))
+
+                    # our apps dependencies on shared libs
+                    # for each app, for each dylib we collected in dylibs,
+                    # create a symlink to the real copy of the dylib.
+                    with self.prefix(dst=os.path.join(app, "Contents", "Resources")):
+                        for libfile in dylibs:
+                            self.relsymlinkf(os.path.join(libfile_parent, libfile))
+
+                # Dullahan helper apps go inside SLPlugin.app
+                with self.prefix(dst=os.path.join(
+                    "SLPlugin.app", "Contents", "Frameworks")):
+
+                    frameworkname = 'Chromium Embedded Framework'
+
+                    # This code constructs a relative symlink from the
+                    # target framework folder back to the real CEF framework.
+                    # It needs to be relative so that the symlink still works when
+                    # (as is normal) the user moves the app bundle out of the DMG
+                    # and into the /Applications folder. Note we pass catch=False,
+                    # letting the uncaught exception terminate the process, since
+                    # without this symlink, Second Life web media can't possibly work.
+
+                    # It might seem simpler just to symlink Frameworks back to
+                    # the parent of Chromimum Embedded Framework.framework. But
+                    # that would create a symlink cycle, which breaks our
+                    # packaging step. So make a symlink from Chromium Embedded
+                    # Framework.framework to the directory of the same name, which
+                    # is NOT an ancestor of the symlink.
+
+                    # from SLPlugin.app/Contents/Frameworks/Chromium Embedded
+                    # Framework.framework back to
+                    # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework
+                    SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False)
+
+                    # copy DullahanHelper.app
+                    self.path2basename(relpkgdir, 'DullahanHelper.app')
+
+                    # and fix that up with a Frameworks/CEF symlink too
+                    with self.prefix(dst=os.path.join(
+                        'DullahanHelper.app', 'Contents', 'Frameworks')):
+                        # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded
+                        # Framework.framework back to
+                        # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework
+                        # Since SLPlugin_framework is itself a
+                        # symlink, don't let relsymlinkf() resolve --
+                        # explicitly call relpath(symlink=True) and
+                        # create that symlink here.
+                        DullahanHelper_framework = \
+                            self.symlinkf(self.relpath(SLPlugin_framework, symlink=True),
+                                          catch=False)
+
+                    # change_command includes install_name_tool, the
+                    # -change subcommand and the old framework rpath
+                    # stamped into the executable. To use it with
+                    # run_command(), we must still append the new
+                    # framework path and the pathname of the
+                    # executable to change.
+                    change_command = [
+                        'install_name_tool', '-change',
+                        '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework']
+
+                    with self.prefix(dst=os.path.join(
+                        'DullahanHelper.app', 'Contents', 'MacOS')):
+                        # Now self.get_dst_prefix() is, at runtime,
+                        # @executable_path. Locate the helper app
+                        # framework (which is a symlink) from here.
+                        newpath = os.path.join(
+                            '@executable_path',
+                            self.relpath(DullahanHelper_framework, symlink=True),
+                            frameworkname)
+                        # and restamp the DullahanHelper executable
+                        self.run_command(
+                            change_command +
+                            [newpath, self.dst_path_of('DullahanHelper')])
+
+                # SLPlugin plugins
+                with self.prefix(dst="llplugin"):
+                    dylibexecutable = 'media_plugin_cef.dylib'
+                    self.path2basename("../media_plugins/cef/" + self.args['configuration'],
+                                       dylibexecutable)
+
+                    # Do this install_name_tool *after* media plugin is copied over.
+                    # Locate the framework lib executable -- relative to
+                    # SLPlugin.app/Contents/MacOS, which will be our
+                    # @executable_path at runtime!
+                    newpath = os.path.join(
+                        '@executable_path',
+                        self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"],
+                                     symlink=True),
+                        frameworkname)
+                    # restamp media_plugin_cef.dylib
+                    self.run_command(
+                        change_command +
+                        [newpath, self.dst_path_of(dylibexecutable)])
+
+                    # copy LibVLC plugin itself
+                    self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
+                                       "media_plugin_libvlc.dylib")
+
+                    # copy LibVLC dynamic libraries
+                    with self.prefix(src=relpkgdir, dst="lib"):
+                        self.path( "libvlc*.dylib*" )
+                        # copy LibVLC plugins folder
+                        with self.prefix(src='plugins', dst=""):
+                            self.path( "*.dylib" )
+                            self.path( "plugins.dat" )
 
     def package_finish(self):
         global CHANNEL_VENDOR_BASE
@@ -1416,10 +1295,35 @@ def package_finish(self):
                             else:
                                 print >> sys.stderr, "Maximum codesign attempts exceeded; giving up"
                                 raise
-                    self.run_command(['spctl', '-a', '-texec', '-vv', app_in_dmg])
-
-            imagename="SecondLife_" + '_'.join(self.args['version'])
-
+                    print 72*'='
+                    import stat
+                    print app_in_dmg
+                    # Second Life.app
+                    for sub0 in os.listdir(app_in_dmg):
+                        print '--{}'.format(sub0)
+                        path0 = os.path.join(app_in_dmg, sub0)
+                        if os.path.isfile(path0):
+                            # shouldn't be any file here
+                            with open(path0) as inf:
+                                for line in inf:
+                                    print '  {}'.format(line.rstrip())
+                        elif os.path.isdir(path0):
+                            # Contents
+                            for sub1 in os.listdir(path0):
+                                print '----{}'.format(sub1)
+                                path1 = os.path.join(path0, sub1)
+                                if os.path.isfile(path1):
+                                    # Info.plist, PkgInfo
+                                    with open(path1) as inf:
+                                        for line in inf:
+                                            print '    {}'.format(line.rstrip())
+                                elif os.path.isdir(path1):
+                                    # Frameworks, MacOS, Resources
+                                    for sub2 in os.listdir(path1):
+                                        path2 = os.path.join(path1, sub2)
+                                        print '    {:04o} {}'.format(stat.S_IMODE(os.stat(path2).st_mode), sub2)
+                    print 72*'='
+                    self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg])
 
         finally:
             # Unmount the image even if exceptions from any of the above 
@@ -1476,11 +1380,7 @@ def construct(self):
             self.path2basename("../llplugin/slplugin", "SLPlugin") 
             #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323
             with self.prefix(src="../viewer_components/manager", dst=""):
-                self.path("SL_Launcher")
-                self.path("*.py")
-            with self.prefix(src=os.path.join("lib", "python", "llbase"), dst="llbase"):
                 self.path("*.py")
-                self.path("_cllsd.so")         
 
         # recurses, packaged again
         self.path("res-sdl")
@@ -1555,7 +1455,7 @@ def strip_binaries(self):
             self.run_command(
                 ["find"] +
                 [os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] +
-                ['-type', 'f', '!', '-name', '*.py', '!', '-name', 'SL_Launcher',
+                ['-type', 'f', '!', '-name', '*.py',
                  '!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';'])
 
 class Linux_i686_Manifest(LinuxManifest):