diff --git a/indra/cmake/BuildPackagesInfo.cmake b/indra/cmake/BuildPackagesInfo.cmake
index c67d4ea2f848f83ce83edad78abaee77745c61d1..8b3fc9576d843d8e74e4af76b49c54451dd24385 100644
--- a/indra/cmake/BuildPackagesInfo.cmake
+++ b/indra/cmake/BuildPackagesInfo.cmake
@@ -15,5 +15,5 @@ add_custom_command(OUTPUT packages-info.txt
   COMMAND ${Python3_EXECUTABLE}
           ${CMAKE_SOURCE_DIR}/cmake/run_build_test.py -DAUTOBUILD_ADDRSIZE=${ADDRESS_SIZE} -DAUTOBUILD=${AUTOBUILD_EXECUTABLE}
           ${Python3_EXECUTABLE}
-          ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py "${VIEWER_CHANNEL}" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}" > packages-info.txt
+          ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py "${VIEWER_CHANNEL}" "${VIEWER_SHORT_VERSION}" > packages-info.txt
   )
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index 51e050d3d3376f237112a0655b6e4e262e8eab5b..cc4b3bbc56df7a8a46e9440d56ef71e0f296768a 100644
--- a/indra/cmake/BuildVersion.cmake
+++ b/indra/cmake/BuildVersion.cmake
@@ -43,26 +43,29 @@ if(NOT DEFINED VIEWER_CHANNEL)
     endif()
 endif()
 
+if(DEFINED VIEWER_CHANNEL)
+    string(REPLACE " " "" VIEWER_CHANNEL_ONEWORD ${VIEWER_CHANNEL})
+endif()
+
 # Construct the viewer version number based on the indra/VIEWER_VERSION file
 if(NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/newview/
     set(VIEWER_VERSION_BASE_FILE "${CMAKE_SOURCE_DIR}/newview/VIEWER_VERSION.txt")
 
     if(EXISTS ${VIEWER_VERSION_BASE_FILE})
-        file(STRINGS ${VIEWER_VERSION_BASE_FILE} VIEWER_SHORT_VERSION REGEX "^[0-9]+\\.[0-9]+\\.[0-9]+")
-        string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" VIEWER_VERSION_MAJOR ${VIEWER_SHORT_VERSION})
-        string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" VIEWER_VERSION_MINOR ${VIEWER_SHORT_VERSION})
-        string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" VIEWER_VERSION_PATCH ${VIEWER_SHORT_VERSION})
+        file(STRINGS ${VIEWER_VERSION_BASE_FILE} VIEWER_FILE_VERSION REGEX "^[0-9]+\\.[0-9]+")
+        string(REGEX REPLACE "^([0-9]+)\\.[0-9]+" "\\1" VIEWER_VERSION_MAJOR ${VIEWER_FILE_VERSION})
+        string(REGEX REPLACE "^[0-9]+\\.([0-9]+)" "\\1" VIEWER_VERSION_MINOR ${VIEWER_FILE_VERSION})
 
         if(REVISION_FROM_VCS)
             find_package(Git)
         endif()
 
         if((NOT REVISION_FROM_VCS) AND DEFINED ENV{CI_PIPELINE_ID})
-            set(VIEWER_VERSION_REVISION $ENV{CI_PIPELINE_ID})
-            message(STATUS "Revision (from environment): ${VIEWER_VERSION_REVISION}")
+            set(VIEWER_VERSION_PATCH $ENV{CI_PIPELINE_ID})
+            message(STATUS "Revision (from environment): ${VIEWER_VERSION_PATCH}")
         elseif((NOT REVISION_FROM_VCS) AND DEFINED ENV{AUTOBUILD_BUILD_ID})
-            set(VIEWER_VERSION_REVISION $ENV{AUTOBUILD_BUILD_ID})
-            message(STATUS "Revision (from autobuild environment): ${VIEWER_VERSION_REVISION}")
+            set(VIEWER_VERSION_PATCH $ENV{AUTOBUILD_BUILD_ID})
+            message(STATUS "Revision (from autobuild environment): ${VIEWER_VERSION_PATCH}")
         elseif(Git_FOUND)
             execute_process(
                 COMMAND ${GIT_EXECUTABLE} rev-list HEAD --count
@@ -71,24 +74,26 @@ if(NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/ne
                 OUTPUT_STRIP_TRAILING_WHITESPACE)
 
             if(GIT_REV_LIST_COUNT)
-                set(VIEWER_VERSION_REVISION ${GIT_REV_LIST_COUNT})
+                set(VIEWER_VERSION_PATCH ${GIT_REV_LIST_COUNT})
             else(GIT_REV_LIST_COUNT)
-                set(VIEWER_VERSION_REVISION 0)
+                set(VIEWER_VERSION_PATCH 0)
             endif(GIT_REV_LIST_COUNT)
         else()
-            set(VIEWER_VERSION_REVISION 0)
+            set(VIEWER_VERSION_PATCH 0)
         endif()
-        message(STATUS "Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
+        message(STATUS "Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}")
+
+        if("${VIEWER_VERSION_PATCH}" STREQUAL "")
+            message(STATUS "Ultimate fallback, revision was blank or not set: will use 0")
+            set(VIEWER_VERSION_PATCH 0)
+        endif("${VIEWER_VERSION_PATCH}" STREQUAL "")
+
+        set(VIEWER_SHORT_VERSION "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}")
     else(EXISTS ${VIEWER_VERSION_BASE_FILE})
         message(SEND_ERROR "Cannot get viewer version from '${VIEWER_VERSION_BASE_FILE}'")
     endif(EXISTS ${VIEWER_VERSION_BASE_FILE})
 
-    if("${VIEWER_VERSION_REVISION}" STREQUAL "")
-        message(STATUS "Ultimate fallback, revision was blank or not set: will use 0")
-        set(VIEWER_VERSION_REVISION 0)
-    endif("${VIEWER_VERSION_REVISION}" STREQUAL "")
-
-    set(VIEWER_VERSION_AND_CHANNEL "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
+    set(VIEWER_VERSION_AND_CHANNEL "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}")
 endif(NOT DEFINED VIEWER_SHORT_VERSION)
 
 if (NOT DEFINED VIEWER_COMMIT_LONG_SHA)
diff --git a/indra/cmake/ViewerManager.cmake b/indra/cmake/ViewerManager.cmake
index 77cac3a187781c05f84af289e01474fbda71e30f..93cd6eb12558f721d658f7e0b88e0e781fa3ad44 100644
--- a/indra/cmake/ViewerManager.cmake
+++ b/indra/cmake/ViewerManager.cmake
@@ -1,4 +1,4 @@
 include (Prebuilt)
-if(NOT LINUX)
-    use_prebuilt_binary(viewer-manager)
-endif()
+# if(NOT LINUX)
+#     use_prebuilt_binary(viewer-manager)
+# endif()
diff --git a/indra/llfilesystem/lldir_win32.cpp b/indra/llfilesystem/lldir_win32.cpp
index afd95b1afa94da904d3cc0c4bdebe661688e461f..7fa594f9163174b15be5a2d482ff1734ba59d496 100644
--- a/indra/llfilesystem/lldir_win32.cpp
+++ b/indra/llfilesystem/lldir_win32.cpp
@@ -381,7 +381,7 @@ bool LLDir_Win32::fileExists(const std::string& filename) const
 
 /*virtual*/ std::string LLDir_Win32::getLLPluginLauncher()
 {
-	return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() +
+	return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() +
 		"SLPlugin.exe";
 }
 
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0a0c2aec81243e80fa1bc5cb6a11c5abd3b74010..5a0597a36c1c7086f73da5180bf6c57580c767fa 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1549,11 +1549,16 @@ source_group("CMake Rules" FILES ViewerInstall.cmake)
 #build_data.json creation moved to viewer_manifest.py MAINT-6413
 # the viewer_version.txt file created here is for passing to viewer_manifest and autobuild
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt"
-           "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n")
+           "${VIEWER_SHORT_VERSION}\n")
 
 configure_file(llviewerbuildconfig.h.in llviewerbuildconfig.h @ONLY)
 LIST(APPEND viewer_HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/llviewerbuildconfig.h)
 
+if (WINDOWS)
+  LIST(APPEND viewer_SOURCE_FILES alsquirrelupdater.cpp)
+  LIST(APPEND viewer_HEADER_FILES alsquirrelupdater.h)
+endif (WINDOWS)
+
 if (DARWIN)
   LIST(APPEND viewer_SOURCE_FILES llappviewermacosx.cpp)
   LIST(APPEND viewer_SOURCE_FILES llappviewermacosx-objc.mm)
@@ -1727,6 +1732,10 @@ if (WINDOWS)
                     ${CMAKE_CURRENT_BINARY_DIR}/viewerRes.rc
                     )
 
+    configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/installers/windows/viewer.nuspec
+                    ${CMAKE_CURRENT_BINARY_DIR}/viewer.nuspec
+                    )
+
     list(APPEND viewer_RESOURCE_FILES
     	windows.manifest
         ${CMAKE_CURRENT_BINARY_DIR}/viewerRes.rc
@@ -2206,7 +2215,7 @@ set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
     "Path to artwork files.")
 
 if (LINUX)
-  set(product Alchemy-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION})
+  set(product Alchemy-${ARCH}-${VIEWER_SHORT_VERSION})
 
   # These are the generated targets that are copied to package/
   set(COPY_INPUT_DEPENDENCIES
@@ -2287,10 +2296,10 @@ if (DARWIN)
   set(MACOSX_BUNDLE_INFO_STRING "${VIEWER_CHANNEL}")
   set(MACOSX_BUNDLE_ICON_FILE "alchemy.icns")
   set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.alchemyviewer.viewer")
-  set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
+  set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}")
   set(MACOSX_BUNDLE_BUNDLE_NAME "Alchemy")
-  set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
-  set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_VERSION_REVISION}")
+  set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}")
+  set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}")
   set(MACOSX_BUNDLE_COPYRIGHT "Copyright (C) 2013-2021 Alchemy Development Group")
   set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "Alchemy.nib")
   set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "LLApplication")
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index f5199477c52d78cde8dd8517794f43ad0e5abd47..12e41412939763fb74d07f838735c69ed5c3334f 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.6.9
+6.9
diff --git a/indra/newview/alsquirrelupdater.cpp b/indra/newview/alsquirrelupdater.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..73afe03fc746f78f17cd307c8a1ed8446443c6ad
--- /dev/null
+++ b/indra/newview/alsquirrelupdater.cpp
@@ -0,0 +1,558 @@
+/**
+* @file alsquirrelupdater.cpp
+* @brief Quick Settings popdown panel
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Alchemy Viewer Source Code
+* Copyright (C) 2013-2023, Alchemy Viewer Project.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "alsquirrelupdater.h"
+
+#include "llappviewer.h"
+#include "llnotificationsutil.h"
+#include "llversioninfo.h"
+#include "llviewercontrol.h"
+
+#include "llcallbacklist.h"
+#include "llprocess.h"
+#include "llsdjson.h"
+#include "llsdutil.h"
+#include "llwin32headerslean.h"
+#include "llstartup.h"
+
+static std::string win32_errorcode_to_string(LONG errorMessageID)
+{
+	if (errorMessageID == 0)
+		return std::string(); //No error message has been recorded
+
+	LPWSTR messageBuffer = nullptr;
+	size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+		NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), messageBuffer, 0, NULL);
+
+	std::wstring message(messageBuffer, size);
+
+	//Free the buffer.
+	LocalFree(messageBuffer);
+
+	return ll_convert_wide_to_string(message);
+}
+
+struct ALRegWriter
+{
+	static void setValueFailed(const LSTATUS& rc) { LL_WARNS() << "Failed to write reg value with error: " << win32_errorcode_to_string(rc) << LL_ENDL; }
+	static void checkSuccess(const LSTATUS& rc, std::function<void(const LSTATUS&)> on_failed = setValueFailed)
+	{
+		if (rc != ERROR_SUCCESS) on_failed(rc);
+	}
+
+	ALRegWriter(HKEY parent_key, const std::wstring& key_name) : mSuccess(true)
+	{
+		checkSuccess(RegCreateKeyEx(parent_key, key_name.c_str(), NULL, NULL, NULL, KEY_ALL_ACCESS, NULL, &mResultKey, NULL), [&](const LSTATUS& rc)
+		{
+			mSuccess = false;
+			LL_WARNS() << "Failed to open " << ll_convert_wide_to_string(key_name) << " with error: " << win32_errorcode_to_string(rc) << LL_ENDL;
+		});
+	}
+
+	void setValue(const std::wstring& value, DWORD dwType = REG_SZ, LPCTSTR value_name = NULL) const
+	{
+		checkSuccess(RegSetValueEx(mResultKey, value_name, NULL, dwType, (LPBYTE) value.c_str(), (value.size() + 1) * sizeof(wchar_t)));
+	}
+
+	void setValue(const std::string& value, DWORD dwType = REG_SZ, LPCTSTR value_name = NULL) const
+	{
+		setValue(ll_convert_string_to_wide(value), dwType, value_name);
+	}
+
+	std::string getStringValue(const std::wstring& subkey_name, const std::wstring& value_name)
+	{
+		const DWORD BUFFER_SIZE = 512;
+		WCHAR outstr[BUFFER_SIZE];
+		DWORD bufsize = BUFFER_SIZE;
+		checkSuccess(RegGetValue(mResultKey, subkey_name.c_str(), value_name.c_str(), RRF_RT_REG_SZ, nullptr, outstr, &bufsize), [&](const LSTATUS& rc)
+		{
+			LL_WARNS() << "Failed to read " << ll_convert_wide_to_string(value_name) << " from key " << ll_convert_wide_to_string(subkey_name)
+				<< " with error: " << win32_errorcode_to_string(rc) << LL_ENDL;
+			return std::string();
+		});
+		std::wstring widestr(outstr, bufsize);
+		return ll_convert_wide_to_string(widestr);
+	}
+
+	ALRegWriter createSubKey(const std::wstring& key_name) const
+	{
+		return ALRegWriter(mResultKey, key_name);
+	}
+
+	void deleteTree(const wchar_t* name) const { RegDeleteTree(mResultKey, name); }
+
+	~ALRegWriter()
+	{
+		RegFlushKey(mResultKey);
+		RegCloseKey(mResultKey);
+	}
+
+	operator bool() { return mSuccess; }
+
+	bool mSuccess;
+	HKEY mResultKey;
+};
+
+// static
+void ALUpdateUtils::updateSlurlRegistryKeys(const std::string& protocol, const std::string& name, const std::string& executable_path)
+{
+	// SecondLife slurls
+	std::wstring reg_path = ll_convert_string_to_wide(llformat("Software\\Classes\\%s", protocol.c_str()));
+	if (auto regpath = ALRegWriter(HKEY_CURRENT_USER, reg_path))
+	{
+		regpath.setValue(name);
+
+		ALRegWriter::checkSuccess(RegSetValueEx(regpath.mResultKey, TEXT("URL Protocol"), NULL, REG_SZ, NULL, 0));
+
+		if (auto defaulticon = regpath.createSubKey(TEXT("DefaultIcon")))
+		{
+			defaulticon.setValue(executable_path);
+		}
+
+		if (auto shell = regpath.createSubKey(TEXT("shell")))
+		{
+			shell.setValue(TEXT("open"));
+
+			if (auto open = shell.createSubKey(TEXT("open")))
+			{
+				open.setValue(LLVersionInfo::instance().getChannel(), REG_SZ, TEXT("FriendlyAppName"));
+
+				if (auto command = open.createSubKey(TEXT("command")))
+				{
+					std::string open_cmd_string = llformat("\"%s\" -url \"%s\"", executable_path.c_str(), "%1");
+					command.setValue(open_cmd_string, REG_EXPAND_SZ);
+				}
+			}
+		}
+	}
+}
+
+// static
+bool ALUpdateUtils::handleCommandLineParse(LLControlGroupCLP& clp)
+{
+	if(!ALUpdateHandler::isSupported()) return true;
+
+	bool is_install = clp.hasOption("squirrel-install");
+	bool is_update = clp.hasOption("squirrel-updated");
+	bool is_uninstall = clp.hasOption("squirrel-uninstall");
+	if (is_install || is_update || is_uninstall)
+	{
+		std::string install_dir = gDirUtilp->getExecutableDir();
+		size_t path_end = install_dir.find_last_of('\\');
+		if (path_end != std::string::npos)
+		{
+			install_dir = install_dir.substr(0, path_end);
+		}
+
+		if (is_install)
+		{
+			std::string executable_path(install_dir);
+			gDirUtilp->append(executable_path, gDirUtilp->getExecutableFilename());
+
+			updateSlurlRegistryKeys("secondlife", "URL:Second Life", executable_path);
+			updateSlurlRegistryKeys("x-grid-info", "URL:Hypergrid", executable_path);
+			updateSlurlRegistryKeys("x-grid-location-info", "URL:Hypergrid", executable_path);
+		}
+		else if (is_uninstall) // uninstall
+		{
+			// Delete SecondLife and Hypergrid slurls
+			if (auto classes = ALRegWriter(HKEY_CURRENT_USER, TEXT("Software\\Classes")))
+			{
+				auto appname = classes.getStringValue(TEXT("secondlife\\shell\\open"), TEXT("FriendlyAppName"));
+				if (appname.find(LLVersionInfo::instance().getChannel(), 0) != std::string::npos)
+				{
+					classes.deleteTree(TEXT("secondlife"));
+				}
+				appname = classes.getStringValue(TEXT("x-grid-info\\shell\\open"), TEXT("FriendlyAppName"));
+				if (appname.find(LLVersionInfo::instance().getChannel(), 0) != std::string::npos)
+				{
+					classes.deleteTree(TEXT("x-grid-info"));
+				}
+				appname = classes.getStringValue(TEXT("x-grid-location-info\\shell\\open"), TEXT("FriendlyAppName"));
+				if (appname.find(LLVersionInfo::instance().getChannel(), 0) != std::string::npos)
+				{
+					classes.deleteTree(TEXT("x-grid-location-info"));
+				}
+			}
+		}
+
+		std::string updater_path = install_dir;
+		gDirUtilp->append(updater_path, "Update.exe");
+		if (LLFile::isfile(updater_path))
+		{
+			LLProcess::Params process_params;
+			process_params.executable = updater_path;
+
+			if (is_install)
+			{
+				process_params.args.add("--createShortcut");
+			}
+			else if (is_uninstall)
+			{
+				process_params.args.add("--removeShortcut");
+			}
+			process_params.args.add(gDirUtilp->getExecutableFilename());
+			if (is_update)
+			{
+				process_params.args.add("--updateOnly");
+			}
+			process_params.args.add("--shortcut-locations");
+			process_params.args.add("Desktop,StartMenu");
+			process_params.attached = false;
+			process_params.autokill = false;
+			LLProcess::create(process_params);
+		}
+		else
+		{
+			LL_WARNS() << "Squirrel not found or viewer is not running in squirrel directory" << LL_ENDL;
+		}
+		LLAppViewer::instance()->removeDumpDir();
+		LLAppViewer::instance()->removeMarkerFiles();
+		return false;
+	}
+	return true;
+}
+
+ALUpdateHandler::ALUpdateHandler()
+	: mUpdaterDonePump("SquirrelUpdate", true)
+	, mUpdateAction(E_NO_ACTION)
+	, mUpdateCallback(nullptr)
+{
+	if (gSavedSettings.getControl("AlchemyUpdateServiceURL"))
+	{
+		mUpdateURL = gSavedSettings.getString("AlchemyUpdateServiceURL");
+	}
+	else
+	{
+		std::string channel = LLVersionInfo::instance().getChannel();
+		channel.erase(std::remove_if(channel.begin(), channel.end(), isspace), channel.end());
+
+		mUpdateURL = llformat("http://update.alchemyviewer.net/windows%s/channel/%s/", std::to_string(ADDRESS_SIZE).c_str(), channel.c_str());
+	}
+	LL_INFOS() << "Update service url: " << mUpdateURL << LL_ENDL;
+
+	doPeriodically(boost::bind(&ALUpdateHandler::periodicUpdateCheck, this), gSavedSettings.getF32("AlchemyUpdateCheckInterval"));
+}
+
+bool ALUpdateHandler::periodicUpdateCheck()
+{
+	check();
+	return LLApp::isExiting();
+}
+
+bool ALUpdateHandler::start(EUpdateAction update_action, update_callback_t callback)
+{
+	mUpdateAction = update_action;
+	mUpdateCallback = callback;
+
+	mUpdatePumpListenerName = LLEventPump::inventName("SquirrelEvent");
+	mUpdaterDonePump.listen(mUpdatePumpListenerName, boost::bind(&ALUpdateHandler::processDone, this, _1));
+
+	std::string updater_dir = gDirUtilp->getExecutableDir();
+	size_t path_end = updater_dir.find_last_of('\\');
+	if (path_end != std::string::npos)
+	{
+		updater_dir = updater_dir.substr(0, path_end);
+	}
+
+	std::string updater_path = updater_dir;
+	gDirUtilp->append(updater_path, "Update.exe");
+
+	if (LLFile::isfile(updater_path))
+	{
+		// Okay, launch child.
+		LLProcess::Params params;
+		params.executable = updater_path;
+		params.cwd = updater_dir;
+		if (mUpdateAction == E_CHECK)
+		{
+			params.args.add("--checkForUpdate");
+			params.args.add(mUpdateURL);
+		}
+		else if (mUpdateAction == E_DOWNLOAD)
+		{
+			params.args.add("--download");
+			params.args.add(mUpdateURL);
+		}
+		else if (mUpdateAction == E_INSTALL)
+		{
+			params.autokill = false;
+			params.attached = false;
+			params.args.add("--update");
+			params.args.add(mUpdateURL);
+		}
+		else if (mUpdateAction == E_QUIT_INSTALL)
+		{
+			params.autokill = false;
+			params.attached = false;
+			params.args.add("--processStartAndWait");
+			params.args.add(gDirUtilp->getExecutableFilename());
+		}
+		params.files.add(LLProcess::FileParam()); // stdin
+		params.files.add(LLProcess::FileParam("pipe")); // stdout
+		params.files.add(LLProcess::FileParam()); // stderr
+		params.postend = mUpdaterDonePump.getName();
+		mUpdater = LLProcess::create(params);
+	}
+
+	if (!mUpdater)
+	{
+		LL_WARNS() << "Failed to run updater at path '" << updater_path << "'" << LL_ENDL;
+		mUpdaterDonePump.stopListening(mUpdatePumpListenerName);
+		mUpdater = nullptr;
+		return false;
+	}
+	return true;
+}
+
+bool ALUpdateHandler::processDone(const LLSD& data)
+{
+	bool success = false;
+	if (data.has("data"))
+	{
+		S32 exit_code = data["data"].asInteger();
+		if (exit_code == 0)
+		{
+			success = true;
+		}
+	}
+	if (success)
+	{
+		LLSD update_data = LLSD::emptyMap();
+		if (mUpdateAction != E_INSTALL || mUpdateAction != E_QUIT_INSTALL)
+		{
+			LLProcess::ReadPipe& childout(mUpdater->getReadPipe(LLProcess::STDOUT));
+			if (childout.size())
+			{
+				std::string output = childout.read(childout.size());
+				size_t found = output.find_first_of('{', 0);
+				if (found != std::string::npos)
+				{
+					output = output.substr(found, std::string::npos);
+
+					nlohmann::json update_info;
+					try
+					{
+						update_info = nlohmann::json::parse(output);
+					}
+					catch (nlohmann::json::exception &e)
+					{
+						LL_WARNS() << "Exception during json processing: " << e.what() << LL_ENDL;
+						if (mUpdateCallback != nullptr)
+						{
+							mUpdateCallback(update_data);
+						}
+						mUpdaterDonePump.stopListening(mUpdatePumpListenerName);
+						mUpdater = nullptr;
+						mUpdateAction = E_NO_ACTION;
+						return false;
+					}
+
+					if (update_info.is_object())
+					{
+						update_data = LlsdFromJson(update_info);
+						LL_INFOS() << "Outdata from updater test: " << ll_pretty_print_sd(update_data) << LL_ENDL;
+					}
+				}
+			}
+		}
+
+		mUpdaterDonePump.stopListening(mUpdatePumpListenerName);
+		mUpdater = nullptr;
+		if (mUpdateCallback != nullptr)
+		{
+			mUpdateCallback(update_data);
+		}
+	}
+	else
+	{
+		LL_WARNS() << "Process error for listener " << mUpdatePumpListenerName << " with data " << ll_pretty_print_sd(data) << LL_ENDL;
+		mUpdaterDonePump.stopListening(mUpdatePumpListenerName);
+		mUpdateAction = E_NO_ACTION;
+		mUpdater = nullptr;
+	}
+
+	mUpdateAction = E_NO_ACTION;
+	return true;
+}
+
+bool ALUpdateHandler::check()
+{
+	if (!mUpdater && mUpdateAction == E_NO_ACTION)
+	{
+		LL_INFOS() << "Discovering viewer update..." << LL_ENDL;
+		return start(ALUpdateHandler::E_CHECK,
+			std::bind(&ALUpdateHandler::updateCheckFinished, this, std::placeholders::_1));
+	}
+	else
+	{
+		LL_INFOS() << "Not checking update because mUpdater=" << mUpdater << " and mUpdateAction=" << mUpdateAction << LL_ENDL;
+	}
+	return false;
+}
+
+bool ALUpdateHandler::download()
+{
+	if (!mUpdater)
+	{
+		LL_INFOS() << "Downloading a new update!" << LL_ENDL;
+		return start(ALUpdateHandler::E_DOWNLOAD,
+			std::bind(&ALUpdateHandler::updateDownloadFinished, this, std::placeholders::_1));
+	}
+	return false;
+}
+
+bool ALUpdateHandler::install()
+{
+	if (!mUpdater)
+	{
+		return start(ALUpdateHandler::E_INSTALL,
+			std::bind(&ALUpdateHandler::updateInstallFinished, this, std::placeholders::_1));
+	}
+	return false;
+}
+
+void ALUpdateHandler::restartToNewVersion()
+{
+	if (!mUpdater)
+	{
+		start(ALUpdateHandler::E_QUIT_INSTALL, update_callback_t());
+		LLAppViewer::instance()->requestQuit();
+	}
+}
+
+void ALUpdateHandler::updateCheckFinished(const LLSD& data)
+{
+	if (data.emptyMap()) return;
+	ALVersionInfo cur_ver(LLVersionInfo::instance().getMajor(), LLVersionInfo::instance().getMinor(), LLVersionInfo::instance().getPatch());
+	ALVersionInfo new_ver;
+	if (data.has("futureVersion")) new_ver.parse(data["futureVersion"].asString());
+
+	if (new_ver > cur_ver)
+	{
+		mSavedUpdateInfo = data;
+		LL_WARNS() << "New ver found: " << new_ver.version() << LL_ENDL;
+		static LLCachedControl<S32> update_preference(gSavedSettings, "AlchemyUpdatePreference", 0);
+		if (update_preference == 0)
+		{
+			install();
+		}
+		else if (update_preference == 1)
+		{
+			download();
+		}
+		else if (update_preference == 2)
+		{
+			LLSD args;
+			args["VIEWER_VER"] = llformat("%s %s", LLVersionInfo::instance().getChannel().c_str(), LLVersionInfo::instance().getShortVersion().c_str());
+			args["VIEWER_UPDATES"] = llformat("%s", new_ver.version().c_str());
+			LLSD payload;
+			payload["user_update_action"] = LLSD(E_DOWNLOAD_INSTALL);
+			LLNotificationsUtil::add("UpdateDownloadRequest", args, payload, boost::bind(&ALUpdateHandler::onUpdateNotification, this, _1, _2));
+		}
+	}
+	else
+	{
+		LL_INFOS() << "No new update was found." << LL_ENDL;
+		mUpdateAction = E_NO_ACTION;
+	}
+}
+
+void ALUpdateHandler::updateDownloadFinished(const LLSD& data)
+{
+	static LLCachedControl<S32> update_preference(gSavedSettings, "AlchemyUpdatePreference", 0);
+	if (update_preference == 1)
+	{
+		ALVersionInfo new_ver;
+		if (mSavedUpdateInfo.has("futureVersion")) new_ver.parse(mSavedUpdateInfo["futureVersion"].asString());
+
+		std::string releases;
+		if (mSavedUpdateInfo.has("releasesToApply"))
+		{
+			LLSD release_array = mSavedUpdateInfo["releasesToApply"];
+			if (release_array.size() > 0)
+			{
+				for (LLSD::array_const_iterator it = release_array.beginArray(), end_it = release_array.endArray(); it != end_it; ++it)
+				{
+					auto release_entry = *it;
+					if (release_entry.isMap())
+					{
+						releases += release_entry["version"].asString();
+					}
+				}
+			}
+		}
+		LLSD args;
+		args["VIEWER_VER"] = llformat("%s %s", LLVersionInfo::instance().getChannel().c_str(), new_ver.version().c_str());
+		args["VIEWER_UPDATES"] = releases;
+		LLSD payload;
+		payload["user_update_action"] = LLSD(E_DOWNLOADED);
+		LLNotificationsUtil::add("UpdateDownloaded", args, payload, boost::bind(&ALUpdateHandler::onUpdateNotification, this, _1, _2));
+	}
+}
+
+void ALUpdateHandler::updateInstallFinished(const LLSD& data)
+{
+	static LLCachedControl<S32> update_preference(gSavedSettings, "AlchemyUpdatePreference", 0);
+	// Autodownload and install
+	if (update_preference == 0)
+	{
+		ALVersionInfo new_ver;
+		if (mSavedUpdateInfo.has("futureVersion")) new_ver.parse(mSavedUpdateInfo["futureVersion"].asString());
+		LLSD args;
+		args["VIEWER_VER"] = llformat("%s %s", LLVersionInfo::instance().getChannel().c_str(), LLVersionInfo::instance().getShortVersion().c_str());
+		args["VIEWER_UPDATES"] = llformat("%s", new_ver.version().c_str());
+		LLSD payload;
+		payload["user_update_action"] = LLSD(E_INSTALLED_RESTART);
+		LLNotificationsUtil::add((LLStartUp::getStartupState() < STATE_STARTED ? "UpdateInstalledRestart" : "UpdateInstalledRestartToast"), args, payload, boost::bind(&ALUpdateHandler::onUpdateNotification, this, _1, _2));
+	}
+	// Autodownload and request install or Request download and request install
+	else if (update_preference == 1 || update_preference == 2)
+	{
+		restartToNewVersion();
+	}
+}
+
+void ALUpdateHandler::onUpdateNotification(const LLSD& notification, const LLSD& response)
+{
+	const S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	if (option == 0)
+	{
+		S32 update_action = notification["payload"]["user_update_action"].asInteger();
+		if (update_action == E_INSTALLED_RESTART)
+		{
+			restartToNewVersion();
+		}
+		else if (update_action == E_DOWNLOAD || update_action == E_DOWNLOAD_INSTALL)
+		{
+			install();
+		}
+		return;
+	}
+	mUpdateAction = E_NO_ACTION;
+	mSavedUpdateInfo = LLSD::emptyMap();
+}
diff --git a/indra/newview/alsquirrelupdater.h b/indra/newview/alsquirrelupdater.h
new file mode 100644
index 0000000000000000000000000000000000000000..1166333cdab3e4e64386a50ea26f29db1b7980dc
--- /dev/null
+++ b/indra/newview/alsquirrelupdater.h
@@ -0,0 +1,174 @@
+/**
+* @file alsquirrelupdater.h
+* @brief Quick Settings popdown panel
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Alchemy Viewer Source Code
+* Copyright (C) 2018, Alchemy Viewer Project.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* $/LicenseInfo$
+*/
+
+
+#include "llcommandlineparser.h"
+
+#include "llevents.h"
+#include "lleventtimer.h"
+#include "llprocess.h"
+#include "llsingleton.h"
+
+class ALUpdateUtils
+{
+public:
+	// static functions
+	static void updateSlurlRegistryKeys(const std::string& protocol, const std::string& name, const std::string& executable_path);
+	static bool handleCommandLineParse(LLControlGroupCLP& clp);
+};
+
+class ALUpdateHandler : public LLSingleton<ALUpdateHandler>
+{
+	LLSINGLETON(ALUpdateHandler);
+public:
+	typedef enum EUpdateAction {
+		E_NO_ACTION = 0,
+		E_CHECK,
+		E_DOWNLOAD,
+		E_INSTALL,
+		E_QUIT_INSTALL
+	} e_update_action;
+
+	typedef std::function<void(const LLSD& data)> update_callback_t;
+
+	bool periodicUpdateCheck();
+
+	bool check();
+	bool download();
+	bool install();
+
+	void restartToNewVersion();
+
+	struct ALVersionInfo
+	{
+		ALVersionInfo()
+			: mMajor(0), mMinor(0), mPatch(0)
+		{}
+		ALVersionInfo(S32 major, S32 minor, S32 patch)
+			: mMajor(major), mMinor(minor), mPatch(patch)
+		{}
+
+		bool parse(const std::string& instr)
+		{
+			std::istringstream inver(instr);
+			S32 ver_part;
+			try
+			{
+				inver >> ver_part;
+				mMajor = ver_part;
+				char c = inver.get(); // skip the period
+				if (c != '.') { return false; }
+				inver >> ver_part;
+				mMinor = ver_part;
+				c = inver.get(); // skip the hypen
+				if (c != '.') { return false; }
+				inver >> ver_part;
+				mPatch = ver_part;
+			}
+			catch (...)
+			{
+				return false;
+			}
+			return true;
+		}
+
+		std::string version()
+		{
+			return llformat("%i.%i.%i", mMajor, mMinor, mPatch);
+		}
+
+		bool operator == (const ALVersionInfo& rhs) const
+		{
+			return (mMajor == rhs.mMajor && mMinor == rhs.mMinor && mPatch == rhs.mPatch);
+		}
+		bool operator != (const ALVersionInfo& rhs) const
+		{
+			return (mMajor != rhs.mMajor || (mMinor != rhs.mMinor || mPatch != rhs.mPatch));
+		}
+		bool operator < (const ALVersionInfo& rhs) const
+		{
+			return ((mMajor < rhs.mMajor)
+				|| ((mMajor <= rhs.mMajor && mMinor < rhs.mMinor)
+					|| (mMajor <= rhs.mMajor && mMinor <= rhs.mMinor && mPatch < rhs.mPatch)));
+		}
+		bool operator <= (const ALVersionInfo& rhs) const
+		{
+			return (*this < rhs) || (*this == rhs);
+		}
+		bool operator > (const ALVersionInfo& rhs) const
+		{
+			return ((mMajor > rhs.mMajor)
+				|| ((mMajor >= rhs.mMajor && mMinor > rhs.mMinor)
+					|| (mMajor >= rhs.mMajor && mMinor >= rhs.mMinor && mPatch > rhs.mPatch)));
+		}
+		bool operator >= (const ALVersionInfo& rhs) const
+		{
+			return (*this > rhs) || (*this == rhs);
+		}
+
+	private:
+		S32 mMajor, mMinor, mPatch;
+	};
+
+	static bool isSupported()
+	{
+		std::string updater_path = gDirUtilp->getExecutableDir();
+		size_t path_end = updater_path.find_last_of('\\');
+		if (path_end != std::string::npos)
+		{
+			updater_path = updater_path.substr(0, path_end);
+		}
+
+		gDirUtilp->append(updater_path, "Update.exe");
+		return LLFile::isfile(updater_path);
+	}
+
+private:
+	bool start(EUpdateAction update_action, update_callback_t callback);
+	bool processDone(const LLSD& data);
+
+	typedef enum EUserUpdateAction {
+		E_INSTALLED_RESTART = 0,
+		E_DOWNLOADED,
+		E_DOWNLOAD_INSTALL
+	} e_user_update_action;
+
+	void updateCheckFinished(const LLSD& data);
+	void updateDownloadFinished(const LLSD& data);
+	void updateInstallFinished(const LLSD& data);
+
+	void onUpdateNotification(const LLSD& notification, const LLSD& response);
+
+	LLProcessPtr mUpdater;
+
+	std::string mUpdatePumpListenerName;
+	LLEventStream mUpdaterDonePump;
+
+	EUpdateAction mUpdateAction;
+	update_callback_t mUpdateCallback;
+
+	LLSD mSavedUpdateInfo;
+	std::string mUpdateURL;
+};
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index e16a5c7e76014ece4bdc11a137a51c10aa9803e8..09698f60f072761a32800c749a92bfbfb1c18a8b 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -415,6 +415,40 @@
       <key>map-to</key>
       <string>CmdLineSkipUpdater</string>
     </map>
-
+    <key>squirrel-install</key>
+    <map>
+      <key>count</key>
+      <integer>1</integer>
+      <key>map-to</key>
+      <string>CmdLineSquirrelInstall</string>
+    </map>
+    <key>squirrel-firstrun</key>
+    <map>
+      <key>count</key>
+      <integer>0</integer>
+      <key>map-to</key>
+      <string>CmdLineSquirrelFirstRun</string>
+    </map>
+    <key>squirrel-updated</key>
+    <map>
+      <key>count</key>
+      <integer>1</integer>
+      <key>map-to</key>
+      <string>CmdLineSquirrelUpdated</string>
+    </map>
+    <key>squirrel-obsolete</key>
+    <map>
+      <key>count</key>
+      <integer>1</integer>
+      <key>map-to</key>
+      <string>CmdLineSquirrelObsolete</string>
+    </map>
+    <key>squirrel-uninstall</key>
+    <map>
+      <key>count</key>
+      <integer>1</integer>
+      <key>map-to</key>
+      <string>CmdLineSquirrelUninstall</string>
+    </map>
   </map>
 </llsd>
diff --git a/indra/newview/app_settings/settings_alchemy.xml b/indra/newview/app_settings/settings_alchemy.xml
index a68ff67be6aa929047f442d06a0dae7785500d57..734dbc79d03c5612b5a14b3e5800af50001bf18c 100644
--- a/indra/newview/app_settings/settings_alchemy.xml
+++ b/indra/newview/app_settings/settings_alchemy.xml
@@ -805,6 +805,28 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>AlchemyUpdatePreference</key>
+    <map>
+      <key>Comment</key>
+      <string>Default behavior of updater 0(Download and install), 1(download and prompt for install), 2(Prompt for download and install)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>AlchemyUpdateCheckInterval</key>
+    <map>
+      <key>Comment</key>
+      <string>How frequently to check for updates in seconds.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>14400.0</real>
+    </map>
     <key>ChatAlerts</key>
     <map>
       <key>Comment</key>
@@ -816,6 +838,61 @@
       <key>Value</key>
       <boolean>0</boolean>
     </map>
+    <key>CmdLineSquirrelInstall</key>
+    <map>
+      <key>Comment</key>
+      <string>Command line flag for initial install from squirrel with version as arguement</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string />
+    </map>
+    <key>CmdLineSquirrelFirstRun</key>
+    <map>
+      <key>Comment</key>
+      <string>Command line flag for initial application run from squirrel</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>CmdLineSquirrelUpdated</key>
+    <map>
+      <key>Comment</key>
+      <string>Command line flag for update from squirrel with version as arguement</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string />
+    </map>
+    <key>CmdLineSquirrelObsolete</key>
+    <map>
+      <key>Comment</key>
+      <string>Command line flag for obsolete version from squirrel with version as arguement</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string />
+    </map>
+    <key>CmdLineSquirrelUninstall</key>
+    <map>
+      <key>Comment</key>
+      <string>Command line flag for uninstall from squirrel with version as arguement</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string />
+    </map>
     <key>GroupSnoozeTime</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/installers/windows/viewer.nuspec b/indra/newview/installers/windows/viewer.nuspec
new file mode 100644
index 0000000000000000000000000000000000000000..af8fb411ab8028f558f3da4cd2e3a23192ff099d
--- /dev/null
+++ b/indra/newview/installers/windows/viewer.nuspec
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<package >
+  <metadata>
+    <id>${VIEWER_CHANNEL_ONEWORD}</id>
+    <version>${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}</version>
+    <authors>Alchemy Development Group</authors>
+    <owners>Alchemy Development Group</owners>
+	<title>${VIEWER_CHANNEL}</title>
+    <description>${VIEWER_CHANNEL}</description>
+    <copyright>Copyright (C) 2013-2023 Alchemy Development Group</copyright>
+	<projectUrl>https://www.alchemyviewer.org</projectUrl>
+  </metadata>
+  <files>
+    <file src="Release\**\*.*" target="lib\net45\" exclude="Release\**\*.pdb;Release\**\*.vshost.*;Release\**\*.nsi;Release\**\*.bat;Release\**\*_Setup.exe;Release\**\*-bin.exe"/>
+  </files>
+</package>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cf1c97707b79be759e6af71f5ee2dca8526a83d6..6f5fe3352cea4d73d7d9f9435e486a435890d9e5 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -31,6 +31,9 @@
 #include "llappviewer.h"
 
 // Viewer includes
+#if LL_WINDOWS
+#include "alsquirrelupdater.h"
+#endif
 #include "llregex.h"
 #include "llversioninfo.h"
 #include "llfeaturemanager.h"
@@ -1138,73 +1141,23 @@ bool LLAppViewer::init()
 
 	gGLActive = FALSE;
 
-#if LL_RELEASE_FOR_DOWNLOAD && !defined(LL_LINUX)
+#if LL_RELEASE_FOR_DOWNLOAD
     // Skip updater if this is a non-interactive instance
     if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive)
     {
-        LLProcess::Params updater;
-        updater.desc = "updater process";
-        // Because it's the updater, it MUST persist beyond the lifespan of the
-        // viewer itself.
-        updater.autokill = false;
-        std::string updater_file;
 #if LL_WINDOWS
-        updater_file = "SLVersionChecker.exe";
-        updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file);
-#elif LL_DARWIN
-        updater_file = "SLVersionChecker";
-        updater.executable = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", updater_file);
-#else
-        updater_file = "SLVersionChecker";
-        updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file);
+		// Init updater here
+		if (ALUpdateHandler::isSupported())
+		{
+			ALUpdateHandler::getInstance()->check();
+		}
 #endif
-        // add LEAP mode command-line argument to whichever of these we selected
-        updater.args.add("leap");
-        // UpdaterServiceSettings
-        if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
-        {
-            // Befor first login, treat this as 'manual' updates,
-            // updater won't install anything, but required updates
-            updater.args.add("0");
-        }
-        else
-        {
-            updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting")));
-        }
-        // channel
-        updater.args.add(LLVersionInfo::instance().getChannel());
-        // testok
-        updater.args.add(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest")));
-        // ForceAddressSize
-        updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize")));
-
-        try
-        {
-            // Run the updater. An exception from launching the updater should bother us.
-            LLLeap::create(updater, true);
-            mUpdaterNotFound = false;
-        }
-        catch (...)
-        {
-            LLUIString details = LLNotifications::instance().getGlobalString("LLLeapUpdaterFailure");
-            details.setArg("[UPDATER_APP]", updater_file);
-            OSMessageBox(
-                details.getString(),
-                LLStringUtil::null,
-                OSMB_OK);
-            mUpdaterNotFound = true;
-        }
     }
     else
     {
         LL_WARNS("InitInfo") << "Skipping updater check." << LL_ENDL;
     }
 
-    if (mUpdaterNotFound)
-    {
-        LL_WARNS("InitInfo") << "Failed to launch updater. Skipping Leap commands." << LL_ENDL;
-    }
-    else
     {
         // 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.
@@ -1230,13 +1183,6 @@ bool LLAppViewer::init()
             LLLeap::create("", leap.asString(), false); // exception=false
         }
     }
-
-    if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
-    {
-        LL_WARNS("InitInfo") << "QAModeEventHostPort DEPRECATED: "
-                             << "lleventhost no longer supported as a dynamic library"
-                             << LL_ENDL;
-    }
 #endif //LL_RELEASE_FOR_DOWNLOAD
 
 	LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match;
@@ -2613,6 +2559,12 @@ bool LLAppViewer::initConfiguration()
 		return false;
 	}
 
+#if LL_WINDOWS
+	if (ALUpdateHandler::isSupported() && !ALUpdateUtils::handleCommandLineParse(clp))
+	{
+		return false;
+	}
+#endif
 	// - selectively apply settings
 
 	// If the user has specified a alternate settings file name.
@@ -3201,7 +3153,7 @@ LLSD LLAppViewer::getViewerInfo() const
 	// LLFloaterAbout.
 	LLSD info;
 	auto& versionInfo(LLVersionInfo::instance());
-	info["VIEWER_VERSION"] = LLSDArray(versionInfo.getMajor())(versionInfo.getMinor())(versionInfo.getPatch())(versionInfo.getBuild());
+	info["VIEWER_VERSION"] = LLSDArray(versionInfo.getMajor())(versionInfo.getMinor())(versionInfo.getPatch());
 	info["VIEWER_VERSION_STR"] = versionInfo.getVersion();
 	info["CHANNEL"] = versionInfo.getChannel();
     info["ADDRESS_SIZE"] = ADDRESS_SIZE;
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 91fb124d2c201c81554c4e8b7b8cbd1e76c664b7..f536c9f98d87884a22c2f338727e560d7e1317be 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -761,7 +761,7 @@ void LLAppViewerWin32::initCrashReporting(bool reportFreeze)
 	sentry_options_set_dsn(options, SENTRY_DSN);
 	sentry_options_set_release(options, LL_VIEWER_CHANNEL_AND_VERSION);
 
-	std::string crashpad_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "crashpad_handler.exe");
+	std::string crashpad_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "sentry", "crashpad_handler.exe");
 	sentry_options_set_handler_pathw(options, ll_convert_string_to_wide(crashpad_path).c_str());
 
 	std::string database_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "sentry");
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index 35a9f07f37c6eaf91d2d8721a6853ce0ddce7378..c91b63e2358a2bc21034a012270c3e766ee887e0 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -36,8 +36,7 @@
 #if ! defined(LL_VIEWER_CHANNEL)       \
  || ! defined(LL_VIEWER_VERSION_MAJOR) \
  || ! defined(LL_VIEWER_VERSION_MINOR) \
- || ! defined(LL_VIEWER_VERSION_PATCH) \
- || ! defined(LL_VIEWER_VERSION_BUILD)
+ || ! defined(LL_VIEWER_VERSION_PATCH)
  #error "Channel or Version information is undefined"
 #endif
 
@@ -95,7 +94,7 @@ S32 LLVersionInfo::getPatch()
 
 S32 LLVersionInfo::getBuild()
 {
-	return LL_VIEWER_VERSION_BUILD;
+	return 0;
 }
 
 const std::string& LLVersionInfo::getVersion()
@@ -113,7 +112,7 @@ const std::string& LLVersionInfo::getChannelAndVersion()
 	if (mVersionChannel.empty())
 	{
 		// cache the version string
-		mVersionChannel = getChannel() + " " + getVersion();
+		mVersionChannel = getChannel() + " " + getShortVersion();
 	}
 
 	return mVersionChannel;
diff --git a/indra/newview/llviewerbuildconfig.h.in b/indra/newview/llviewerbuildconfig.h.in
index 141304158fe23f5c6bb231df499b1261bfcd2f8d..a408ccd56a508c8f3dcb7e3f4602a521caeeaefe 100644
--- a/indra/newview/llviewerbuildconfig.h.in
+++ b/indra/newview/llviewerbuildconfig.h.in
@@ -41,7 +41,6 @@
 #define LL_VIEWER_VERSION_MAJOR @VIEWER_VERSION_MAJOR@
 #define LL_VIEWER_VERSION_MINOR @VIEWER_VERSION_MINOR@
 #define LL_VIEWER_VERSION_PATCH @VIEWER_VERSION_PATCH@
-#define LL_VIEWER_VERSION_BUILD @VIEWER_VERSION_REVISION@
 
 // Sentry
 #define SENTRY_DSN "@SENTRY_DSN@"
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 6f65655ab5385928493cebcd818b719508f16bda..7feea83287c9906715d49b0e45e64477d4c149a7 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -956,7 +956,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
 #if LL_WINDOWS
         // On windows use exe (not work or RO) directory
         std::string exe_path = gDirUtilp->getExecutableDir();
-        gDirUtilp->append(exe_path, "SLVoice.exe");
+        gDirUtilp->append(exe_path, "voice", "SLVoice.exe");
 #elif LL_DARWIN
         // On MAC use resource directory
         std::string exe_path = gDirUtilp->getAppRODataDir();
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index c377639579df3d5e39189f201b9d4ccffef0d971..8f0f6190f1308b0f7155dd280012a3e0e78add44 100755
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -136,8 +136,8 @@ TOOLNO                  CURSOR                  "llno.cur"
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION ${VIEWER_VERSION_MAJOR},${VIEWER_VERSION_MINOR},${VIEWER_VERSION_PATCH},${VIEWER_VERSION_REVISION}
- PRODUCTVERSION ${VIEWER_VERSION_MAJOR},${VIEWER_VERSION_MINOR},${VIEWER_VERSION_PATCH},${VIEWER_VERSION_REVISION}
+ FILEVERSION ${VIEWER_VERSION_MAJOR},${VIEWER_VERSION_MINOR},${VIEWER_VERSION_PATCH},0
+ PRODUCTVERSION ${VIEWER_VERSION_MAJOR},${VIEWER_VERSION_MINOR},${VIEWER_VERSION_PATCH},0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -154,12 +154,13 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Alchemy Development Group"
             VALUE "FileDescription", "Alchemy"
-            VALUE "FileVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}"
+            VALUE "FileVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}"
             VALUE "InternalName", "Alchemy"
-            VALUE "LegalCopyright", "Copyright (C) 2013-2021 Alchemy Development Group"
+            VALUE "LegalCopyright", "Copyright (C) 2013-2023 Alchemy Development Group"
             VALUE "OriginalFilename", "Alchemy.exe"
             VALUE "ProductName", "Alchemy"
-            VALUE "ProductVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}"
+            VALUE "ProductVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}"
+            VALUE "SquirrelAwareVersion", "1"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 586807e2cf1b1ea05d527a1861ed199c1ed799c3..1b734eab47b09c63c94c5fde6b3a3f695ad4df0e 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -12730,4 +12730,63 @@ Would you like to reset the graphic preferences?
   notext="Leave as-is"
   canceltext="Never reset"/>
  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="UpdateDownloadRequest"
+   type="alertmodal">
+A new version has been detected.
+Would you like to download and install [VIEWER_VER] with following updates now?
+
+[VIEWER_UPDATES]
+    <tag>confirm</tag>
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Remind Me Later"
+     yestext="Ok"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="UpdateDownloaded"
+   type="alertmodal">
+[VIEWER_VER] has been downloaded.
+Would you like to install [VIEWER_VER] for following updates now?
+
+[VIEWER_UPDATES]
+    <tag>confirm</tag>
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Remind Me Later"
+     yestext="Ok"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="UpdateInstalledRestart"
+   type="alertmodal">
+Your viewer has been updated to the following version:
+[VIEWER_VER] => [VIEWER_UPDATES] 
+
+Would you like to restart now?
+    <tag>confirm</tag>
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Remind Me Later"
+     yestext="Ok"/>
+  </notification>
+  <notification
+   icon="notify.tga"
+   name="UpdateInstalledRestartToast"
+   type="notify">
+Your viewer has been updated to the following version:
+[VIEWER_VER] => [VIEWER_UPDATES] 
+
+Would you like to restart now?
+    <tag>confirm</tag>
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Remind Me Later"
+     yestext="Ok"/>
+  </notification>
 </notifications>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 15b69af4e6e97e2baf3138a24973acd122ec8564..b3f8bf6b70395d2310eb00936d0f518b6928e88a 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -35,7 +35,7 @@
 
 	<!-- about dialog/support string-->
 	<string name="AboutHeader">
-[CHANNEL] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([ADDRESS_SIZE]bit)
+[CHANNEL] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2] ([ADDRESS_SIZE]bit)
 [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]]
 	</string>
 	<string name="AboutCompiler">Compiler Version: [COMPILER] [COMPILER_VERSION]</string>
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 89c69bf0ed48d1d653baab176b4aed23f59d3482..bc003fc1f821f3d727dc7f60a7f808af58557881 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -439,22 +439,11 @@ def construct(self):
             # Find alchemy-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
             self.path(src='%s/alchemy-bin.exe' % self.args['configuration'], dst=self.final_exe())
 
-            with self.prefix(src=os.path.join(pkgdir, "VMP")):
-                # include the compiled launcher scripts so that it gets included in the file_list
-                self.path('SLVersionChecker.exe')
-
-            with self.prefix(dst="vmp_icons"):
-                with self.prefix(src=self.icon_path()):
-                    self.path(src="alchemy.ico", dst="secondlife.ico")
-                #VMP  Tkinter icons
-                with self.prefix(src="vmp_icons"):
-                    self.path("*.png")
-                    self.path("*.gif")
-
         # Plugin host application
-        self.path2basename(os.path.join(os.pardir,
-                                        'llplugin', 'slplugin', self.args['configuration']),
-                           "slplugin.exe")
+        with self.prefix(dst="llplugin"):
+            self.path2basename(os.path.join(os.pardir,
+                                            'llplugin', 'slplugin', self.args['configuration']),
+                                            "slplugin.exe")
         
         # Get shared libs from the shared libs staging directory
         with self.prefix(src=os.path.join(self.args['build'], os.pardir,
@@ -482,34 +471,23 @@ def construct(self):
                 else:
                     self.path(src="kdu.dll", dst="kdu.dll")
 					
-            # These need to be installed as a SxS assembly, currently a 'private' assembly.
-            # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
-            self.path("concrt140.dll")
-            self.path("msvcp140.dll")
-            self.path("msvcp140_1.dll")
-            self.path("msvcp140_2.dll")
-            self.path("msvcp140_atomic_wait.dll")
-            self.path("msvcp140_codecvt_ids.dll")
-            self.path("vccorlib140.dll")
-            self.path("vcruntime140.dll")
-            self.path("vcruntime140_1.dll")
-
             # SLVoice executable
-            with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
-                self.path("SLVoice.exe")
+            with self.prefix(dst="voice"):
+                with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
+                    self.path("SLVoice.exe")
 
-            # Vivox libraries
-            if (self.address_size == 64):
-                self.path("vivoxsdk_x64.dll")
-                self.path("ortp_x64.dll")
-            else:
-                self.path("vivoxsdk.dll")
-                self.path("ortp.dll")
+                # Vivox libraries
+                if (self.address_size == 64):
+                    self.path("vivoxsdk_x64.dll")
+                    self.path("ortp_x64.dll")
+                else:
+                    self.path("vivoxsdk.dll")
+                    self.path("ortp.dll")
 
             # Sentry
             if self.args['sentry'] == 'ON' or self.args['sentry'] == 'TRUE':
                 self.path("sentry.dll")
-                with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
+                with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="sentry"):
                     self.path("crashpad_handler.exe")
 
             if self.args['discord'] == 'ON' or self.args['discord'] == 'TRUE':
@@ -626,139 +604,27 @@ def construct(self):
         if not self.is_packaging_viewer():
             self.package_file = "copied_deps"    
 
-    def nsi_file_commands(self, install=True):
-        def wpath(path):
-            if path.endswith('/') or path.endswith(os.path.sep):
-                path = path[:-1]
-            path = path.replace('/', '\\')
-            return path
-
-        result = ""
-        dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
-        # sort deepest hierarchy first
-        dest_files.sort(key=lambda f: (f.count(os.path.sep), f), reverse=True)
-        out_path = None
-        for pkg_file in dest_files:
-            rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
-            installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
-            pkg_file = wpath(os.path.normpath(pkg_file))
-            if installed_dir != out_path:
-                if install:
-                    out_path = installed_dir
-                    result += 'SetOutPath ' + out_path + '\n'
-            if install:
-                result += 'File ' + pkg_file + '\n'
-            else:
-                result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
-
-        # at the end of a delete, just rmdir all the directories
-        if not install:
-            deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
-            # find all ancestors so that we don't skip any dirs that happened to have no non-dir children
-            deleted_dirs = []
-            for d in deleted_file_dirs:
-                deleted_dirs.extend(path_ancestors(d))
-            # sort deepest hierarchy first
-            deleted_dirs.sort(key=lambda f: (f.count(os.path.sep), f), reverse=True)
-            prev = None
-            for d in deleted_dirs:
-                if d != prev:   # skip duplicates
-                    result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
-                prev = d
-
-        return result
-
     def package_finish(self):
-        # a standard map of strings for replacing in the templates
-        substitution_strings = {
-            'version' : '.'.join(self.args['version']),
-            'version_short' : '.'.join(self.args['version'][:-1]),
-            'version_dashes' : '-'.join(self.args['version']),
-            'version_registry' : '%s(%s)' %
-            ('.'.join(self.args['version']), self.address_size),
-            'final_exe' : self.final_exe(),
-            'flags':'',
-            'app_name':self.app_name(),
-            'app_name_oneword':self.app_name_oneword()
-            }
+        nuget_exe = os.path.join(self.args['build'], os.pardir, 'packages', 'squirrel', 'nuget.exe')
+        self.run_command(
+            [nuget_exe,
+                'pack',
+                '-Properties', 'NoWarn=NU5128',
+                os.path.join(self.args['build'], 'viewer.nuspec')])
+
+        squirrel_exe = os.path.join(self.args['build'], os.pardir, 'packages', 'squirrel', 'Squirrel.exe')
+        self.run_command(
+            [squirrel_exe,
+                'releasify',
+                '--releaseDir', os.path.join(self.args['build'], 'Releases'),
+                '--framework', 'vcredist143-x64',
+                '--icon', os.path.join(self.args['source'], 'installers', 'windows', 'install_icon.ico'),
+                '--splashImage', os.path.join(self.args['source'], 'installers', 'windows', 'splash.gif'),
+                '--package', os.path.join(self.args['build'], '{}.{}.nupkg'.format(self.app_name_oneword(), '.'.join(self.args['version'])))])
 
         installer_file = self.installer_base_name() + '_Setup.exe'
-        substitution_strings['installer_file'] = installer_file
-        
-        version_vars = """
-        !define INSTEXE "SLVersionChecker.exe"
-        !define VERSION "%(version_short)s"
-        !define VERSION_LONG "%(version)s"
-        !define VERSION_DASHES "%(version_dashes)s"
-        !define VERSION_REGISTRY "%(version_registry)s"
-        !define VIEWER_EXE "%(final_exe)s"
-        """ % substitution_strings
-        
-        if self.channel_type() == 'release':
-            substitution_strings['caption'] = CHANNEL_VENDOR_BASE
-        else:
-            substitution_strings['caption'] = self.app_name() + ' ${VERSION}'
-
-        inst_vars_template = """
-            OutFile "%(installer_file)s"
-            !define INSTNAME   "%(app_name_oneword)s"
-            !define SHORTCUT   "%(app_name)s"
-            !define URLNAME   "secondlife"
-            Caption "%(caption)s"
-            """
-
-        if(self.address_size == 64):
-            engage_registry="SetRegView 64"
-            program_files="!define MULTIUSER_USE_PROGRAMFILES64"
-        else:
-            engage_registry="SetRegView 32"
-            program_files=""
-
-        tempfile = "alchemy_setup_tmp.nsi"
-        # the following replaces strings in the nsi template
-        # it also does python-style % substitution
-        self.replace_in("installers/windows/installer_template.nsi", tempfile, {
-                "%%VERSION%%":version_vars,
-                "%%SOURCE%%":self.get_src_prefix(),
-                "%%INST_VARS%%":inst_vars_template % substitution_strings,
-                "%%INSTALL_FILES%%":self.nsi_file_commands(True),
-                "%%PROGRAMFILES%%":program_files,
-                "%%ENGAGEREGISTRY%%":engage_registry,
-                "%%DELETE_FILES%%":self.nsi_file_commands(False)})
-
-        # If we're on a build machine, sign the code using our Authenticode certificate. JC
-        # 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 (
-            self.final_exe(),
-            "SLVersionChecker.exe",
-            "llplugin/dullahan_host.exe",
-            ):
-            self.sign(exe)
-            
-        # Check two paths, one for Program Files, and one for Program Files (x86).
-        # Yay 64bit windows.
-        for ProgramFiles in 'ProgramFiles', 'ProgramFiles(x86)':
-            NSIS_path = os.path.expandvars(r'${%s}\NSIS\makensis.exe' % ProgramFiles)
-            if os.path.exists(NSIS_path):
-                break
-        installer_created=False
-        nsis_attempts=3
-        nsis_retry_wait=15
-        for attempt in range(nsis_attempts):
-            try:
-                self.run_command([NSIS_path, '/V2', self.dst_path_of(tempfile)])
-            except ManifestError as err:
-                if attempt+1 < nsis_attempts:
-                    print("nsis failed, waiting %d seconds before retrying" % nsis_retry_wait, file=sys.stderr)
-                    time.sleep(nsis_retry_wait)
-                    nsis_retry_wait*=2
-            else:
-                # NSIS worked! Done!
-                break
-        else:
-            print("Maximum nsis attempts exceeded; giving up", file=sys.stderr)
-            raise
+
+        os.rename(os.path.join('Releases', self.app_name_oneword() + 'Setup.exe'), os.path.join('Release', installer_file))
 
         self.sign(installer_file)
         self.created_path(self.dst_path_of(installer_file))
@@ -863,15 +729,6 @@ def construct(self):
                 with self.prefix(src=self.icon_path(), dst="") :
                     self.path("alchemy.icns")
 
-                # Copy in the updater script and helper modules
-                self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater")
-
-                with self.prefix(src="", dst=os.path.join("updater", "icons")):
-                    self.path2basename(self.icon_path(), "alchemy.ico")
-                    with self.prefix(src="vmp_icons", dst=""):
-                        self.path("*.png")
-                        self.path("*.gif")
-
                 with self.prefix(src_dst="cursors_mac"):
                     self.path("*.tif")