diff --git a/doc/contributions.txt b/doc/contributions.txt
index c33562839103a525883f27a82f7d4fd7a2d79cf6..bebe715e87b258b308377d72ddd85084c92f718c 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -1188,6 +1188,7 @@ PanteraPolnocy
 	SL-18891
 	SL-18904
 	SL-18937
+	SL-19681
 Parvati Silverweb
 Patric Mills
 	VWR-2645
@@ -1413,6 +1414,7 @@ Sovereign Engineer
     SL-18525
     SL-18534
     SL-19690
+    SL-19336
 SpacedOut Frye
 	VWR-34
 	VWR-45
diff --git a/indra/deps/CMakeLists.txt b/indra/deps/CMakeLists.txt
index 1f361f7475fa24cc3fa9f2978a28932d38e412bc..59fc2851117e7208fb76522602d4eac9afbfe76a 100644
--- a/indra/deps/CMakeLists.txt
+++ b/indra/deps/CMakeLists.txt
@@ -37,7 +37,7 @@ FetchContent_Declare(
 FetchContent_Declare(
   fmt
   GIT_REPOSITORY https://github.com/fmtlib/fmt.git
-  GIT_TAG        9.1.0
+  GIT_TAG        10.0.0
   GIT_SHALLOW TRUE
   GIT_PROGRESS TRUE
   )
@@ -79,7 +79,7 @@ if(USE_NFD)
   FetchContent_Declare(
     nfd
     GIT_REPOSITORY https://github.com/btzy/nativefiledialog-extended.git
-    GIT_TAG        v1.0.3
+    GIT_TAG        v1.1.0
     )
 
   set(NFD_PORTAL ON)
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 76925160e06a4ad1b2f9e0909118b0e3dd78127f..f4ab12fe2304bddb3c3870e41741c51b59f790bf 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -1145,6 +1145,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
 	// get number of joint motions
 	//-------------------------------------------------------------------------
 	U32 num_motions = 0;
+    S32 rotation_dupplicates = 0;
+    S32 position_dupplicates = 0;
 	if (!dp.unpackU32(num_motions, "num_joints"))
 	{
 		LL_WARNS() << "can't read number of joints"
@@ -1376,6 +1378,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
 
 		std::sort(rCurve->mKeys.begin(), rCurve->mKeys.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
 
+        if (joint_motion->mRotationCurve.mNumKeys > joint_motion->mRotationCurve.mKeys.size())
+        {
+            rotation_dupplicates++;
+            LL_INFOS() << "Motion: " << asset_id << " had dupplicate rotation keys that were removed" << LL_ENDL;
+        }
+
 		//---------------------------------------------------------------------
 		// scan position curve header
 		//---------------------------------------------------------------------
@@ -1480,9 +1488,24 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
 
 		std::sort(pCurve->mKeys.begin(), pCurve->mKeys.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
 
+        if (joint_motion->mPositionCurve.mNumKeys > joint_motion->mPositionCurve.mKeys.size())
+        {
+            position_dupplicates++;
+        }
+
 		joint_motion->mUsage = joint_state->getUsage();
 	}
 
+    if (rotation_dupplicates > 0)
+    {
+        LL_INFOS() << "Motion: " << asset_id << " had " << rotation_dupplicates << " dupplicate rotation keys that were removed" << LL_ENDL;
+    }
+
+    if (position_dupplicates > 0)
+    {
+        LL_INFOS() << "Motion: " << asset_id << " had " << position_dupplicates << " dupplicate position keys that were removed" << LL_ENDL;
+    }
+
 	//-------------------------------------------------------------------------
 	// get number of constraints
 	//-------------------------------------------------------------------------
@@ -1762,10 +1785,13 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
 		JointMotion* joint_motionp = mJointMotionList->getJointMotion(i);
 		success &= dp.packString(joint_motionp->mJointName, "joint_name");
 		success &= dp.packS32(joint_motionp->mPriority, "joint_priority");
-		success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys");
+        success &= dp.packS32(joint_motionp->mRotationCurve.mKeys.size(), "num_rot_keys");
 
-		LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL;
-		for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys)
+        LL_DEBUGS("BVH") << "Joint " << i
+            << " name: " << joint_motionp->mJointName
+            << " Rotation keys: " << joint_motionp->mRotationCurve.mKeys.size()
+            << " Position keys: " << joint_motionp->mPositionCurve.mKeys.size() << LL_ENDL;
+        for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys)
 		{
 			RotationKey& rot_key = rot_pair.second;
 			U16 time_short = F32_to_U16(rot_key.mTime, 0.f, mJointMotionList->mDuration);
@@ -1785,7 +1811,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
 			LL_DEBUGS("BVH") << "  rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL;
 		}
 
-		success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys");
+		success &= dp.packS32(joint_motionp->mPositionCurve.mKeys.size(), "num_pos_keys");
 		for (PositionCurve::key_map_t::value_type& pos_pair : joint_motionp->mPositionCurve.mKeys)
 		{
 			PositionKey& pos_key = pos_pair.second;
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index c90d8f24c810b64561dde49c9b120eb76dcec679..c7e34b83f05e805c460d0d4c7f8aa8611729af88 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -42,7 +42,6 @@ set(llcommon_SOURCE_FILES
     lldependencies.cpp
     lldictionary.cpp
     llerror.cpp
-    llerrorthread.cpp
     llevent.cpp
     lleventapi.cpp
     lleventcoro.cpp
@@ -154,7 +153,6 @@ set(llcommon_HEADER_FILES
     llendianswizzle.h
     llerror.h
     llerrorcontrol.h
-    llerrorthread.h
     llevent.h
     lleventapi.h
     lleventcoro.h
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index dee10cadf9514999ba989a76452a6f3f6c3ca097..b4da4a437d685ef65eed4ecb8cbdf5a8a4d6d653 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -39,7 +39,6 @@
 #include "llcommon.h"
 #include "llapr.h"
 #include "llerrorcontrol.h"
-#include "llerrorthread.h"
 #include "llframetimer.h"
 #include "lllivefile.h"
 #include "llmemory.h"
@@ -100,12 +99,7 @@ LLAppErrorHandler LLApp::sErrorHandler = NULL;
 BOOL LLApp::sErrorThreadRunning = FALSE;
 
 
-LLApp::LLApp() : mThreadErrorp(NULL)
-{
-	commonCtor();
-}
-
-void LLApp::commonCtor()
+LLApp::LLApp()
 {
 	assert_main_thread();		// Make sure we record the main thread
 	on_main_thread();			// Make sure we record the main thread
@@ -133,12 +127,6 @@ void LLApp::commonCtor()
 	sApplication = this;
 }
 
-LLApp::LLApp(LLErrorThread *error_thread) :
-	mThreadErrorp(error_thread)
-{
-	commonCtor();
-}
-
 
 LLApp::~LLApp()
 {
@@ -148,13 +136,6 @@ LLApp::~LLApp()
 	mLiveFiles.clear();
 
 	setStopped();
-	// HACK: wait for the error thread to clean itself
-	ms_sleep(20);
-	if (mThreadErrorp)
-	{
-		delete mThreadErrorp;
-		mThreadErrorp = NULL;
-	}
 
 	SUBSYSTEM_CLEANUP_DBG(LLCommon);
 }
@@ -374,43 +355,17 @@ void LLApp::setupErrorHandling(bool second_instance)
 
 #if defined(LL_WINDOWS)
 
-#if LL_SEND_CRASH_REPORTS && ! defined(AL_SENTRY)
-	EnableCrashingOnCrashes();
-
-	// This sets a callback to handle w32 signals to the console window.
-	// The viewer shouldn't be affected, sicne its a windowed app.
-	SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
-#endif // LL_SEND_CRASH_REPORTS && ! defined(AL_SENTRY)
 #else  // ! LL_WINDOWS
 	//
+#if ! defined(AL_SENTRY)
 	// Start up signal handling.
 	//
 	// There are two different classes of signals.  Synchronous signals are delivered to a specific
 	// thread, asynchronous signals can be delivered to any thread (in theory)
 	//
 	setup_signals();
+#endif // ! AL_SENTRY
 #endif // ! LL_WINDOWS
-
-#if defined(AL_SENTRY)
-    // do not start our own error thread
-#else // ! AL_SENTRY
-	startErrorThread();
-#endif
-}
-
-void LLApp::startErrorThread()
-{
-	//
-	// Start the error handling thread, which is responsible for taking action
-	// when the app goes into the APP_STATUS_ERROR state
-	//
-	if(!mThreadErrorp)
-	{
-		LL_INFOS() << "Starting error thread" << LL_ENDL;
-		mThreadErrorp = new LLErrorThread();
-		mThreadErrorp->setUserData((void *) this);
-		mThreadErrorp->start();
-	}
 }
 
 void LLApp::setErrorHandler(LLAppErrorHandler handler)
@@ -473,7 +428,7 @@ void LLApp::setStatus(EAppStatus status)
 // static
 void LLApp::setError()
 {
-	// set app status to ERROR so that the LLErrorThread notices
+	// set app status to ERROR
 	setStatus(APP_STATUS_ERROR);
 }
 
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 80288e1d82d8ea9b15fa57b7578497f4f9e43240..8d426b9abc20f01d458fb526d304137b9d5a5f76 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -34,7 +34,6 @@
 #include <atomic>
 #include <chrono>
 // Forward declarations
-class LLErrorThread;
 class LLLiveFile;
 #if LL_LINUX
 #include <signal.h>
@@ -53,7 +52,6 @@ void clear_signals();
 
 class LL_COMMON_API LLApp
 {
-	friend class LLErrorThread;
 public:
 	typedef enum e_app_status
 	{
@@ -67,11 +65,6 @@ class LL_COMMON_API LLApp
 	LLApp();
 	virtual ~LLApp();
 
-protected:
-	LLApp(LLErrorThread* error_thread);
-	void commonCtor();
-public:
-	
 	/** 
 	 * @brief Return the static app instance if one was created.
 	 */
@@ -257,14 +250,14 @@ class LL_COMMON_API LLApp
 	void setupErrorHandling(bool mSecondInstance=false);
 
 	void setErrorHandler(LLAppErrorHandler handler);
-	static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
+	static void runErrorHandler(); // run shortly after we detect an error
 	//@}
-	
+
 	// the maximum length of the minidump filename returned by getMiniDumpFilename()
 	static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
 
 	// change the directory where Breakpad minidump files are written to
-    void setDebugFileNames(const std::string &path);
+	void setDebugFileNames(const std::string &path);
 
 	// Return the Google Breakpad minidump filename after a crash.
 	std::string* getStaticDebugFile() { return &mStaticDebugFileName; }
@@ -300,10 +293,8 @@ class LL_COMMON_API LLApp
 	void stepFrame();
 
 private:
-	void startErrorThread();
-	
-    std::string mStaticDebugFileName;
-    std::string mDynamicDebugFileName;
+	std::string mStaticDebugFileName;
+	std::string mDynamicDebugFileName;
 
 	// *NOTE: On Windows, we need a routine to reset the structured
 	// exception handler when some evil driver has taken it over for
@@ -311,9 +302,6 @@ class LL_COMMON_API LLApp
 	typedef int(*signal_handler_func)(int signum);
 	static LLAppErrorHandler sErrorHandler;
 
-	// Default application threads
-	LLErrorThread* mThreadErrorp;		// Waits for app to go to status ERROR, then runs the error callback
-
 	// This is the application level runnable scheduler.
 	LLRunner mRunner;
 
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index fcfa569ccf193339485fd5aa97946c1734e44a21..4342d2a695e9ad5b63b677311facc76ba04f02f6 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -276,7 +276,6 @@ namespace LLError
 		// used to indicate no class info known for logging
 
     //LLCallStacks keeps track of call stacks and output the call stacks to log file
-    //when LLAppViewer::handleViewerCrash() is triggered.
     //
     //Note: to be simple, efficient and necessary to keep track of correct call stacks, 
     //LLCallStacks is designed not to be thread-safe.
diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp
deleted file mode 100644
index a20253bf45c5c28f8727f1291199a1c3e4ba37a2..0000000000000000000000000000000000000000
--- a/indra/llcommon/llerrorthread.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/** 
- * @file llerrorthread.cpp
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * 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
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llerrorthread.h"
-
-#include "llapp.h"
-#include "lltimer.h"	// ms_sleep()
-
-LLErrorThread::LLErrorThread()
-	: LLThread("Error"),
-	  mUserDatap(NULL)
-{
-}
-
-void LLErrorThread::setUserData(void* user_data)
-{
-	mUserDatap = user_data;
-}
-
-
-void* LLErrorThread::getUserData() const
-{
-	return mUserDatap;
-}
-
-#if !LL_WINDOWS
-//
-// Various signal/error handling functions that can't be put into the class
-//
-void get_child_status(const int waitpid_status, int &process_status, bool &exited, bool do_logging)
-{
-	exited = false;
-	process_status = -1;
-	// The child process exited.  Call its callback, and then clean it up
-	if (WIFEXITED(waitpid_status))
-	{
-		process_status = WEXITSTATUS(waitpid_status);
-		exited = true;
-		if (do_logging)
-		{
-			LL_INFOS() << "get_child_status - Child exited cleanly with return of " << process_status << LL_ENDL;
-		}
-		return;
-	}
-	else if (WIFSIGNALED(waitpid_status))
-	{
-		process_status = WTERMSIG(waitpid_status);
-		exited = true;
-		if (do_logging)
-		{
-			LL_INFOS() << "get_child_status - Child died because of uncaught signal " << process_status << LL_ENDL;
-#ifdef WCOREDUMP
-			if (WCOREDUMP(waitpid_status))
-			{
-				LL_INFOS() << "get_child_status - Child dumped core" << LL_ENDL;
-			}
-			else
-			{
-				LL_INFOS() << "get_child_status - Child didn't dump core" << LL_ENDL;
-			}
-#endif
-		}
-		return;
-	}
-	else if (do_logging)
-	{
-		// This is weird.  I just dump the waitpid status into the status code,
-		// not that there's any way of telling what it is...
-		LL_INFOS() << "get_child_status - Got SIGCHILD but child didn't exit" << LL_ENDL;
-		process_status = waitpid_status;
-	}
-
-}
-#endif
-
-void LLErrorThread::run()
-{
-	LLApp::sErrorThreadRunning = TRUE;
-	// This thread sits and waits for the sole purpose
-	// of waiting for the signal/exception handlers to flag the
-	// application state as APP_STATUS_ERROR.
-	//LL_INFOS() << "thread_error - Waiting for an error" << LL_ENDL;
-
-	while (! (LLApp::isError() || LLApp::isStopped()))
-	{
-		ms_sleep(10);
-	}
-	if (LLApp::isError())
-	{
-		// The app is in an error state, run the application's error handler.
-		//LL_INFOS() << "thread_error - An error has occurred, running error callback!" << LL_ENDL;
-		// Run the error handling callback
-		LLApp::runErrorHandler();
-	}
-	else
-	{
-		// Everything is okay, a clean exit.
-		//LL_INFOS() << "thread_error - Application exited cleanly" << LL_ENDL;
-	}
-	
-	//LL_INFOS() << "thread_error - Exiting" << LL_ENDL;
-	LLApp::sErrorThreadRunning = FALSE;
-}
-
diff --git a/indra/llcommon/llerrorthread.h b/indra/llcommon/llerrorthread.h
deleted file mode 100644
index 037fce7e3f7975516ce9e3c9f62e34d5173dafdc..0000000000000000000000000000000000000000
--- a/indra/llcommon/llerrorthread.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/** 
- * @file llerrorthread.h
- * @brief Specialized thread to handle runtime errors.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * 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
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLERRORTHREAD_H
-#define LL_LLERRORTHREAD_H
-
-#include "llthread.h"
-
-class LL_COMMON_API LLErrorThread final : public LLThread
-{
-public:
-	LLErrorThread();
-	~LLErrorThread() = default;
-
-	/*virtual*/ void run(void);
-	void setUserData(void *user_data);
-	void *getUserData() const;
-
-protected:
-	void* mUserDatap; // User data associated with this thread
-};
-
-#endif // LL_LLERRORTHREAD_H
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 536e66de24270f82e34bb2e06456c0d6f38317db..366ce79381411c0b3e1331a39345ed6c066b4142 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -553,7 +553,9 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
 
 	// if the input wasn't a correctly formatted legacy name, just return it  
 	// cleaned up from a potential terminal "Resident"
-	return cleanFullName(full_name);
+    std::string clean_name = cleanFullName(full_name);
+    LLStringUtil::toLower(clean_name);
+	return clean_name;
 }
 
 //static 
diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp
index ac968fe496e82c39a1b45b2862067c74ab2fcb3a..7de38af7d0bd51183f11c1ea21b5d35b8fbd54f0 100644
--- a/indra/llprimitive/llmaterial.cpp
+++ b/indra/llprimitive/llmaterial.cpp
@@ -438,18 +438,18 @@ bool LLMaterial::operator != (const LLMaterial& rhs) const
 }
 
 
-U32 LLMaterial::getShaderMask(U32 alpha_mode)
+U32 LLMaterial::getShaderMask(U32 alpha_mode, BOOL is_alpha)
 { //NEVER incorporate this value into the message system -- this function will vary depending on viewer implementation
-    U32 ret = 0;
 
-    //two least significant bits are "diffuse alpha mode"
-    if (alpha_mode != DIFFUSE_ALPHA_MODE_DEFAULT)
+	//two least significant bits are "diffuse alpha mode"
+	U32 ret = alpha_mode;
+    if (ret == DIFFUSE_ALPHA_MODE_DEFAULT)
     {
-        ret = alpha_mode;
-    }
-    else
-    {
-        ret = getDiffuseAlphaMode();
+		ret = getDiffuseAlphaMode();
+		if (ret == DIFFUSE_ALPHA_MODE_BLEND && !is_alpha)
+		{
+			ret = DIFFUSE_ALPHA_MODE_NONE;
+		}
     }
 
     llassert(ret < SHADER_COUNT);
diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h
index 5d3f4abf2793ab6477e7ef7ceb37430fe90440e3..0adaa6b62c1cee1ed8eec19d473eeca750b5621d 100644
--- a/indra/llprimitive/llmaterial.h
+++ b/indra/llprimitive/llmaterial.h
@@ -124,7 +124,7 @@ class LLMaterial final : public LLRefCount
     bool        operator == (const LLMaterial& rhs) const;
     bool        operator != (const LLMaterial& rhs) const;
 
-    U32         getShaderMask(U32 alpha_mode = DIFFUSE_ALPHA_MODE_DEFAULT);
+    U32         getShaderMask(U32 alpha_mode, BOOL is_alpha);
     LLUUID      getHash() const;
 
 protected:
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 78a6fab0cb91bda8c593ef53dab30dccad0fe3ad..d7e9ed10dd0e56f7eaa82541239799e05bbfe4bf 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -491,7 +491,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max
 	return getWidthF32(wtext.c_str(), begin_offset, max_chars);
 }
 
-F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
+F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const
 {
 	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
 
@@ -514,12 +514,15 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 
 		F32 advance = mFontFreetype->getXAdvance(fgi);
 
-		// for the last character we want to measure the greater of its width and xadvance values
-		// so keep track of the difference between these values for the each character we measure
-		// so we can fix things up at the end
-		width_padding = llmax(	0.f,											// always use positive padding amount
-								width_padding - advance,						// previous padding left over after advance of current character
-								(F32)(fgi->mWidth + fgi->mXBearing) - advance);	// difference between width of this character and advance to next character
+		if (!no_padding)
+		{
+			// for the last character we want to measure the greater of its width and xadvance values
+			// so keep track of the difference between these values for the each character we measure
+			// so we can fix things up at the end
+			width_padding = llmax(0.f,											// always use positive padding amount
+				width_padding - advance,						// previous padding left over after advance of current character
+				(F32)(fgi->mWidth + fgi->mXBearing) - advance);	// difference between width of this character and advance to next character
+		}
 
 		cur_x += advance;
 		llwchar next_char = wchars[i+1];
@@ -536,8 +539,11 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 		cur_x = (F32)ll_round(cur_x);
 	}
 
-	// add in extra pixels for last character's width past its xadvance
-	cur_x += width_padding;
+	if (!no_padding)
+	{
+		// add in extra pixels for last character's width past its xadvance
+		cur_x += width_padding;
+	}
 
 	return cur_x / sScaleX;
 }
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index f7461af3dfbb6c7afeccb731c8b50de5f2323649..7d815bf9b56510b891838dd6fe1c6e90236c1d31 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -138,7 +138,7 @@ class LLFontGL
 	F32 getWidthF32(const std::string& utf8text) const;
 	F32 getWidthF32(const llwchar* wchars) const;
 	F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const;
-	F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars) const;
+	F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, bool no_padding = false) const;
 
 	// The following are called often, frequently with large buffers, so do not use a string interface
 	
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index af9360cf08d8b88cd540047fa43cd6dac4d73cf7..1df1e48d6a8f8d98e1f344ccbb426777c370ef21 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -903,10 +903,17 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32
 						{
 							stop_glerror();
 
-							if (prev_mip_data != cur_mip_data)
-								delete[] prev_mip_data;
+							if (prev_mip_data)
+							{
+								if (prev_mip_data != cur_mip_data)
+									delete[] prev_mip_data;
+								prev_mip_data = nullptr;
+							}
 							if (cur_mip_data)
+							{
 								delete[] cur_mip_data;
+								cur_mip_data = nullptr;
+							}
 							
 							mGLTextureCreated = false;
 							return FALSE;
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index dad94168f1d3aeca23c7b9938601609018b772e7..3b476c683132e25ba0e1ab652797b98ee48af471 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -283,6 +283,17 @@ void LLLayoutStack::draw()
 	}
 }
 
+void LLLayoutStack::deleteAllChildren()
+{
+    mPanels.clear();
+    LLView::deleteAllChildren();
+
+    // Not really needed since nothing is left to
+    // display, but for the sake of consistency
+    updateFractionalSizes();
+    mNeedsLayout = true;
+}
+
 void LLLayoutStack::removeChild(LLView* view)
 {
 	LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
@@ -290,12 +301,14 @@ void LLLayoutStack::removeChild(LLView* view)
 	if (embedded_panelp)
 	{
 		mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
-		delete embedded_panelp;
+        LLView::removeChild(view);
 		updateFractionalSizes();
 		mNeedsLayout = true;
 	}
-
-	LLView::removeChild(view);
+    else
+    {
+        LLView::removeChild(view);
+    }
 }
 
 BOOL LLLayoutStack::postBuild()
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 1227acd0339980801dfd13017f3ab5ea001565e0..b0b06059e1ad0d1df88886c91583b8b36e964238 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -67,6 +67,7 @@ class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
 	virtual ~LLLayoutStack();
 
 	/*virtual*/ void draw();
+    /*virtual*/ void deleteAllChildren();
 	/*virtual*/ void removeChild(LLView*);
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index c6eb6b12d1be30adfb21e05e654beae11511d4f5..423adea3b916c9019aadca044020fcde1066a6b0 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -1903,6 +1903,13 @@ bool LLMenuGL::addContextChild(LLView* view, S32 tab_group)
 	return false;
 }
 
+
+void LLMenuGL::deleteAllChildren()
+{
+    mItems.clear();
+    LLUICtrl::deleteAllChildren();
+}
+
 void LLMenuGL::removeChild( LLView* ctrl)
 {
 	// previously a dynamic_cast with if statement to check validity
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 43c1d218a0a5ff3120082456f887a2a5db4fa5ae..2a81bacd31846a8f9748dff5a7327fa182d8fb30 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -451,6 +451,7 @@ class LLMenuGL
 	/*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha);
 	/*virtual*/ void setVisible(BOOL visible);
 	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
+    /*virtual*/ void deleteAllChildren();
 	/*virtual*/ void removeChild( LLView* ctrl);
 	/*virtual*/ BOOL postBuild();
 	
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 3e026b7d752bfb4d64185cadc917c865c7bce466..474fa687a782f78bbba6b37427851611978aa5f4 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -128,6 +128,7 @@ class LLPanel : public LLUICtrl, public LLBadgeHolder
 	virtual 	void	clearCtrls(); // overridden in LLPanelObject and LLPanelVolume
 
 	// Border controls
+	const LLViewBorder* getBorder() const { return mBorder; }
 	void addBorder( LLViewBorder::Params p);
 	void addBorder();
 	void			removeBorder();
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 071ceb39395d78ebb0d0db5b84eaf5b6ffadf69d..b5214eef7108f1391ab6792ae6beb7009d4ef43f 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -378,7 +378,7 @@ void LLTextBase::onValueChange(S32 start, S32 end)
 {
 }
 
-std::vector<LLRect> LLTextBase::getSelctionRects(const highlight_list_t& highlights)
+std::vector<LLRect> LLTextBase::getSelectionRects(const highlight_list_t& highlights)
 {
     // Nor supposed to be called without selection
     llassert(hasSelection());
@@ -518,7 +518,7 @@ void LLTextBase::drawHighlightsBackground(const highlight_list_t& highlights, co
 	if (!mLineInfoList.empty())
 // [/SL:KB]
 	{
-        std::vector<LLRect> selection_rects = getSelctionRects(highlights);
+        std::vector<LLRect> selection_rects = getSelectionRects(highlights);
 		
 		// Draw the selection box (we're using a box instead of reversing the colors on the selected text).
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -3674,7 +3674,7 @@ bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w
 		height = mFontHeight;
 		const LLWString &text = getWText();
 		// if last character is a newline, then return true, forcing line break
-		width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars);
+		width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars, true);
 	}
 	return false;
 }
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index a064ea64e277343fc7087367abf4ccb0598969f4..6e66192c3ad70eb89c2c2f9393ca66f9e3db93f1 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -680,7 +680,7 @@ class LLTextBase
 public:
 	bool							hasSelection() const { return (mSelectionStart !=mSelectionEnd); }
 
-    std::vector<LLRect> getSelctionRects(const highlight_list_t& highlights);
+    std::vector<LLRect> getSelectionRects(const highlight_list_t& highlights);
 
 protected:
 	// text segmentation and flow
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 4fede1ed02502d43d68478e31a36a868547a2a18..584825d4e920f30f6d0146156323fe673a985910 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -174,7 +174,8 @@ void LLTextBox::reshapeToFitText(BOOL called_from_parent)
 
 	S32 width = getTextPixelWidth();
 	S32 height = getTextPixelHeight();
-	reshape( width + 2 * mHPad, height + 2 * mVPad, called_from_parent );
+    //consider investigating reflow() to find missing width pixel (see SL-17045 changes)
+	reshape( width + 2 * mHPad + 1, height + 2 * mVPad, called_from_parent );
 }
 
 
diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index dfff572dbac37ee12ed5f991910d13850d02193d..87d76e84cec0406a430d092f44d6edfe11190b4f 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -199,7 +199,6 @@ LLUIColor LLUIColorTable::getColor(std::string_view name, const LLColor4& defaul
 void LLUIColorTable::setColor(std::string_view name, const LLColor4& color)
 {
 	setColor(name, color, mUserSetColors);
-	setColor(name, color, mLoadedColors);
 }
 
 bool LLUIColorTable::loadFromSettings()
@@ -226,6 +225,11 @@ void LLUIColorTable::saveUserSettings(const bool scrub /* = false */) const
 
 	for (const auto& color_pair : mUserSetColors)
 	{
+		// Compare user color value with the default value, skip if equal
+		string_color_map_t::const_iterator itd = mLoadedColors.find(color_pair.first);
+		if(itd != mLoadedColors.end() && itd->second == color_pair.second)
+			continue;
+	
 		if (!scrub || color_pair.first.find("ColorPaletteEntry") != std::string::npos)
 		{
 			ColorEntryParams color_entry;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index a53c95242eb680967214c7ef11d8996439cc9cee..7bb6432153883c331a6aacb87a5409d1826e846b 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -576,8 +576,10 @@ void LLView::deleteAllChildren()
 
 	while (!mChildList.empty())
 	{
-		LLView* viewp = mChildList.front();
-		delete viewp; // will remove the child from mChildList
+        LLView* viewp = mChildList.front();
+        viewp->mParentView = NULL;
+        delete viewp;
+        mChildList.pop_front();
 	}
 }
 
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index a079a92227bc330a928a660c391e932781387040..eae43221b514247e3fe69613bcd0f0c07098fd50 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -118,7 +118,8 @@ class LLWindow : public LLInstanceTracker<LLWindow>
 
 	// Sets cursor, may set to arrow+hourglass
 	virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; };
-	virtual ECursorType getCursor() const;
+    virtual ECursorType getCursor() const;
+    virtual ECursorType getNextCursor() const { return mNextCursor; };
 	virtual void updateCursor() = 0;
 
 	virtual void captureMouse() = 0;
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index fb4dbc2cc0b413a8b4417bdad9a62f590805d450..611b0bee49db39b47915bf76b7784ec0869ba8c0 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -13659,13 +13659,13 @@
     <key>TranslationService</key>
     <map>
       <key>Comment</key>
-      <string>Translation API to use. (google|bing)</string>
+      <string>Translation API to use. (google|azure)</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
-      <string>bing</string>
+      <string>azure</string>
     </map>
     <key>GoogleTranslateAPIKey</key>
     <map>
@@ -13681,7 +13681,7 @@
     <key>BingTranslateAPIKey</key>
     <map>
       <key>Comment</key>
-      <string>Bing AppID to use with the Microsoft Translator API</string>
+      <string>(Deprecated) Bing AppID to use with the Microsoft Translator API</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -13689,6 +13689,28 @@
       <key>Value</key>
       <string></string>
     </map>
+    <key>AzureTranslateAPIKey</key>
+    <map>
+      <key>Comment</key>
+      <string>Azure Translation service data to use with the MS Azure Translator API</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>LLSD</string>
+      <key>Value</key>
+      <string></string>
+    </map>
+    <key>DeepLTranslateAPIKey</key>
+    <map>
+        <key>Comment</key>
+        <string>DeepL Translation service data to use with the DeepL Translator API</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>LLSD</string>
+        <key>Value</key>
+        <string></string>
+    </map>
     <key>TutorialURL</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1003008ba2a21bef2c5bc1c7ce6f4afa9c578bca..c2293e66aa1878034869cc0ee61559ec41132824 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3607,149 +3607,6 @@ void LLAppViewer::writeSystemInfo()
 	writeDebugInfo(); // Save out debug_info.log early, in case of crash.
 }
 
-void LLAppViewer::handleViewerCrash()
-{
-	LL_INFOS("CRASHREPORT") << "Handle viewer crash entry." << LL_ENDL;
-
-	LL_INFOS("CRASHREPORT") << "Last render pool type: " << LLPipeline::sCurRenderPoolType << LL_ENDL ;
-
-	LLMemory::logMemoryInfo(true) ;
-
-	//print out recorded call stacks if there are any.
-	LLError::LLCallStacks::print();
-
-	LLAppViewer* pApp = LLAppViewer::instance();
-	if (pApp->beingDebugged())
-	{
-		// This will drop us into the debugger.
-		abort();
-	}
-
-	if (LLApp::isCrashloggerDisabled())
-	{
-		abort();
-	}
-
-	// Returns whether a dialog was shown.
-	// Only do the logic in here once
-	if (pApp->mReportedCrash)
-	{
-		return;
-	}
-	pApp->mReportedCrash = TRUE;
-
-	// Insert crash host url (url to post crash log to) if configured.
-	std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
-	if(crashHostUrl != "")
-	{
-		gDebugInfo["Dynamic"]["CrashHostUrl"] = crashHostUrl;
-	}
-
-	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-	if ( parcel && parcel->getMusicURL()[0])
-	{
-		gDebugInfo["Dynamic"]["ParcelMusicURL"] = parcel->getMusicURL();
-	}
-	if ( parcel && parcel->getMediaURL()[0])
-	{
-		gDebugInfo["Dynamic"]["ParcelMediaURL"] = parcel->getMediaURL();
-	}
-
-	gDebugInfo["Dynamic"]["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds());
-	gDebugInfo["Dynamic"]["RAMInfo"]["Allocated"] = LLSD::Integer(LLMemory::getCurrentRSS() / 1024);
-
-	if(gLogoutInProgress)
-	{
-		gDebugInfo["Dynamic"]["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
-	}
-	else
-	{
-		gDebugInfo["Dynamic"]["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
-	}
-
-	if(gAgent.getRegion())
-	{
-		gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegion()->getSimHostName();
-		gDebugInfo["Dynamic"]["CurrentRegion"] = gAgent.getRegion()->getName();
-
-		const LLVector3& loc = gAgent.getPositionAgent();
-		gDebugInfo["Dynamic"]["CurrentLocationX"] = loc.mV[0];
-		gDebugInfo["Dynamic"]["CurrentLocationY"] = loc.mV[1];
-		gDebugInfo["Dynamic"]["CurrentLocationZ"] = loc.mV[2];
-	}
-
-	if(LLAppViewer::instance()->mMainloopTimeout)
-	{
-		gDebugInfo["Dynamic"]["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
-	}
-
-	// The crash is being handled here so set this value to false.
-	// Otherwise the crash logger will think this crash was a freeze.
-	gDebugInfo["Dynamic"]["CrashNotHandled"] = LLSD::Boolean(false);
-
-	//Write out the crash status file
-	//Use marker file style setup, as that's the simplest, especially since
-	//we're already in a crash situation
-	if (gDirUtilp)
-	{
-		std::string crash_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
-																			gLLErrorActivated
-																			? LLERROR_MARKER_FILE_NAME
-																			: ERROR_MARKER_FILE_NAME);
-		LLAPRFile crash_marker_file ;
-		crash_marker_file.open(crash_marker_file_name, LL_APR_WB);
-		if (crash_marker_file.getFileHandle())
-		{
-			LL_INFOS("MarkerFile") << "Created crash marker file " << crash_marker_file_name << LL_ENDL;
-			recordMarkerVersion(crash_marker_file);
-		}
-		else
-		{
-			LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_marker_file_name << LL_ENDL;
-		}
-	}
-	else
-	{
-		LL_WARNS("MarkerFile") << "No gDirUtilp with which to create error marker file name" << LL_ENDL;
-	}
-
-#ifdef LL_WINDOWS
-	Sleep(200);
-#endif
-
-    gDebugInfo["Dynamic"]["CrashType"]="crash";
-
-	if (gMessageSystem && gDirUtilp)
-	{
-		std::string filename;
-		filename = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "stats.log");
-        LL_DEBUGS("CRASHREPORT") << "recording stats " << filename << LL_ENDL;
-		llofstream file(filename.c_str(), std::ios_base::binary);
-		if(file.good())
-		{
-			gMessageSystem->summarizeLogs(file);
-			file.close();
-		}
-        else
-        {
-            LL_WARNS("CRASHREPORT") << "problem recording stats" << LL_ENDL;
-        }
-	}
-
-	if (gMessageSystem)
-	{
-		gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]);
-		gMessageSystem->stopLogging();
-	}
-
-	if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]);
-
-	gDebugInfo["FatalMessage"] = LLError::getFatalMessage();
-
-	// Close the debug file
-	pApp->writeDebugInfo(false);  //false answers the isStatic question with the least overhead.
-}
-
 // static
 void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file)
 {
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 03a783d7e59cc4e2a0a8da8433b69cc5b620dd02..4cb7439198560343051479c6a8b14caeac7fbc3a 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -115,7 +115,6 @@ class LLAppViewer : public LLApp
 	virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
 	                                     // return false if the error trap needed restoration.
 	virtual void initCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report?
-	static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
 	void checkForCrash();
     
 	// Thread accessors
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 510f5bcc095f6aab5da1803e0273ec98abb16772..8dc9f533ef8767cc15a1ede6fb986aa953e4490b 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -85,8 +85,6 @@ int main( int argc, char **argv )
 
 	// install unexpected exception handler
 	gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
-	// install crash handlers
-	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
 
 	bool ok = viewer_app_ptr->init();
 	if(!ok)
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index d367395d5d3a22fb053a73db1fa2e36efd9ca7e3..dc0bad04bcab06fbdc91633d6bb55e98419fd3ad 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -78,8 +78,6 @@ void constructViewer()
 	}
 
 	gViewerAppPtr = new LLAppViewerMacOSX();
-
-	gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash);
 }
 
 bool initViewer()
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 747b72fbba50623f0f6629cf6306ead9eaff753f..8c496e4095bd4652d908f9349ddbcdf8369d41cd 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -354,8 +354,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 
 	gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
 
-	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
-
 	// Set a debug info flag to indicate if multiple instances are running.
 	bool found_other_instance = !create_app_mutex();
 	gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance);
diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h
index a6de5e333dc3c892373125c50940aea45b963ebb..2722112b8f033d8566440bc82c85a257c2327bef 100644
--- a/indra/newview/llavatarpropertiesprocessor.h
+++ b/indra/newview/llavatarpropertiesprocessor.h
@@ -74,6 +74,7 @@ struct LLAvatarData
 	std::string	profile_url;
 	U8			caption_index;
 	std::string	caption_text;
+    std::string	customer_type;
 	U32			flags;
 	BOOL		allow_publish;
 };
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 875ea8c492fee8c86a5ff9bafca04ae13c82151c..39e9f2e4d2cb7723812bbf72651d8c947a231aa7 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -282,6 +282,7 @@ void LLDrawPoolAlpha::renderDebugAlpha()
         gGL.diffuseColor4f(1, 0, 0, 1);
         gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::getSmokeImage());
 
+
         renderAlphaHighlight();
 
 		pushUntexturedBatches(LLRenderPass::PASS_ALPHA_MASK);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 5f66d64285ab6d2974b5a25122aa38d039d0c5a9..6c99f648dec5ed3074e914bfb90d6576b2d1eb3d 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1776,7 +1776,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
                         }
 
                         *dst++ = tc;
-                        if (do_bump)
+                        if ((!mat && !gltf_mat) && do_bump)
                         {
                             bump_tc.push_back(tc);
                         }
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 73312f9890a304abea62b789be87d608f39b2a4b..4d7d6a4d4a6ce97c7e850d85a8f5d1a3e481e36c 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -608,11 +608,11 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
 		mOFN.lpstrFilter = ANIM_FILTER \
 			L"\0";
 		break;
-    case FFLOAD_GLTF:
-        mOFN.lpstrFilter = GLTF_FILTER \
-            L"\0";
-        break;
-    case FFLOAD_COLLADA:
+	case FFLOAD_GLTF:
+		mOFN.lpstrFilter = GLTF_FILTER \
+			L"\0";
+		break;
+	case FFLOAD_COLLADA:
 		mOFN.lpstrFilter = COLLADA_FILTER \
 			L"\0";
 		break;
@@ -1213,7 +1213,6 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension,
         case LLFilePicker::FFSAVE_ANIM:
             extension = "xaf";
             break;
-
         case LLFilePicker::FFSAVE_GLTF:
             extension = "glb";
             break;
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 87279b6970a14565d1da68af50bdace055399848..10c42b2844bfda0f5919dc41133ab2f1f5b7e69d 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -117,6 +117,8 @@ LLFloaterIMNearbyChat::LLFloaterIMNearbyChat(const LLSD& llsd)
 	mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&cb_do_nothing));
 	mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&cb_do_nothing));
 	mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&cb_do_nothing));
+
+    mMinFloaterHeight = EXPANDED_MIN_HEIGHT;
 }
 
 //static
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 1550cf94a26eb4c9b56db364223abca0b60c3785..e6222c8b56e00bf124ee8c639c32a87ba7cca049 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -92,6 +92,8 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
     mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2));
     mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2));
     mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing));
+
+    mMinFloaterHeight = getMinHeight();
 }
 
 LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
@@ -939,10 +941,13 @@ void LLFloaterIMSessionTab::reshapeFloater(bool collapse)
 		S32 height = mContentPanel->getRect().getHeight() + mToolbarPanel->getRect().getHeight()
 			+ mChatLayoutPanel->getRect().getHeight() - mChatLayoutPanelHeight + 2;
 		floater_rect.mTop -= height;
+
+        setResizeLimits(getMinWidth(), floater_rect.getHeight());
 	}
 	else
 	{
 		floater_rect.mTop = floater_rect.mBottom + mFloaterHeight;
+        setResizeLimits(getMinWidth(), mMinFloaterHeight);
 	}
 
 	enableResizeCtrls(true, true, !collapse);
@@ -967,6 +972,7 @@ void LLFloaterIMSessionTab::restoreFloater()
 		setShape(floater_rect, true);
 		mBodyStack->updateLayout();
 		mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon"));
+        setResizeLimits(getMinWidth(), mMinFloaterHeight);
 		setMessagePaneExpanded(true);
 		saveCollapsedState();
 		mInputEditor->enableSingleLineMode(false);
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index e14e5c88dac19765a59f2f5f57f220147e7dfcc9..183c194afcdc1f38bc7bbc90f7107f57e22bbef6 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -155,6 +155,7 @@ class LLFloaterIMSessionTab
 
 	bool mMessagePaneExpanded;
 	bool mIsParticipantListExpanded;
+    S32 mMinFloaterHeight;
 
 
 	LLIMModel::LLIMSession* mSession;
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index cbdab11ca72daa930569f74d168d9fd9349a782c..01e41a055583283395084b6f5ef38f89f8640d1a 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -316,7 +316,6 @@ void LLFloaterRegionInfo::onOpen(const LLSD& key)
 	}
 	refreshFromRegion(gAgent.getRegion());
 	requestRegionInfo();
-	requestMeshRezInfo();
 
 	if (!mGodLevelChangeSlot.connected())
 	{
@@ -1005,19 +1004,6 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L
 	return false;
 }
 
-void LLFloaterRegionInfo::requestMeshRezInfo()
-{
-	std::string sim_console_url = gAgent.getRegionCapability("SimConsoleAsync");
-
-	if (!sim_console_url.empty())
-	{
-		std::string request_str = "get mesh_rez_enabled";
-		
-        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(sim_console_url, LLSD(request_str),
-            "Requested mesh_rez_enabled", "Error requesting mesh_rez_enabled");
-	}
-}
-
 // setregioninfo
 // strings[0] = 'Y' - block terraform, 'N' - not
 // strings[1] = 'Y' - block fly, 'N' - not
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index cf38c0458c119f7dc67382d00fd435f5682e8276..a1b11faafa955327cb566dcdde1abd256c696fd4 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -102,7 +102,6 @@ class LLFloaterRegionInfo final : public LLFloater
 	
 	void onRegionChanged();
 	void requestRegionInfo();
-	void requestMeshRezInfo();
 	void enableTopButtons();
 	void disableTopButtons();
 
diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index 082bb888b1fa444003fba5901002131bc84cba64..d29ecbbf956f47824975b337c89325898167f287 100644
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -45,15 +45,9 @@
 LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key)
 :	LLFloater(key)
 ,	mMachineTranslationCB(NULL)
-,	mLanguageCombo(NULL)
-,	mTranslationServiceRadioGroup(NULL)
-,	mBingAPIKeyEditor(NULL)
-,	mGoogleAPIKeyEditor(NULL)
-,	mBingVerifyBtn(NULL)
-,	mGoogleVerifyBtn(NULL)
-,	mOKBtn(NULL)
-,	mBingKeyVerified(false)
+,	mAzureKeyVerified(false)
 ,	mGoogleKeyVerified(false)
+,	mDeepLKeyVerified(false)
 {
 }
 
@@ -63,24 +57,54 @@ BOOL LLFloaterTranslationSettings::postBuild()
 	mMachineTranslationCB = getChild<LLCheckBoxCtrl>("translate_chat_checkbox");
 	mLanguageCombo = getChild<LLComboBox>("translate_language_combo");
 	mTranslationServiceRadioGroup = getChild<LLRadioGroup>("translation_service_rg");
-	mBingAPIKeyEditor = getChild<LLLineEditor>("bing_api_key");
+    mAzureAPIEndpointEditor = getChild<LLComboBox>("azure_api_endpoint_combo");
+	mAzureAPIKeyEditor = getChild<LLLineEditor>("azure_api_key");
+    mAzureAPIRegionEditor = getChild<LLLineEditor>("azure_api_region");
 	mGoogleAPIKeyEditor = getChild<LLLineEditor>("google_api_key");
-	mBingVerifyBtn = getChild<LLButton>("verify_bing_api_key_btn");
+    mDeepLAPIDomainCombo = getChild<LLComboBox>("deepl_api_domain_combo");
+    mDeepLAPIKeyEditor = getChild<LLLineEditor>("deepl_api_key");
+	mAzureVerifyBtn = getChild<LLButton>("verify_azure_api_key_btn");
 	mGoogleVerifyBtn = getChild<LLButton>("verify_google_api_key_btn");
+    mDeepLVerifyBtn = getChild<LLButton>("verify_deepl_api_key_btn");
 	mOKBtn = getChild<LLButton>("ok_btn");
 
 	mMachineTranslationCB->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this));
 	mTranslationServiceRadioGroup->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this));
 	mOKBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnOK, this));
 	getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloater::closeFloater, this, false));
-	mBingVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnBingVerify, this));
+	mAzureVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnAzureVerify, this));
 	mGoogleVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnGoogleVerify, this));
+    mDeepLVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnDeepLVerify, this));
+
+	mAzureAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+	mAzureAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL);
+    mAzureAPIRegionEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+    mAzureAPIRegionEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL);
+
+    mAzureAPIEndpointEditor->setFocusLostCallback([this](LLFocusableElement*)
+                                                  {
+                                                      setAzureVerified(false, false, 0);
+                                                  });
+    mAzureAPIEndpointEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param)
+                                               {
+                                                   setAzureVerified(false, false, 0);
+                                               });
 
-	mBingAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
-	mBingAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onBingKeyEdited, this), NULL);
 	mGoogleAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
 	mGoogleAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onGoogleKeyEdited, this), NULL);
 
+    mDeepLAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+    mDeepLAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onDeepLKeyEdited, this), NULL);
+
+    mDeepLAPIDomainCombo->setFocusLostCallback([this](LLFocusableElement*)
+                                                  {
+                                                      setDeepLVerified(false, false, 0);
+                                                  });
+    mDeepLAPIDomainCombo->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param)
+                                               {
+                                                setDeepLVerified(false, false, 0);
+                                               });
+
 	center();
 	return TRUE;
 }
@@ -92,17 +116,28 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 	mLanguageCombo->setSelectedByValue(gSavedSettings.getString("TranslateLanguage"), TRUE);
 	mTranslationServiceRadioGroup->setSelectedByValue(gSavedSettings.getString("TranslationService"), TRUE);
 
-	std::string bing_key = gSavedSettings.getString("BingTranslateAPIKey");
-	if (!bing_key.empty())
+	LLSD azure_key = gSavedSettings.getLLSD("AzureTranslateAPIKey");
+	if (azure_key.isMap() && !azure_key["id"].asString().empty())
 	{
-		mBingAPIKeyEditor->setText(bing_key);
-		mBingAPIKeyEditor->setTentative(FALSE);
-		verifyKey(LLTranslate::SERVICE_BING, bing_key, false);
+		mAzureAPIKeyEditor->setText(azure_key["id"].asString());
+		mAzureAPIKeyEditor->setTentative(false);
+        if (azure_key.has("region") && !azure_key["region"].asString().empty())
+        {
+            mAzureAPIRegionEditor->setText(azure_key["region"].asString());
+            mAzureAPIRegionEditor->setTentative(false);
+        }
+        else
+        {
+            mAzureAPIRegionEditor->setTentative(true);
+        }
+        mAzureAPIEndpointEditor->setValue(azure_key["endpoint"]);
+		verifyKey(LLTranslate::SERVICE_AZURE, azure_key, false);
 	}
 	else
 	{
-		mBingAPIKeyEditor->setTentative(TRUE);
-		mBingKeyVerified = FALSE;
+		mAzureAPIKeyEditor->setTentative(TRUE);
+        mAzureAPIRegionEditor->setTentative(true);
+		mAzureKeyVerified = FALSE;
 	}
 
 	std::string google_key = gSavedSettings.getString("GoogleTranslateAPIKey");
@@ -118,39 +153,74 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 		mGoogleKeyVerified = FALSE;
 	}
 
+    LLSD deepl_key = gSavedSettings.getLLSD("DeepLTranslateAPIKey");
+    if (deepl_key.isMap() && !deepl_key["id"].asString().empty())
+    {
+        mDeepLAPIKeyEditor->setText(deepl_key["id"].asString());
+        mDeepLAPIKeyEditor->setTentative(false);
+        mDeepLAPIDomainCombo->setValue(deepl_key["domain"]);
+        verifyKey(LLTranslate::SERVICE_DEEPL, deepl_key, false);
+    }
+    else
+    {
+        mDeepLAPIKeyEditor->setTentative(TRUE);
+        mDeepLKeyVerified = FALSE;
+    }
+
 	updateControlsEnabledState();
 }
 
-void LLFloaterTranslationSettings::setBingVerified(bool ok, bool alert)
+void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert, S32 status)
 {
 	if (alert)
 	{
-		showAlert(ok ? "bing_api_key_verified" : "bing_api_key_not_verified");
+		showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified", status);
 	}
 
-	mBingKeyVerified = ok;
+	mAzureKeyVerified = ok;
 	updateControlsEnabledState();
 }
 
-void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert)
+void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert, S32 status)
 {
 	if (alert)
 	{
-		showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified");
+		showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified", status);
 	}
 
 	mGoogleKeyVerified = ok;
 	updateControlsEnabledState();
 }
 
+void LLFloaterTranslationSettings::setDeepLVerified(bool ok, bool alert, S32 status)
+{
+    if (alert)
+    {
+        showAlert(ok ? "deepl_api_key_verified" : "deepl_api_key_not_verified", status);
+    }
+
+    mDeepLKeyVerified = ok;
+    updateControlsEnabledState();
+}
+
 std::string LLFloaterTranslationSettings::getSelectedService() const
 {
 	return mTranslationServiceRadioGroup->getSelectedValue().asString();
 }
 
-std::string LLFloaterTranslationSettings::getEnteredBingKey() const
+LLSD LLFloaterTranslationSettings::getEnteredAzureKey() const
 {
-	return mBingAPIKeyEditor->getTentative() ? LLStringUtil::null : mBingAPIKeyEditor->getText();
+    LLSD key;
+    if (!mAzureAPIKeyEditor->getTentative())
+    {
+        key["endpoint"] = mAzureAPIEndpointEditor->getValue();
+        key["id"] = mAzureAPIKeyEditor->getText();
+        if (!mAzureAPIRegionEditor->getTentative())
+        {
+            key["region"] = mAzureAPIRegionEditor->getText();
+        }
+    }
+	return key;
 }
 
 std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const
@@ -158,10 +228,26 @@ std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const
 	return mGoogleAPIKeyEditor->getTentative() ? LLStringUtil::null : mGoogleAPIKeyEditor->getText();
 }
 
-void LLFloaterTranslationSettings::showAlert(const std::string& msg_name) const
+LLSD LLFloaterTranslationSettings::getEnteredDeepLKey() const
+{
+    LLSD key;
+    if (!mDeepLAPIKeyEditor->getTentative())
+    {
+        key["domain"] = mDeepLAPIDomainCombo->getValue();
+        key["id"] = mDeepLAPIKeyEditor->getText();
+    }
+    return key;
+}
+
+void LLFloaterTranslationSettings::showAlert(const std::string& msg_name, S32 status) const
 {
+    LLStringUtil::format_map_t string_args;
+    // For now just show an http error code, whole 'reason' string might be added later
+    string_args["[STATUS]"] = llformat("%d", status);
+    std::string message = getString(msg_name, string_args);
+
 	LLSD args;
-	args["MESSAGE"] = getString(msg_name);
+	args["MESSAGE"] = message;
 	LLNotificationsUtil::add("GenericAlert", args);
 }
 
@@ -170,34 +256,51 @@ void LLFloaterTranslationSettings::updateControlsEnabledState()
 	// Enable/disable controls based on the checkbox value.
 	bool on = mMachineTranslationCB->getValue().asBoolean();
 	std::string service = getSelectedService();
-	bool bing_selected = service == "bing";
+	bool azure_selected = service == "azure";
 	bool google_selected = service == "google";
+    bool deepl_selected = service == "deepl";
 
 	mTranslationServiceRadioGroup->setEnabled(on);
 	mLanguageCombo->setEnabled(on);
 
-	getChild<LLTextBox>("bing_api_key_label")->setEnabled(on);
-	mBingAPIKeyEditor->setEnabled(on);
+    // MS Azure
+    getChild<LLTextBox>("azure_api_endoint_label")->setEnabled(on);
+    mAzureAPIEndpointEditor->setEnabled(on && azure_selected);
+    getChild<LLTextBox>("azure_api_key_label")->setEnabled(on);
+    mAzureAPIKeyEditor->setEnabled(on && azure_selected);
+    getChild<LLTextBox>("azure_api_region_label")->setEnabled(on);
+    mAzureAPIRegionEditor->setEnabled(on && azure_selected);
 
-	getChild<LLTextBox>("google_api_key_label")->setEnabled(on);
-	mGoogleAPIKeyEditor->setEnabled(on);
+    mAzureVerifyBtn->setEnabled(on && azure_selected &&
+                                !mAzureKeyVerified && getEnteredAzureKey().isMap());
 
-	mBingAPIKeyEditor->setEnabled(on && bing_selected);
-	mGoogleAPIKeyEditor->setEnabled(on && google_selected);
+    // Google
+    getChild<LLTextBox>("google_api_key_label")->setEnabled(on);
+    mGoogleAPIKeyEditor->setEnabled(on && google_selected);
 
-	mBingVerifyBtn->setEnabled(on && bing_selected &&
-		!mBingKeyVerified && !getEnteredBingKey().empty());
 	mGoogleVerifyBtn->setEnabled(on && google_selected &&
 		!mGoogleKeyVerified && !getEnteredGoogleKey().empty());
 
-	bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified);
+    // DeepL
+    getChild<LLTextBox>("deepl_api_domain_label")->setEnabled(on);
+    mDeepLAPIDomainCombo->setEnabled(on && deepl_selected);
+    getChild<LLTextBox>("deepl_api_key_label")->setEnabled(on);
+    mDeepLAPIKeyEditor->setEnabled(on && deepl_selected);
+
+    mDeepLVerifyBtn->setEnabled(on && deepl_selected &&
+                                 !mDeepLKeyVerified && getEnteredDeepLKey().isMap());
+
+    bool service_verified =
+        (azure_selected && mAzureKeyVerified) 
+        || (google_selected && mGoogleKeyVerified)
+        || (deepl_selected && mDeepLKeyVerified);
 	gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
 
 	mOKBtn->setEnabled(!on || service_verified);
 }
 
 /*static*/
-void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert)
+void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert, S32 status)
 {
     LLFloaterTranslationSettings* floater =
         LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
@@ -210,20 +313,23 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
 
     switch (service)
     {
-    case LLTranslate::SERVICE_BING:
-        floater->setBingVerified(ok, alert);
+    case LLTranslate::SERVICE_AZURE:
+        floater->setAzureVerified(ok, alert, status);
         break;
     case LLTranslate::SERVICE_GOOGLE:
-        floater->setGoogleVerified(ok, alert);
+        floater->setGoogleVerified(ok, alert, status);
+        break;
+    case LLTranslate::SERVICE_DEEPL:
+        floater->setDeepLVerified(ok, alert, status);
         break;
     }
 }
 
 
-void LLFloaterTranslationSettings::verifyKey(int service, const std::string& key, bool alert)
+void LLFloaterTranslationSettings::verifyKey(int service, const LLSD& key, bool alert)
 {
     LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key,
-        boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert));
+        boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert, _3));
 }
 
 void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
@@ -239,11 +345,13 @@ void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
 	}
 }
 
-void LLFloaterTranslationSettings::onBingKeyEdited()
+void LLFloaterTranslationSettings::onAzureKeyEdited()
 {
-	if (mBingAPIKeyEditor->isDirty())
+	if (mAzureAPIKeyEditor->isDirty()
+        || mAzureAPIRegionEditor->isDirty())
 	{
-		setBingVerified(false, false);
+        // todo: verify mAzureAPIEndpointEditor url
+		setAzureVerified(false, false, 0);
 	}
 }
 
@@ -251,16 +359,24 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited()
 {
 	if (mGoogleAPIKeyEditor->isDirty())
 	{
-		setGoogleVerified(false, false);
+		setGoogleVerified(false, false, 0);
 	}
 }
 
-void LLFloaterTranslationSettings::onBtnBingVerify()
+void LLFloaterTranslationSettings::onDeepLKeyEdited()
 {
-	std::string key = getEnteredBingKey();
-	if (!key.empty())
+    if (mDeepLAPIKeyEditor->isDirty())
+    {
+        setDeepLVerified(false, false, 0);
+    }
+}
+
+void LLFloaterTranslationSettings::onBtnAzureVerify()
+{
+	LLSD key = getEnteredAzureKey();
+	if (key.isMap())
 	{
-		verifyKey(LLTranslate::SERVICE_BING, key);
+		verifyKey(LLTranslate::SERVICE_AZURE, key);
 	}
 }
 
@@ -269,26 +385,40 @@ void LLFloaterTranslationSettings::onBtnGoogleVerify()
 	std::string key = getEnteredGoogleKey();
 	if (!key.empty())
 	{
-		verifyKey(LLTranslate::SERVICE_GOOGLE, key);
+		verifyKey(LLTranslate::SERVICE_GOOGLE, LLSD(key));
 	}
 }
+
+void LLFloaterTranslationSettings::onBtnDeepLVerify()
+{
+    LLSD key = getEnteredDeepLKey();
+    if (key.isMap())
+    {
+        verifyKey(LLTranslate::SERVICE_DEEPL, key);
+    }
+}
+
 void LLFloaterTranslationSettings::onClose(bool app_quitting)
 {
 	std::string service = gSavedSettings.getString("TranslationService");
-	bool bing_selected = service == "bing";
+	bool azure_selected = service == "azure";
 	bool google_selected = service == "google";
+    bool deepl_selected = service == "deepl";
 
-	bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified);
-	gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
-
+    bool service_verified =
+        (azure_selected && mAzureKeyVerified)
+        || (google_selected && mGoogleKeyVerified)
+        || (deepl_selected && mDeepLKeyVerified);
+    gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
 }
 void LLFloaterTranslationSettings::onBtnOK()
 {
 	gSavedSettings.setBOOL("TranslateChat", mMachineTranslationCB->getValue().asBoolean());
 	gSavedSettings.setString("TranslateLanguage", mLanguageCombo->getSelectedValue().asString());
 	gSavedSettings.setString("TranslationService", getSelectedService());
-	gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey());
+	gSavedSettings.setLLSD("AzureTranslateAPIKey", getEnteredAzureKey());
 	gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey());
+    gSavedSettings.setLLSD("DeepLTranslateAPIKey", getEnteredDeepLKey());
 
 	closeFloater(false);
 }
diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h
index ff7ad9c50e462af22330b86192ef36ae4200c981..670734f152dec85a88fe79c3d94ff1d8081e0556 100644
--- a/indra/newview/llfloatertranslationsettings.h
+++ b/indra/newview/llfloatertranslationsettings.h
@@ -42,38 +42,48 @@ class LLFloaterTranslationSettings final : public LLFloater
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void onOpen(const LLSD& key);
 
-	void setBingVerified(bool ok, bool alert);
-	void setGoogleVerified(bool ok, bool alert);
+	void setAzureVerified(bool ok, bool alert, S32 status);
+	void setGoogleVerified(bool ok, bool alert, S32 status);
+    void setDeepLVerified(bool ok, bool alert, S32 status);
 	void onClose(bool app_quitting);
 
 private:
 	std::string getSelectedService() const;
-	std::string getEnteredBingKey() const;
+	LLSD getEnteredAzureKey() const;
 	std::string getEnteredGoogleKey() const;
-	void showAlert(const std::string& msg_name) const;
+    LLSD getEnteredDeepLKey() const;
+	void showAlert(const std::string& msg_name, S32 status) const;
 	void updateControlsEnabledState();
-	void verifyKey(int service, const std::string& key, bool alert = true);
+    void verifyKey(int service, const LLSD& key, bool alert = true);
 
 	void onEditorFocused(LLFocusableElement* control);
-	void onBingKeyEdited();
+	void onAzureKeyEdited();
 	void onGoogleKeyEdited();
-	void onBtnBingVerify();
+    void onDeepLKeyEdited();
+	void onBtnAzureVerify();
 	void onBtnGoogleVerify();
+    void onBtnDeepLVerify();
 	void onBtnOK();
 
-    static void setVerificationStatus(int service, bool alert, bool ok);
+    static void setVerificationStatus(int service, bool alert, bool ok, S32 status);
 
 	LLCheckBoxCtrl* mMachineTranslationCB;
 	LLComboBox* mLanguageCombo;
-	LLLineEditor* mBingAPIKeyEditor;
+    LLComboBox* mAzureAPIEndpointEditor;
+	LLLineEditor* mAzureAPIKeyEditor;
+    LLLineEditor* mAzureAPIRegionEditor;
 	LLLineEditor* mGoogleAPIKeyEditor;
+    LLComboBox* mDeepLAPIDomainCombo;
+    LLLineEditor* mDeepLAPIKeyEditor;
 	LLRadioGroup* mTranslationServiceRadioGroup;
-	LLButton* mBingVerifyBtn;
+	LLButton* mAzureVerifyBtn;
 	LLButton* mGoogleVerifyBtn;
+    LLButton* mDeepLVerifyBtn;
 	LLButton* mOKBtn;
 
-	bool mBingKeyVerified;
+	bool mAzureKeyVerified;
 	bool mGoogleKeyVerified;
+    bool mDeepLKeyVerified;
 };
 
 #endif // LL_LLFLOATERTRANSLATIONSETTINGS_H
diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp
index 68801b08951b622e828d6c731d9f303b56b0157c..6f93a78ca67f2054951d285ca59e81a128e1ba28 100644
--- a/indra/newview/llinspecttoast.cpp
+++ b/indra/newview/llinspecttoast.cpp
@@ -47,6 +47,7 @@ class LLInspectToast: public LLInspect
 
 	/*virtual*/ void onOpen(const LLSD& notification_id);
 	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
+    /*virtual*/ void deleteAllChildren();
 	/*virtual*/ void removeChild(LLView* child);
 private:
 	void onToastDestroy(LLToast * toast);
@@ -122,6 +123,12 @@ BOOL LLInspectToast::handleToolTip(S32 x, S32 y, MASK mask)
 	return LLFloater::handleToolTip(x, y, mask);
 }
 
+void LLInspectToast::deleteAllChildren()
+{
+    mPanel = NULL;
+    LLInspect::deleteAllChildren();
+}
+
 // virtual
 void LLInspectToast::removeChild(LLView* child)
 {
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 970278a7a426e7fd6051b1baf3c840a5cd48effc..607dc8b6d05137ed2822f827020cd7af63d848df 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -616,7 +616,11 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
 		}
 	}
 	
-	if(rv.isNull() && create_folder && root_id.notNull())
+	if(rv.isNull() 
+       && root_id.notNull()
+       && create_folder
+       && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS
+       && preferred_type != LLFolderType::FT_OUTBOX)
 	{
 
 		if (isInventoryUsable())
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index c9b4cbfa743461c38ad6abe797526a13188b89c3..c944edd4d6d9dce6cf8e649580e60c764ee192af 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -30,8 +30,10 @@
 #include "llagent.h"
 #include "llappviewer.h"
 #include "llcallbacklist.h"
-#include "llinventorypanel.h"
 #include "llinventorymodel.h"
+#include "llinventorypanel.h"
+#include "llnotificationsutil.h"
+#include "llstartup.h"
 #include "llviewercontrol.h"
 #include "llviewerinventory.h"
 #include "llviewermessage.h"
@@ -576,6 +578,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 	// *TODO:  Think I'd like to get a shared pointer to this and share it
 	// among all the folder requests.
 	uuid_vec_t recursive_cats;
+    uuid_vec_t all_cats; // dupplicate avoidance
 
 	LLSD folder_request_body;
 	LLSD folder_request_body_lib;
@@ -606,7 +609,8 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 		
 				if (cat)
 				{
-					if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
+					if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()
+                        && std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
 					{
 						LLSD folder_sd;
 						folder_sd["folder_id"]		= cat->getUUID();
@@ -645,6 +649,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 			{
 				recursive_cats.push_back(cat_id);
 			}
+            all_cats.push_back(cat_id);
 		}
 		else
 		{
@@ -963,6 +968,63 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
 					  << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL;
 
 	// Could use a 404 test here to try to detect revoked caps...
+
+    if(status == LLCore::HttpStatus(HTTP_FORBIDDEN))
+    {
+        // Too large, split into two if possible
+        if (gDisconnected || LLApp::isExiting())
+        {
+            return;
+        }
+
+        const std::string url(gAgent.getRegionCapability("FetchInventoryDescendents2"));
+        if (url.empty())
+        {
+            LL_WARNS(LOG_INV) << "Failed to get AIS2 cap" << LL_ENDL;
+            return;
+        }
+
+        S32 size = mRequestSD["folders"].size();
+
+        if (size > 1)
+        {
+            // Can split, assume that this isn't the library
+            LLSD folders;
+            uuid_vec_t recursive_cats;
+            LLSD::array_iterator iter = mRequestSD["folders"].beginArray();
+            LLSD::array_iterator end = mRequestSD["folders"].endArray();
+            while (iter != end)
+            {
+                folders.append(*iter);
+                LLUUID fodler_id = iter->get("folder_id").asUUID();
+                if (std::find(mRecursiveCatUUIDs.begin(), mRecursiveCatUUIDs.end(), fodler_id) != mRecursiveCatUUIDs.end())
+                {
+                    recursive_cats.push_back(fodler_id);
+                }
+                if (folders.size() == (S32)(size / 2))
+                {
+                    LLSD request_body;
+                    request_body["folders"] = folders;
+                    LLCore::HttpHandler::ptr_t  handler(new BGFolderHttpHandler(request_body, recursive_cats));
+                    gInventory.requestPost(false, url, request_body, handler, "Inventory Folder");
+                    recursive_cats.clear();
+                    folders.clear();
+                }
+                iter++;
+            }
+
+            LLSD request_body;
+            request_body["folders"] = folders;
+            LLCore::HttpHandler::ptr_t  handler(new BGFolderHttpHandler(request_body, recursive_cats));
+            gInventory.requestPost(false, url, request_body, handler, "Inventory Folder");
+            return;
+        }
+        else
+        {
+            // Can't split
+            LLNotificationsUtil::add("InventoryLimitReachedAIS");
+        }
+    }
 	
 	// This was originally the request retry logic for the inventory
 	// request which tested on HTTP_INTERNAL_ERROR status.  This
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 6b29dbadf908e0e609c0eeea4b3560cc2876f9f2..38b828c123004aae02a113b7774d38ccf2535557 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -1272,8 +1272,10 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = LLView::handleHover(x, y, mask);
 	if(handled)
-	{
-		ECursorType cursor = getWindow()->getCursor();
+    {
+        // getCursor gets current cursor, setCursor sets next cursor
+        // check that children didn't set own 'next' cursor
+		ECursorType cursor = getWindow()->getNextCursor();
 		if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && cursor == UI_CURSOR_ARROW)
 		{
 			// replace arrow cursor with arrow and hourglass cursor
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index 115f773c52845267c381c3300b24fd20579c8500..99619faa343842be8167cc4497c613c9f521457a 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -99,6 +99,7 @@ class LLMuteList final : public LLSingleton<LLMuteList>
 	BOOL isMuted(const LLUUID& id, const std::string& name = LLStringUtil::null, U32 flags = 0) const;
 
 	// Workaround for username-based mute search, a lot of string conversions so use cautiously
+    // Expects lower case username
 	BOOL isMuted(const std::string& username, U32 flags = 0) const;
 
 	// Alternate (convenience) form for places we don't need to pass the name, but do need flags
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 3dcdb4bb7b05e9a895784fe1cd9affb2191bd5a2..8bbff470e01382918fbb711375d4fd97c7ea6c0f 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -957,7 +957,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 { //set state of UI to match state of texture entry(ies)  (calls setEnabled, setValue, etc, but NOT setVisible)
 	LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
 
-	if( objectp
+	if (objectp
 		&& objectp->getPCode() == LL_PCODE_VOLUME
 		&& objectp->permModify())
 	{
@@ -987,7 +987,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
         mComboMatMedia->setEnabled(editable);
 
-		LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
+        LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
         if (radio_mat_type->getSelectedIndex() < MATTYPE_DIFFUSE)
         {
             radio_mat_type->selectNthItem(MATTYPE_DIFFUSE);
@@ -1011,7 +1011,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
         // *NOTE: The "identical" variable is currently only used to decide if
         // the texgen control should be tentative - this is not used by GLTF
         // materials. -Cosmic;2022-11-09
-		bool identical				= true;	// true because it is anded below
+		bool identical			= true;	// true because it is anded below
         bool identical_diffuse	= false;
         bool identical_norm		= false;
         bool identical_spec		= false;
@@ -1028,12 +1028,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		{
 			getChildView("color label")->setEnabled(editable);
 		}
-		LLColorSwatchCtrl*	color_swatch = findChild<LLColorSwatchCtrl>("colorswatch");
+		LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("colorswatch");
 
-		LLColor4 color					= LLColor4::white;
-		bool		identical_color	= false;
+		LLColor4 color = LLColor4::white;
+		bool identical_color = false;
 
-		if(color_swatch)
+		if (color_swatch)
 		{
 			LLSelectedTE::getColor(color, identical_color);
 			LLColor4 prev_color = color_swatch->get();
@@ -1067,7 +1067,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 		LLCtrlSelectionInterface* combobox_shininess = mComboShininess->getSelectionInterface();
 		if (combobox_shininess)
-				{
+		{
 			combobox_shininess->selectNthItem((S32)shiny);
 		}
 
@@ -1104,18 +1104,18 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE;
 
 			if (combobox_bumpiness)
-							{
+			{
 				combobox_bumpiness->selectNthItem((S32)bumpy);
-							}
+			}
 			else
-							{
+			{
 				LL_WARNS() << "failed childGetSelectionInterface for 'combobox bumpiness'" << LL_ENDL;
-							}
+			}
 
 			getChildView("combobox bumpiness")->setEnabled(editable);
 			getChild<LLUICtrl>("combobox bumpiness")->setTentative(!identical_bumpy);
 			getChildView("label bumpiness")->setEnabled(editable);
-        }
+		}
 
 		// Texture
 		{
@@ -1129,25 +1129,25 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			bool identical_image_format = false;
 			LLSelectedTE::getImageFormat(image_format, identical_image_format);
             
-         mIsAlpha = FALSE;
-         switch (image_format)
-         {
-               case GL_RGBA:
-               case GL_ALPHA:
-               {
-                  mIsAlpha = TRUE;
-               }
-               break;
-
-               case GL_RGB: break;
-               default:
-               {
-                  LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
-					}
-               break;
+			mIsAlpha = FALSE;
+			switch (image_format)
+			{
+				case GL_RGBA:
+				case GL_ALPHA:
+				{
+					mIsAlpha = TRUE;
+				}
+				break;
+
+				case GL_RGB: break;
+				default:
+				{
+					LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
 				}
+				break;
+			}
 
-			if(LLViewerMedia::getInstance()->textureHasMedia(id))
+			if (LLViewerMedia::getInstance()->textureHasMedia(id))
 			{
 				getChildView("button align")->setEnabled(editable);
 			}
@@ -1199,7 +1199,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				}
 				else if (id.isNull())
 				{
-						// None selected
+					// None selected
 					texture_ctrl->setTentative(FALSE);
 					texture_ctrl->setEnabled(FALSE);
 					texture_ctrl->setImageAssetID(LLUUID::null);
@@ -1212,7 +1212,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				}
 				else
 				{
-						// Tentative: multiple selected with different textures
+					// Tentative: multiple selected with different textures
 					texture_ctrl->setTentative(TRUE);
 					texture_ctrl->setEnabled(editable && !has_pbr_material);
 					texture_ctrl->setImageAssetID(id);
@@ -1223,7 +1223,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					
 					texture_ctrl->setBakeTextureEnabled(TRUE);
 				}
-				
 			}
 
 			if (shinytexture_ctrl)
@@ -1509,7 +1508,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 			LLComboBox*	mComboTexGen = getChild<LLComboBox>("combobox texgen");
 			if (mComboTexGen)
-            {
+			{
 				S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0;
                 bool enabled = editable && (index != 1);
                 bool identical_repeats = true;
@@ -1604,14 +1603,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					if (!mIsAlpha)
 					{ // ... unless there is no alpha channel in the texture, in which case alpha mode MUST ebe none
 						alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-				}
+					}
 
 					combobox_alphamode->selectNthItem(alpha_mode);
-			}
-			else
-			{
+				}
+				else
+				{
 					LL_WARNS() << "failed childGetSelectionInterface for 'combobox alphamode'" << LL_ENDL;
-			}
+				}
 				mSpinMaskCutoff->setValue(material->getAlphaMaskCutoff());
 				updateAlphaControls();
 
@@ -1622,15 +1621,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
                 mShinyTextureCtrl->setImageAssetID(material->getSpecularID());
 
 				if (!material->getSpecularID().isNull() && (shiny == SHINY_TEXTURE))
-			{
+				{
 					material->getSpecularOffset(offset_x,offset_y);
 					material->getSpecularRepeat(repeat_x,repeat_y);
 
 					if (identical_planar_texgen)
-			{
+					{
 						repeat_x *= 2.0f;
 						repeat_y *= 2.0f;
-			}
+					}
 
 					rot = material->getSpecularRotation();
 					getChild<LLUICtrl>("shinyScaleU")->setValue(repeat_x);
@@ -1642,7 +1641,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
                     mSpinEnvironment->setValue(material->getEnvironmentIntensity());
 
 					updateShinyControls(!material->getSpecularID().isNull(), true);
-		}
+				}
 
 				// Assert desired colorswatch color to match material AFTER updateShinyControls
 				// to avoid getting overwritten with the default on some UI state changes.
@@ -1708,14 +1707,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
             pbr_ctrl->setEnabled(FALSE);
         }
 		LLTextureCtrl*	texture_ctrl = getChild<LLTextureCtrl>("texture control"); 
-		if(texture_ctrl)
+		if (texture_ctrl)
 		{
 			texture_ctrl->setImageAssetID( LLUUID::null );
 			texture_ctrl->setEnabled( FALSE );  // this is a LLUICtrl, but we don't want it to have keyboard focus so we add it as a child, not a ctrl.
 // 			texture_ctrl->setValid(FALSE);
 		}
 		LLColorSwatchCtrl* mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
-		if(mColorSwatch)
+		if (mColorSwatch)
 		{
 			mColorSwatch->setEnabled( FALSE );			
 			mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c") );
@@ -1827,7 +1826,6 @@ void LLPanelFace::updateCopyTexButton()
                                                     && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1));
     std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");
     mMenuClipboardTexture->setToolTip(tooltip);
-
 }
 
 void LLPanelFace::refresh()
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index ef07be5a16bb9f8baa218f311107872b7397bbc7..b6d77b237416c84b393695b9e1226af1df478fd4 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -139,7 +139,7 @@ class LLPanelFace : public LLPanel
 	void			sendTexGen();				// applies and sends bump map
 	void			sendShiny(U32 shininess);			// applies and sends shininess
 	void			sendFullbright();		// applies and sends full bright
-	void        sendGlow();
+	void			sendGlow();
     void            alignTestureLayer();
 
     void            updateCopyTexButton();
@@ -284,7 +284,6 @@ class LLPanelFace : public LLPanel
     LLSpinCtrl* mSpinMaskCutoff  = nullptr;
 
 private:
-
 	bool		isAlpha() { return mIsAlpha; }
 
 	// Convenience funcs to keep the visual flack to a minimum
@@ -293,10 +292,10 @@ class LLPanelFace : public LLPanel
 	LLUUID	getCurrentSpecularMap();
 	U32		getCurrentShininess();
 	U32		getCurrentBumpiness();
-	U8			getCurrentDiffuseAlphaMode();
-	U8			getCurrentAlphaMaskCutoff();
-	U8			getCurrentEnvIntensity();
-	U8			getCurrentGlossiness();
+	U8		getCurrentDiffuseAlphaMode();
+	U8		getCurrentAlphaMaskCutoff();
+	U8		getCurrentEnvIntensity();
+	U8		getCurrentGlossiness();
 	F32		getCurrentBumpyRot();
 	F32		getCurrentBumpyScaleU();
 	F32		getCurrentBumpyScaleV();
@@ -372,7 +371,7 @@ class LLPanelFace : public LLPanel
 
 					U32		new_alpha_mode			= new_material->getDiffuseAlphaMode();
 					LLUUID	new_normal_map_id		= new_material->getNormalID();
-					LLUUID	new_spec_map_id		= new_material->getSpecularID();
+					LLUUID	new_spec_map_id			= new_material->getSpecularID();
 
 					if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
 					{
@@ -617,7 +616,6 @@ class LLPanelFace : public LLPanel
 	class LLSelectedTE
 	{
 	public:
-
 		static void getFace(class LLFace*& face_to_return, bool& identical_face);
 		static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
 		static void getTexId(LLUUID& id, bool& identical);
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 7254cbe49bfb0ef3356b715800f047b63bc3b164..af1d0a544a58f7386026cc77c2015886ca0282c3 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -1633,7 +1633,8 @@ void LLPanelObjectInventory::reset()
 		LLEditMenuHandler::gEditMenuHandler = mFolders;
 	}
 
-	LLRect scroller_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
+	int offset = hasBorder() ? getBorder()->getBorderWidth() << 1 : 0;
+	LLRect scroller_rect(0, getRect().getHeight() - offset, getRect().getWidth() - offset, 0);
 	LLScrollContainer::Params scroll_p;
 	scroll_p.name("task inventory scroller");
 	scroll_p.rect(scroller_rect);
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 743195bfda9c713c8da1232cd4b214bdea84e6e9..cfa5543cdc8b13b8dc05713d00f4dbbd7d8557a0 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -161,6 +161,7 @@ void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id)
     avatar_data->fl_about_text = result["fl_about_text"].asString();
     avatar_data->born_on = result["member_since"].asDate();
     avatar_data->profile_url = getProfileURL(agent_id.asString());
+    avatar_data->customer_type = result["customer_type"].asString();
 
     avatar_data->flags = 0;
 
@@ -758,6 +759,8 @@ void LLPanelProfileSecondLife::resetData()
     mCantEditObjectsIcon->setEnabled(false);
 
     childSetVisible("partner_layout", FALSE);
+    childSetVisible("badge_layout", FALSE);
+    childSetVisible("partner_spacer_layout", TRUE);
 }
 
 void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data)
@@ -965,6 +968,73 @@ void LLPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data
 
     std::string caption_text = getString("CaptionTextAcctInfo", args);
     getChild<LLUICtrl>("account_info")->setValue(caption_text);
+
+    const S32 LINDEN_EMPLOYEE_INDEX = 3;
+    LLDate sl_release;
+    sl_release.fromYMDHMS(2003, 6, 23, 0, 0, 0);
+    std::string customer_lower = avatar_data->customer_type;
+    LLStringUtil::toLower(customer_lower);
+    if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX)
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Linden");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeLinden"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (avatar_data->born_on < sl_release)
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Beta");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeBeta"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "beta_lifetime")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Beta_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeBetaLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "lifetime")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "secondlifetime_premium")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Premium_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "secondlifetime_premium_plus")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Pplus_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumPlusLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "monthly" || customer_lower == "quarterly" || customer_lower == "annual")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("AccountLevel_Premium");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremium"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower.find("premium_plus") != std::string::npos)
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("AccountLevel_Plus");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumPlus"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else
+    {
+        childSetVisible("badge_layout", FALSE);
+        childSetVisible("partner_spacer_layout", TRUE);
+    }
 }
 
 void LLPanelProfileSecondLife::fillRightsData()
@@ -1119,7 +1189,7 @@ void LLPanelProfileSecondLife::updateOnlineStatus()
     }
     else
     {
-        childSetVisible("frind_layout", false);
+        childSetVisible("friend_layout", false);
         childSetVisible("online_layout", false);
         childSetVisible("offline_layout", false);
     }
@@ -1127,7 +1197,7 @@ void LLPanelProfileSecondLife::updateOnlineStatus()
 
 void LLPanelProfileSecondLife::processOnlineStatus(bool is_friend, bool show_online, bool online)
 {
-    childSetVisible("frind_layout", is_friend);
+    childSetVisible("friend_layout", is_friend);
     childSetVisible("online_layout", online && show_online);
     childSetVisible("offline_layout", !online && show_online);
 }
diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp
index 8a6f3f77742f2f6267f0bde68b447ffe3849731a..1623884af4b337468a0409b1127e3179d05d69d1 100644
--- a/indra/newview/llpanelprofilepicks.cpp
+++ b/indra/newview/llpanelprofilepicks.cpp
@@ -539,6 +539,7 @@ void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id)
             pick_name = parcel->getName();
             pick_desc = parcel->getDesc();
             snapshot_id = parcel->getSnapshotID();
+            mPickDescription->setParseHTML(false);
         }
 
         LLViewerRegion* region = gAgent.getRegion();
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index 64bdc473bd9520c9415d896f811cff75ada3a38b..042ff74b6ad16714899449f6f9dab2611b9f9d2a 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -598,7 +598,7 @@ void LLPanelWearing::onRemoveAttachment()
 	{
 		LLSelectMgr::getInstance()->deselectAll();
 		LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]);
-		LLSelectMgr::getInstance()->sendDropAttachment();
+		LLSelectMgr::getInstance()->sendDetach();
 	}
 }
 
diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp
index de247592ab8ea9f812a0c75f6ffd527325102a10..da08aa87a8b7c93190136d695780a7f53fce5fe3 100644
--- a/indra/newview/llscripteditor.cpp
+++ b/indra/newview/llscripteditor.cpp
@@ -194,7 +194,7 @@ void LLScriptEditor::drawSelectionBackground()
 	{
 		highlight_list_t highlights;
 		highlights.push_back(range_pair_t(llmin(mSelectionStart, mSelectionEnd), llmax(mSelectionStart, mSelectionEnd)));
-        std::vector<LLRect> selection_rects = getSelctionRects(highlights);
+        std::vector<LLRect> selection_rects = getSelectionRects(highlights);
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		const LLColor4& color = mReadOnly ? mReadOnlyFgColor : mFgColor;
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 73d638deed02241317f0a248b7f85beb794e88ac..8166d44f5597da470dc2b54ba6f4ecebcd5edf9a 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1454,8 +1454,16 @@ bool idle_startup()
 		}
         else if (regionp->capabilitiesError())
         {
-            // Try to connect despite capabilities' error state
-            LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+            LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL;
+            if (gRememberPassword)
+            {
+                LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
+            }
+            else
+            {
+                LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status);
+            }
+            reset_login();
         }
 		else
 		{
@@ -1975,6 +1983,7 @@ bool idle_startup()
 			LLNotificationsUtil::add("InventoryUnusable");
 		}
 		
+        LLInventoryModelBackgroundFetch::instance().start();
 		gInventory.createCommonSystemCategories();
 
 		// It's debatable whether this flag is a good idea - sets all
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 1ff165eee45c97eb80874565e06423b4feface46..f5b06c59fe7662f4e97ead8624cb251dcbeb00ca 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1102,12 +1102,16 @@ void LLToolDragAndDrop::dropMaterialOneFace(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureOneFace no material item." << LL_ENDL;
         return;
     }
+
+    // SL-20013 must save asset_id before handleDropMaterialProtections since our item instance
+    // may be deleted if it is moved into task inventory
+    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
     if (!success)
     {
         return;
     }
-    LLUUID asset_id = item->getAssetUUID();
+
     if (asset_id.isNull())
     {
         // use blank material
@@ -1133,13 +1137,17 @@ void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureAllFaces no material item." << LL_ENDL;
         return;
     }
+
+    // SL-20013 must save asset_id before handleDropMaterialProtections since our item instance
+    // may be deleted if it is moved into task inventory
+    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
+
     if (!success)
     {
         return;
     }
 
-    LLUUID asset_id = item->getAssetUUID();
     if (asset_id.isNull())
     {
         // use blank material
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 84601da4c1d1d37176fb5482ead58352f4991355..3916a69808010d02431da7528cac1e9fb3eec621 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -41,8 +41,8 @@
 
 #include <nlohmann/json.hpp>
 
-static const std::string BING_NOTRANSLATE_OPENING_TAG("<div class=\"notranslate\">");
-static const std::string BING_NOTRANSLATE_CLOSING_TAG("</div>");
+static const std::string AZURE_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">");
+static const std::string AZURE_NOTRANSLATE_CLOSING_TAG("</div>");
 
 /**
 * Handler of an HTTP machine translation service.
@@ -80,7 +80,18 @@ class LLTranslationAPIHandler
     * @param[in]  key  Key to verify.
     */
     virtual std::string getKeyVerificationURL(
-        const std::string &key) const = 0;
+        const LLSD &key) const = 0;
+
+    /**
+    * Check API verification response.
+    *
+    * @param[out] bool  true if valid.
+    * @param[in]  response
+    * @param[in]  status
+    */
+    virtual bool checkVerificationResponse(
+        const LLSD &response,
+        int status) const = 0;
 
     /**
     * Parse translation response.
@@ -92,6 +103,7 @@ class LLTranslationAPIHandler
     * @param[out]    err_msg       Error message (in case of error).
     */
     virtual bool parseResponse(
+        const LLSD& http_response,
         int& status,
         const std::string& body,
         std::string& translation,
@@ -105,14 +117,30 @@ class LLTranslationAPIHandler
 
     virtual LLTranslate::EService getCurrentService() = 0;
 
-    virtual void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) = 0;
+    virtual void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) = 0;
     virtual void translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
 
 
     virtual ~LLTranslationAPIHandler() {}
 
-    void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc);
+    void verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc);
     void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
+
+    virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const = 0;
+    virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const = 0;
+    virtual LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                                       LLCore::HttpRequest::ptr_t request,
+                                       LLCore::HttpOptions::ptr_t options,
+                                       LLCore::HttpHeaders::ptr_t headers,
+                                       const std::string & url,
+                                       const std::string & msg,
+                                       const std::string& from_lang,
+                                       const std::string& to_lang) const = 0;
+    virtual LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url) const = 0;
 };
 
 void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure)
@@ -122,8 +150,7 @@ void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::strin
 
 }
 
-
-void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc)
+void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc)
 {
     LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
     LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
@@ -140,8 +167,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::
         LLVersionInfo::instance().getPatch(),
         LLVersionInfo::instance().getBuild());
 
-    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
-    httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+    initHttpHeader(httpHeaders, user_agent, key);
 
     httpOpts->setFollowRedirects(true);
     httpOpts->setSSLVerifyPeer(false);
@@ -153,17 +179,29 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::
         return;
     }
 
-    LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+    std::string::size_type delim_pos = url.find("://");
+    if (delim_pos == std::string::npos)
+    {
+        LL_INFOS("Translate") << "URL is missing a scheme" << LL_ENDL;
+        return;
+    }
+
+    LLSD result = verifyAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url);
 
     LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
     LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
 
     bool bOk = true;
-    if (!status)
+    int parseResult = status.getType();
+    if (!checkVerificationResponse(httpResults, parseResult))
+    {
         bOk = false;
+    }
 
     if (!fnc.empty())
-        fnc(service, bOk);
+    {
+        fnc(service, bOk, parseResult);
+    }
 }
 
 void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::string msg,
@@ -184,8 +222,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         LLVersionInfo::instance().getPatch(),
         LLVersionInfo::instance().getBuild());
 
-    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
-    httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+    initHttpHeader(httpHeaders, user_agent);
     httpOpts->setSSLVerifyPeer(false);
 
     std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg);
@@ -195,7 +232,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         return;
     }
 
-    LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+    LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg, fromTo.first, fromTo.second);
 
     if (LLApp::isQuitting())
     {
@@ -216,7 +253,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
 
     try
     {
-        res = this->parseResponse(parseResult, body, translation, detected_lang, err_msg);
+        res = this->parseResponse(httpResults, parseResult, body, translation, detected_lang, err_msg);
     }
     catch (std::out_of_range&)
     {
@@ -242,6 +279,11 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
     }
     else
     {
+        if (err_msg.empty() && httpResults.has("error_body"))
+        {
+            err_msg = httpResults["error_body"].asString();
+        }
+
         if (err_msg.empty())
         {
             err_msg = LLTrans::getString("TranslationResponseParseError");
@@ -262,23 +304,44 @@ class LLGoogleTranslationHandler : public LLTranslationAPIHandler
     LOG_CLASS(LLGoogleTranslationHandler);
 
 public:
-    /*virtual*/ std::string getTranslateURL(
+    std::string getTranslateURL(
         const std::string &from_lang,
         const std::string &to_lang,
-        const std::string &text) const;
-    /*virtual*/ std::string getKeyVerificationURL(
-        const std::string &key) const;
-    /*virtual*/ bool parseResponse(
+        const std::string &text) const override;
+    std::string getKeyVerificationURL(
+        const LLSD &key) const override;
+    bool checkVerificationResponse(
+        const LLSD &response,
+        int status) const override;
+    bool parseResponse(
+        const LLSD& http_response,
         int& status,
         const std::string& body,
         std::string& translation,
         std::string& detected_lang,
-        std::string& err_msg) const;
-    /*virtual*/ bool isConfigured() const;
-
-    /*virtual*/ LLTranslate::EService getCurrentService() { return LLTranslate::EService::SERVICE_GOOGLE; }
-
-    /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+        std::string& err_msg) const override;
+    bool isConfigured() const override;
+
+    LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_GOOGLE; }
+
+    void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override;
+
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override;
+    LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url,
+        const std::string & msg,
+        const std::string& from_lang,
+        const std::string& to_lang) const override;
+
+    LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url) const override;
 
 private:
     static void parseErrorResponse(
@@ -311,15 +374,24 @@ std::string LLGoogleTranslationHandler::getTranslateURL(
 
 // virtual
 std::string LLGoogleTranslationHandler::getKeyVerificationURL(
-	const std::string& key) const
+	const LLSD& key) const
 {
-	std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
-		+ key + "&target=en";
+    std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
+        + key.asString() +"&target=en";
     return url;
 }
 
+//virtual
+bool LLGoogleTranslationHandler::checkVerificationResponse(
+    const LLSD &response,
+    int status) const
+{
+    return status == HTTP_OK;
+}
+
 // virtual
 bool LLGoogleTranslationHandler::parseResponse(
+    const LLSD& http_response,
 	int& status,
 	const std::string& body,
 	std::string& translation,
@@ -410,75 +482,199 @@ bool LLGoogleTranslationHandler::parseTranslation(
 // static
 std::string LLGoogleTranslationHandler::getAPIKey()
 {
-	return gSavedSettings.getString("GoogleTranslateAPIKey");
+    static LLCachedControl<std::string> google_key(gSavedSettings, "GoogleTranslateAPIKey");
+	return google_key;
 }
 
 /*virtual*/ 
-void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
+void LLGoogleTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc)
 {
     LLCoros::instance().launch("Google /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
         this, LLTranslate::SERVICE_GOOGLE, key, fnc));
 }
 
+/*virtual*/
+void LLGoogleTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const
+{
+    headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+}
+
+/*virtual*/
+void LLGoogleTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent,
+    const LLSD &key) const
+{
+    headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+}
+
+LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url,
+    const std::string & msg,
+    const std::string& from_lang,
+    const std::string& to_lang) const
+{
+    return adapter->getRawAndSuspend(request, url, options, headers);
+}
+
+LLSD LLGoogleTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url) const
+{
+    return adapter->getAndSuspend(request, url, options, headers);
+}
 
 //=========================================================================
 /// Microsoft Translator v2 API handler.
-class LLBingTranslationHandler : public LLTranslationAPIHandler
+class LLAzureTranslationHandler : public LLTranslationAPIHandler
 {
-    LOG_CLASS(LLBingTranslationHandler);
+    LOG_CLASS(LLAzureTranslationHandler);
 
 public:
-    /*virtual*/ std::string getTranslateURL(
+    std::string getTranslateURL(
         const std::string &from_lang,
         const std::string &to_lang,
-        const std::string &text) const;
-    /*virtual*/ std::string getKeyVerificationURL(
-        const std::string &key) const;
-    /*virtual*/ bool parseResponse(
+        const std::string &text) const override;
+    std::string getKeyVerificationURL(
+        const LLSD &key) const override;
+    bool checkVerificationResponse(
+        const LLSD &response,
+        int status) const override;
+    bool parseResponse(
+        const LLSD& http_response,
         int& status,
         const std::string& body,
         std::string& translation,
         std::string& detected_lang,
-        std::string& err_msg) const;
-    /*virtual*/ bool isConfigured() const;
-
-    /*virtual*/ LLTranslate::EService getCurrentService() { return LLTranslate::EService::SERVICE_BING; }
-
-    /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+        std::string& err_msg) const override;
+    bool isConfigured() const override;
+
+    LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_AZURE; }
+
+    void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override;
+
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override;
+    LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url,
+        const std::string & msg,
+        const std::string& from_lang,
+        const std::string& to_lang) const override;
+
+    LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url) const override;
 private:
-    static std::string getAPIKey();
+    static std::string parseErrorResponse(
+        const std::string& body);
+    static LLSD getAPIKey();
     static std::string getAPILanguageCode(const std::string& lang);
 
 };
 
 //-------------------------------------------------------------------------
 // virtual
-std::string LLBingTranslationHandler::getTranslateURL(
+std::string LLAzureTranslationHandler::getTranslateURL(
 	const std::string &from_lang,
 	const std::string &to_lang,
 	const std::string &text) const
 {
-	std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
-		+ getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + getAPILanguageCode(to_lang);
-	if (!from_lang.empty())
-	{
-		url += "&from=" + getAPILanguageCode(from_lang);
-	}
+    std::string url;
+    LLSD key = getAPIKey();
+    if (key.isMap())
+    {
+        std::string endpoint = key["endpoint"].asString();
+
+        if (*endpoint.rbegin() != '/')
+        {
+            endpoint += "/";
+        }
+        url = endpoint + std::string("translate?api-version=3.0&to=")
+            + getAPILanguageCode(to_lang);
+    }
     return url;
 }
 
 
 // virtual
-std::string LLBingTranslationHandler::getKeyVerificationURL(
-	const std::string& key) const
+std::string LLAzureTranslationHandler::getKeyVerificationURL(
+	const LLSD& key) const
 {
-	std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
-		+ key;
+    std::string url;
+    if (key.isMap())
+    {
+        std::string endpoint = key["endpoint"].asString();
+        if (*endpoint.rbegin() != '/')
+        {
+            endpoint += "/";
+        }
+        url = endpoint + std::string("translate?api-version=3.0&to=en");
+    }
     return url;
 }
 
+//virtual
+bool LLAzureTranslationHandler::checkVerificationResponse(
+    const LLSD &response,
+    int status) const
+{
+    if (status == HTTP_UNAUTHORIZED)
+    {
+        LL_DEBUGS("Translate") << "Key unathorised" << LL_ENDL;
+        return false;
+    }
+
+    if (status == HTTP_NOT_FOUND)
+    {
+        LL_DEBUGS("Translate") << "Either endpoint doesn't have requested resource" << LL_ENDL;
+        return false;
+    }
+
+    if (status != HTTP_BAD_REQUEST)
+    {
+        LL_DEBUGS("Translate") << "Unexpected error code" << LL_ENDL;
+        return false;
+    }
+
+    if (!response.has("error_body"))
+    {
+        LL_DEBUGS("Translate") << "Unexpected response, no error returned" << LL_ENDL;
+        return false;
+    }
+
+    // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}"
+    // But for now just verify response is a valid json
+
+	std::stringstream stream(response["error_body"].asString());
+	nlohmann::json root;
+    try
+    {
+		stream >> root;
+    }
+    catch(nlohmann::json::exception &e)
+	{
+        LL_DEBUGS("Translate") << "Failed to parse error_body:" << e.what() << LL_ENDL;
+		return false;
+	}
+
+    return true;
+}
+
 // virtual
-bool LLBingTranslationHandler::parseResponse(
+bool LLAzureTranslationHandler::parseResponse(
+    const LLSD& http_response,
 	int& status,
 	const std::string& body,
 	std::string& translation,
@@ -487,65 +683,450 @@ bool LLBingTranslationHandler::parseResponse(
 {
 	if (status != HTTP_OK)
 	{
-		static const std::string MSG_BEGIN_MARKER = "Message: ";
-		size_t begin = body.find(MSG_BEGIN_MARKER);
-		if (begin != std::string::npos)
-		{
-			begin += MSG_BEGIN_MARKER.size();
-		}
-		else
-		{
-			begin = 0;
-			err_msg.clear();
-		}
-		size_t end = body.find("</p>", begin);
-		err_msg = body.substr(begin, end-begin);
-		LLStringUtil::replaceString(err_msg, "&#xD;", ""); // strip CR
+        if (http_response.has("error_body"))
+        err_msg = parseErrorResponse(http_response["error_body"].asString());
 		return false;
 	}
 
-	// Sample response: <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hola</string>
-	size_t begin = body.find(">");
-	if (begin == std::string::npos || begin >= (body.size() - 1))
+    //Example:
+    // "[{\"detectedLanguage\":{\"language\":\"en\",\"score\":1.0},\"translations\":[{\"text\":\"Hello, what is your name?\",\"to\":\"en\"}]}]"
+
+	nlohmann::json root;
+    try
+    {
+		root = nlohmann::json::parse(body);
+    }
+    catch(nlohmann::json::exception &e)
 	{
-		begin = 0;
+        err_msg = e.what();
+        return false;
 	}
-	else
+
+    if (!root.is_object() || !root.is_array()) // empty response? should not happen
+    {
+        return false;
+    }
+
+    // Request succeeded, extract translation from the response.
+
+    const nlohmann::json& data = root[0U];
+    if (!data.is_object()
+        || data.find("detectedLanguage") == data.end()
+        || data.find("translations") == data.end())
+    {
+        return false;
+    }
+
+    const nlohmann::json& detectedLanguage = data["detectedLanguage"];
+    if (!detectedLanguage.is_object() || detectedLanguage.find("language") == detectedLanguage.end())
+    {
+        return false;
+    }
+    detected_lang = detectedLanguage["language"].get<std::string>();
+
+    const nlohmann::json& translations = data["translations"];
+    if (!translations.is_array() || translations.size() == 0)
+    {
+        return false;
+    }
+
+    const nlohmann::json& first = translations[0U];
+    if (!first.is_object() || first.find("text") == first.end())
+    {
+        return false;
+    }
+
+    translation = first["text"].get<std::string>();
+
+    return true;
+}
+
+// virtual
+bool LLAzureTranslationHandler::isConfigured() const
+{
+	return getAPIKey().isMap();
+}
+
+//static
+std::string LLAzureTranslationHandler::parseErrorResponse(
+    const std::string& body)
+{
+    // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}"
+    // But for now just verify response is a valid json with an error
+
+	nlohmann::json root;
+    try
+    {
+		root = nlohmann::json::parse(body);
+    }
+    catch(const nlohmann::json::exception&)
 	{
-		++begin;
+        return std::string();
 	}
 
-	size_t end = body.find("</string>", begin);
+    if (!root.is_object() || root.find("error") == root.end())
+    {
+        return std::string();
+    }
 
-	detected_lang.clear(); // unsupported by this API
-	translation = body.substr(begin, end-begin);
-	LLStringUtil::replaceString(translation, "&#xD;", ""); // strip CR
-	return true;
+    const nlohmann::json& error_map = root["error"];
+
+    if (!error_map.is_object() || error_map.find("message") == error_map.end())
+    {
+        return std::string();
+    }
+
+    return error_map["message"].get<std::string>();
 }
 
+// static
+LLSD LLAzureTranslationHandler::getAPIKey()
+{
+    static LLCachedControl<LLSD> azure_key(gSavedSettings, "AzureTranslateAPIKey");
+	return azure_key;
+}
+
+// static
+std::string LLAzureTranslationHandler::getAPILanguageCode(const std::string& lang)
+{
+	return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
+}
+
+/*virtual*/
+void LLAzureTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc)
+{
+    LLCoros::instance().launch("Azure /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, 
+        this, LLTranslate::SERVICE_AZURE, key, fnc));
+}
+/*virtual*/
+void LLAzureTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent) const
+{
+    initHttpHeader(headers, user_agent, getAPIKey());
+}
+
+/*virtual*/
+void LLAzureTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent,
+    const LLSD &key) const
+{
+    headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_JSON);
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+    if (key.has("id"))
+    {
+        // Token based autorization
+        headers->append("Ocp-Apim-Subscription-Key", key["id"].asString());
+    }
+    if (key.has("region"))
+    {
+        // ex: "westeurope"
+        headers->append("Ocp-Apim-Subscription-Region", key["region"].asString());
+    }
+}
+
+LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url,
+    const std::string & msg,
+    const std::string& from_lang,
+    const std::string& to_lang) const
+{
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "[{\"text\":\"";
+    outs << msg;
+    outs << "\"}]";
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
+}
+
+LLSD LLAzureTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url) const
+{
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "[{\"intentionally_invalid_400\"}]";
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
+}
+
+//=========================================================================
+/// DeepL Translator API handler.
+class LLDeepLTranslationHandler: public LLTranslationAPIHandler
+{
+    LOG_CLASS(LLDeepLTranslationHandler);
+
+public:
+    std::string getTranslateURL(
+        const std::string& from_lang,
+        const std::string& to_lang,
+        const std::string& text) const override;
+    std::string getKeyVerificationURL(
+        const LLSD& key) const override;
+    bool checkVerificationResponse(
+        const LLSD& response,
+        int status) const override;
+    bool parseResponse(
+        const LLSD& http_response,
+        int& status,
+        const std::string& body,
+        std::string& translation,
+        std::string& detected_lang,
+        std::string& err_msg) const override;
+    bool isConfigured() const override;
+
+    LLTranslate::EService getCurrentService() override
+    {
+        return LLTranslate::EService::SERVICE_DEEPL;
+    }
+
+    void verifyKey(const LLSD& key, LLTranslate::KeyVerificationResult_fn fnc) override;
+
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD& key) const override;
+    LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                               LLCore::HttpRequest::ptr_t request,
+                               LLCore::HttpOptions::ptr_t options,
+                               LLCore::HttpHeaders::ptr_t headers,
+                               const std::string& url,
+                               const std::string& msg,
+                               const std::string& from_lang,
+                               const std::string& to_lang) const override;
+
+    LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                          LLCore::HttpRequest::ptr_t request,
+                          LLCore::HttpOptions::ptr_t options,
+                          LLCore::HttpHeaders::ptr_t headers,
+                          const std::string& url) const override;
+private:
+    static std::string parseErrorResponse(
+        const std::string& body);
+    static LLSD getAPIKey();
+    static std::string getAPILanguageCode(const std::string& lang);
+};
+
+//-------------------------------------------------------------------------
 // virtual
-bool LLBingTranslationHandler::isConfigured() const
+std::string LLDeepLTranslationHandler::getTranslateURL(
+    const std::string& from_lang,
+    const std::string& to_lang,
+    const std::string& text) const
 {
-	return !getAPIKey().empty();
+    std::string url;
+    LLSD key = getAPIKey();
+    if (key.isMap())
+    {
+        url = key["domain"].asString();
+
+        if (*url.rbegin() != '/')
+        {
+            url += "/";
+        }
+        url += std::string("v2/translate");
+    }
+    return url;
+}
+
+
+// virtual
+std::string LLDeepLTranslationHandler::getKeyVerificationURL(
+    const LLSD& key) const
+{
+    std::string url;
+    if (key.isMap())
+    {
+        url = key["domain"].asString();
+
+        if (*url.rbegin() != '/')
+        {
+            url += "/";
+        }
+        url += std::string("v2/translate");
+    }
+    return url;
+}
+
+//virtual
+bool LLDeepLTranslationHandler::checkVerificationResponse(
+    const LLSD& response,
+    int status) const
+{
+    // Might need to parse body to make sure we got
+    // a valid response and not a message
+    return status == HTTP_OK;
+}
+
+// virtual
+bool LLDeepLTranslationHandler::parseResponse(
+    const LLSD& http_response,
+    int& status,
+    const std::string& body,
+    std::string& translation,
+    std::string& detected_lang,
+    std::string& err_msg) const
+{
+    if (status != HTTP_OK)
+    {
+        if (http_response.has("error_body"))
+            err_msg = parseErrorResponse(http_response["error_body"].asString());
+        return false;
+    }
+
+    //Example:
+    // "{\"translations\":[{\"detected_source_language\":\"EN\",\"text\":\"test\"}]}"
+
+	nlohmann::json root;
+    try
+    {
+		root = nlohmann::json::parse(body);
+    }
+    catch(nlohmann::json::exception &e)
+	{
+        err_msg = e.what();
+        return false;
+	}
+
+    if (!root.is_object()
+        || root.find("translations") == root.end()) // empty response? should not happen
+    {
+        return false;
+    }
+
+    // Request succeeded, extract translation from the response.
+    const nlohmann::json& translations = root["translations"];
+    if (!translations.is_array() || translations.size() == 0)
+    {
+        return false;
+    }
+
+    const nlohmann::json& data= translations[0U];
+    if (!data.is_object()
+        || data.find("detected_source_language") == root.end()
+        || data.find("text") == root.end())
+    {
+        return false;
+    }
+
+    detected_lang = data["detected_source_language"].get<std::string>();
+    LLStringUtil::toLower(detected_lang);
+    translation = data["text"].get<std::string>();
+
+    return true;
+}
+
+// virtual
+bool LLDeepLTranslationHandler::isConfigured() const
+{
+    return getAPIKey().isMap();
+}
+
+//static
+std::string LLDeepLTranslationHandler::parseErrorResponse(
+    const std::string& body)
+{
+    // Example: "{\"message\":\"One of the request inputs is not valid.\"}"
+	nlohmann::json root;
+    try
+    {
+		root = nlohmann::json::parse(body);
+    }
+    catch(const nlohmann::json::exception &)
+	{
+        return {};
+	}
+
+    if (!root.is_object() || root.find("message") == root.end())
+    {
+        return std::string();
+    }
+
+    return root["message"].get<std::string>();
 }
 
 // static
-std::string LLBingTranslationHandler::getAPIKey()
+LLSD LLDeepLTranslationHandler::getAPIKey()
 {
-	return gSavedSettings.getString("BingTranslateAPIKey");
+    static LLCachedControl<LLSD> deepl_key(gSavedSettings, "DeepLTranslateAPIKey");
+    return deepl_key;
 }
 
 // static
-std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang)
+std::string LLDeepLTranslationHandler::getAPILanguageCode(const std::string& lang)
 {
-	return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
+    return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
+}
+
+/*virtual*/
+void LLDeepLTranslationHandler::verifyKey(const LLSD& key, LLTranslate::KeyVerificationResult_fn fnc)
+{
+    LLCoros::instance().launch("DeepL /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
+                                                                this, LLTranslate::SERVICE_DEEPL, key, fnc));
+}
+/*virtual*/
+void LLDeepLTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent) const
+{
+    initHttpHeader(headers, user_agent, getAPIKey());
 }
 
 /*virtual*/
-void LLBingTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
+void LLDeepLTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent,
+    const LLSD& key) const
+{
+    headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded");
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+    if (key.has("id"))
+    {
+        std::string authkey = "DeepL-Auth-Key " + key["id"].asString();
+        headers->append(HTTP_OUT_HEADER_AUTHORIZATION, authkey);
+    }
+}
+
+LLSD LLDeepLTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                                                      LLCore::HttpRequest::ptr_t request,
+                                                      LLCore::HttpOptions::ptr_t options,
+                                                      LLCore::HttpHeaders::ptr_t headers,
+                                                      const std::string& url,
+                                                      const std::string& msg,
+                                                      const std::string& from_lang,
+                                                      const std::string& to_lang) const
 {
-    LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, 
-        this, LLTranslate::SERVICE_BING, key, fnc));
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "text=";
+    std::string escaped_string = LLURI::escape(msg);
+    outs << escaped_string;
+    outs << "&target_lang=";
+    std::string lang = to_lang;
+    LLStringUtil::toUpper(lang);
+    outs << lang;
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
+}
+
+LLSD LLDeepLTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                                                 LLCore::HttpRequest::ptr_t request,
+                                                 LLCore::HttpOptions::ptr_t options,
+                                                 LLCore::HttpHeaders::ptr_t headers,
+                                                 const std::string& url) const
+{
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "text=&target_lang=EN";
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
 }
 
 //=========================================================================
@@ -572,58 +1153,78 @@ void LLTranslate::translateMessage(const std::string &from_lang, const std::stri
 
 std::string LLTranslate::addNoTranslateTags(std::string mesg)
 {
-    if (getPreferredHandler().getCurrentService() != SERVICE_BING)
+    if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE)
+    {
+        return mesg;
+    }
+
+    if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL)
     {
         return mesg;
     }
 
-    std::string upd_msg(mesg);
-    LLUrlMatch match;
-    S32 dif = 0;
-    //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation
-    while (LLUrlRegistry::instance().findUrl(mesg, match))
+    if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
     {
-        upd_msg.insert(dif + match.getStart(), BING_NOTRANSLATE_OPENING_TAG);
-        upd_msg.insert(dif + BING_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, BING_NOTRANSLATE_CLOSING_TAG);
-        mesg.erase(match.getStart(), match.getEnd() - match.getStart());
-        dif += match.getEnd() - match.getStart() + BING_NOTRANSLATE_OPENING_TAG.size() + BING_NOTRANSLATE_CLOSING_TAG.size();
+        // https://learn.microsoft.com/en-us/azure/cognitive-services/translator/prevent-translation
+        std::string upd_msg(mesg);
+        LLUrlMatch match;
+        S32 dif = 0;
+        //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation
+        while (LLUrlRegistry::instance().findUrl(mesg, match))
+        {
+            upd_msg.insert(dif + match.getStart(), AZURE_NOTRANSLATE_OPENING_TAG);
+            upd_msg.insert(dif + AZURE_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, AZURE_NOTRANSLATE_CLOSING_TAG);
+            mesg.erase(match.getStart(), match.getEnd() - match.getStart());
+            dif += match.getEnd() - match.getStart() + AZURE_NOTRANSLATE_OPENING_TAG.size() + AZURE_NOTRANSLATE_CLOSING_TAG.size();
+        }
+        return upd_msg;
     }
-    return upd_msg;
+    return mesg;
 }
 
 std::string LLTranslate::removeNoTranslateTags(std::string mesg)
 {
-    if (getPreferredHandler().getCurrentService() != SERVICE_BING)
+    if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE)
     {
         return mesg;
     }
-    std::string upd_msg(mesg);
-    LLUrlMatch match;
-    S32 opening_tag_size = BING_NOTRANSLATE_OPENING_TAG.size();
-    S32 closing_tag_size = BING_NOTRANSLATE_CLOSING_TAG.size();
-    S32 dif = 0;
-    //remove 'no-translate' tags we added to the links before
-    while (LLUrlRegistry::instance().findUrl(mesg, match))
+    if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL)
     {
-        if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == BING_NOTRANSLATE_OPENING_TAG)
-        {
-            upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size);
-            dif -= opening_tag_size;
+        return mesg;
+    }
 
-            if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == BING_NOTRANSLATE_CLOSING_TAG)
+    if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
+    {
+        std::string upd_msg(mesg);
+        LLUrlMatch match;
+        S32 opening_tag_size = AZURE_NOTRANSLATE_OPENING_TAG.size();
+        S32 closing_tag_size = AZURE_NOTRANSLATE_CLOSING_TAG.size();
+        S32 dif = 0;
+        //remove 'no-translate' tags we added to the links before
+        while (LLUrlRegistry::instance().findUrl(mesg, match))
+        {
+            if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == AZURE_NOTRANSLATE_OPENING_TAG)
             {
-                upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " ");
-                dif -= closing_tag_size - 1;
+                upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size);
+                dif -= opening_tag_size;
+
+                if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == AZURE_NOTRANSLATE_CLOSING_TAG)
+                {
+                    upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " ");
+                    dif -= closing_tag_size - 1;
+                }
             }
+            mesg.erase(match.getStart(), match.getUrl().size());
+            dif += match.getUrl().size();
         }
-        mesg.erase(match.getStart(), match.getUrl().size());
-        dif += match.getUrl().size();
+        return upd_msg;
     }
-    return upd_msg;
+
+    return mesg;
 }
 
 /*static*/
-void LLTranslate::verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc)
+void LLTranslate::verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc)
 {
     LLTranslationAPIHandler& handler = getHandler(service);
 
@@ -689,13 +1290,21 @@ LLSD LLTranslate::asLLSD() const
 // static
 LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
 {
-	EService service = SERVICE_BING;
+	EService service = SERVICE_AZURE;
 
 	std::string service_str = gSavedSettings.getString("TranslationService");
 	if (service_str == "google")
 	{
 		service = SERVICE_GOOGLE;
 	}
+    if (service_str == "azure")
+    {
+        service = SERVICE_AZURE;
+    }
+    if (service_str == "deepl")
+    {
+        service = SERVICE_DEEPL;
+    }
 
 	return getHandler(service);
 }
@@ -704,12 +1313,19 @@ LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
 LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
 {
 	static LLGoogleTranslationHandler google;
-	static LLBingTranslationHandler bing;
+	static LLAzureTranslationHandler azure;
+    static LLDeepLTranslationHandler deepl;
 
-	if (service == SERVICE_GOOGLE)
-	{
-		return google;
-	}
+    switch (service)
+    {
+        case SERVICE_AZURE:
+            return azure;
+        case SERVICE_GOOGLE:
+            return google;
+        case SERVICE_DEEPL:
+            return deepl;
+    }
+
+    return azure;
 
-	return bing;
 }
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 58707e2d3620e1c0f8b59d24be16f2f7a546b9b3..4a5d80737c022542ad02b9be1c913676a2f7dab2 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -59,11 +59,12 @@ class LLTranslate: public LLSingleton<LLTranslate>
 public :
 
 	typedef enum e_service {
-		SERVICE_BING,
+		SERVICE_AZURE,
 		SERVICE_GOOGLE,
+		SERVICE_DEEPL,
 	} EService;
 
-    typedef boost::function<void(EService, bool)> KeyVerificationResult_fn;
+    typedef boost::function<void(EService, bool, S32)> KeyVerificationResult_fn;
     typedef boost::function<void(std::string , std::string )> TranslationSuccess_fn;
     typedef boost::function<void(int, std::string)> TranslationFailure_fn;
 
@@ -78,12 +79,12 @@ public :
     static void translateMessage(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure);
 
     /**
-	 * Verify given API key of a translation service.
-	 *
-	 * @param receiver  Object to pass verification result to.
-	 * @param key       Key to verify.
-	 */
-    static void verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc);
+     * Verify given API key of a translation service.
+     *
+     * @param receiver  Object to pass verification result to.
+     * @param key       Key to verify.
+     */
+    static void verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc);
 
 	/**
 	 * @return translation target language
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 07577992a5d7c904510feb06bee6204948b86b66..efd820c5b4f265370bab98ff0c6d997bb9e4ed13 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1673,7 +1673,8 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 
 BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
 {
-    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
+    bool is_toolmgr_action = false;
+    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down, is_toolmgr_action);
 
     if (clicktype != CLICK_NONE)
     {
@@ -1692,7 +1693,7 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask,
 
         // If the first LMB click is handled by the menu, skip the following double click
         static bool skip_double_click = false;
-        if (clicktype == CLICK_LEFT && down )
+        if (clicktype == CLICK_LEFT && down && !is_toolmgr_action)
         {
             skip_double_click = handled;
         }
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index a20b31b578cfa3ead8e7b2ac58f5ed0ada572e51..5bff3e17ff294db1a7723f14218c139b3105fa12 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -170,7 +170,7 @@ SimMeasurement<>			SIM_TIME_DILATION("simtimedilation", "Simulator time scale",
 							SIM_MAIN_AGENTS("simmainagents", "Number of avatars in current region", LL_SIM_STAT_NUMAGENTMAIN),
 							SIM_CHILD_AGENTS("simchildagents", "Number of avatars in neighboring regions", LL_SIM_STAT_NUMAGENTCHILD),
 							SIM_OBJECTS("simobjects", "", LL_SIM_STAT_NUMTASKS),
-							SIM_ACTIVE_OBJECTS("simactiveobjects", "Number of scripted and/or mocing objects", LL_SIM_STAT_NUMTASKSACTIVE),
+							SIM_ACTIVE_OBJECTS("simactiveobjects", "Number of scripted and/or moving objects", LL_SIM_STAT_NUMTASKSACTIVE),
 							SIM_ACTIVE_SCRIPTS("simactivescripts", "Number of scripted objects", LL_SIM_STAT_NUMSCRIPTSACTIVE),
 							SIM_IN_PACKETS_PER_SEC("siminpps", "", LL_SIM_STAT_INPPS),
 							SIM_OUT_PACKETS_PER_SEC("simoutpps", "", LL_SIM_STAT_OUTPPS),
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 0783497d9b013d4d21fffd8e380c26fcc2616dd9..d47dd8ca29b4c52fd5ec92190e7fefd9e626555d 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -232,6 +232,8 @@ void LLViewerTextureList::doPrefetchImages()
 
     LLViewerTextureManager::getFetchedTexture(IMG_SHOT);
     LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF);
+    LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
+    LLViewerFetchedTexture::sSmokeImagep->setNoDelete();
 
     LLStandardBumpmap::addstandard();
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 2b494df9fb134d1ac390acc075eabd10eed66d97..cf4a51b292c9f9cbfed6d56f4598bbad15f774a1 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1061,7 +1061,7 @@ void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
     }
 }
 
-BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
+BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down, bool& is_toolmgr_action)
 {
 	const char* buttonname = "";
 	const char* buttonstatestr = "";
@@ -1223,6 +1223,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 			LLViewerEventRecorder::instance().clear_xui(); 
 		}
 #endif
+        is_toolmgr_action = true;
 		return TRUE;
 	}
 
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 7f8107d81564c67a38d3308ee4317fe64b6340bc..6bd2c6a6eae85f142369e5136dbbf32977e27fca 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -180,7 +180,7 @@ class LLViewerWindow final : public LLWindowCallbacks
 
     void            reshapeStatusBarContainer();
 
-	BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
+	BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down, bool &is_toolmgr_action);
 
 	//
 	// LLWindowCallback interface implementation
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index bde67d6e03887f2d2d57eb73953cb230102ceeb0..3b04122393d40d335d8f8f5a2365f561d7dea389 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -276,13 +276,13 @@ static void killGateway()
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 bool LLVivoxVoiceClient::sShuttingDown = false;
+bool LLVivoxVoiceClient::sConnected = false;
+LLPumpIO *LLVivoxVoiceClient::sPump = nullptr;
 
 LLVivoxVoiceClient::LLVivoxVoiceClient() :
 	mSessionTerminateRequested(false),
 	mRelogRequested(false),
-	mConnected(false),
 	mTerminateDaemon(false),
-	mPump(NULL),
 	mSpatialJoiningNum(0),
 
 	mTuningMode(false),
@@ -351,7 +351,11 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() :
 	mIsProcessingChannels(false),
 	mIsCoroutineActive(false),
 	mVivoxPump("vivoxClientPump")
-{	
+{
+    sShuttingDown = false;
+    sConnected = false;
+    sPump = nullptr;
+
 	mSpeakerVolume = scale_speaker_volume(0);
 
 	mVoiceVersion.serverVersion = "";
@@ -397,7 +401,7 @@ LLVivoxVoiceClient::~LLVivoxVoiceClient()
 void LLVivoxVoiceClient::init(LLPumpIO *pump)
 {
 	// constructor will set up LLVoiceClient::getInstance()
-	mPump = pump;
+	sPump = pump;
 
 //     LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
 //         boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
@@ -418,10 +422,10 @@ void LLVivoxVoiceClient::terminate()
         logoutOfVivox(false);
     }
     
-	if(mConnected)
+	if(sConnected)
 	{
         breakVoiceConnection(false);
-		mConnected = false;
+        sConnected = false;
 	}
 	else
 	{
@@ -430,7 +434,7 @@ void LLVivoxVoiceClient::terminate()
 	}
 
     sShuttingDown = true;
-    mPump = NULL;
+    sPump = NULL;
 }
 
 //---------------------------------------------------
@@ -476,7 +480,7 @@ bool LLVivoxVoiceClient::writeString(const std::string &str)
 	bool result = false;
     LL_DEBUGS("LowVoice") << "sending:\n" << str << LL_ENDL;
 
-	if(mConnected)
+	if(sConnected)
 	{
 		apr_status_t err;
 		apr_size_t size = (apr_size_t)str.size();
@@ -1113,7 +1117,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
 
     int retryCount(0);
     LLVoiceVivoxStats::getInstance()->reset();
-    while (!mConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX)
+    while (!sConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX)
     {
         LLVoiceVivoxStats::getInstance()->connectionAttemptStart();
         LL_DEBUGS("Voice") << "Attempting to connect to vivox daemon: " << mDaemonHost << LL_ENDL;
@@ -1123,23 +1127,23 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
             mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
         }
 
-        mConnected = mSocket->blockingConnect(mDaemonHost);
-        LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(mConnected);
-        if (!mConnected)
+        sConnected = mSocket->blockingConnect(mDaemonHost);
+        LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(sConnected);
+        if (!sConnected)
         {
             llcoro::suspendUntilTimeout(DAEMON_CONNECT_THROTTLE_SECONDS);
         }
     }
     
     //---------------------------------------------------------------------
-    if (sShuttingDown && !mConnected)
+    if (sShuttingDown && !sConnected)
     {
         return false;
     }
 
     llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
 
-    while (!mPump && !sShuttingDown)
+    while (!sPump && !sShuttingDown)
     {   // Can't use the pump until we have it available.
         llcoro::suspend();
     }
@@ -1161,7 +1165,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
     readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser()));
 
 
-    mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
+    sPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
 
 
     //---------------------------------------------------------------------
@@ -1383,9 +1387,9 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait)
             // the message, yet we need to receive "connector shutdown response".
             // Either wait a bit and emulate it or check gMessageSystem for specific message
             _sleep(1000);
-            if (mConnected)
+            if (sConnected)
             {
-                mConnected = false;
+                sConnected = false;
                 LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
                 mVivoxPump.post(vivoxevent);
             }
@@ -1397,7 +1401,7 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait)
     LL_DEBUGS("Voice") << "closing SLVoice socket" << LL_ENDL;
     closeSocket();		// Need to do this now -- bad things happen if the destructor does it later.
     cleanUp();
-    mConnected = false;
+    sConnected = false;
 
     return retval;
 }
@@ -2576,7 +2580,7 @@ bool LLVivoxVoiceClient::performMicTuning()
 void LLVivoxVoiceClient::closeSocket(void)
 {
 	mSocket.reset();
-	mConnected = false;
+    sConnected = false;
 	mConnectorEstablished = false;
 	mAccountLoggedIn = false;
 }
@@ -3084,7 +3088,7 @@ bool LLVivoxVoiceClient::deviceSettingsAvailable()
 {
 	bool result = true;
 	
-	if(!mConnected)
+	if(!sConnected)
 		result = false;
 	
 	if(mRenderDevices.empty())
@@ -3904,7 +3908,7 @@ void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string &
 		// Should this ever fail?  do we care if it does?
 	}
 	
-	mConnected = false;
+	sConnected = false;
 	mShutdownComplete = true;
 	
     LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
@@ -7486,7 +7490,7 @@ LLIOPipe::EStatus LLVivoxProtocolParser::process_impl(
 	LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL;
 #endif
 	
-	if(!LLVivoxVoiceClient::getInstance()->mConnected)
+	if(!LLVivoxVoiceClient::sConnected)
 	{
 		// If voice has been disabled, we just want to close the socket.  This does so.
 		LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL;
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 7b4c71bedae6a46924a6aa5c7b0e84ab49fcaec9..e635ef3889a79a6336c06c84df378e059d97b79e 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -672,12 +672,10 @@ class LLVivoxVoiceClient final : public LLSingleton<LLVivoxVoiceClient>,
 	
 	LLHost mDaemonHost;
 	LLSocket::ptr_t mSocket;
-	bool mConnected;
 	
 	// We should kill the voice daemon in case of connection alert 
 	bool mTerminateDaemon;
 	
-	LLPumpIO *mPump;
 	friend class LLVivoxProtocolParser;
 	
 	std::string mAccountName;
@@ -922,7 +920,10 @@ class LLVivoxVoiceClient final : public LLSingleton<LLVivoxVoiceClient>,
     bool    mIsProcessingChannels;
     bool    mIsCoroutineActive;
 
-    static bool sShuttingDown; // corutines can last longer than vivox so we need a static variable as a shutdown flag
+    // This variables can last longer than vivox in coroutines so we need them as static
+    static bool sShuttingDown;
+    static bool sConnected;
+    static LLPumpIO* sPump;
 
     LLEventMailDrop mVivoxPump;
 };
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index cca0c75c3ff023180fef816d7fdb5bb67e2f4d6f..18a6c2f06777c6a93878fa7dc51c41326d5e6c0f 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5338,13 +5338,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 
 	if (mat)
 	{
+		BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) || (facep->getTextureEntry()->getColor().mV[3] < 0.999f) ? TRUE : FALSE;
 		if (type == LLRenderPass::PASS_ALPHA)
 		{
-			shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND);
+			shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND, is_alpha);
 		}
 		else
 		{
-			shader_mask = mat->getShaderMask();
+			shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT, is_alpha);
 		}
 	}
 
@@ -5833,15 +5834,20 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						}
 						else
 						{
-                            if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f)
-                            { //only treat as alpha in the pipeline if < 100% transparent
-                                drawablep->setState(LLDrawable::HAS_ALPHA);
-                                add_face(sAlphaFaces, alpha_count, facep);
-                            }
-                            else if (LLDrawPoolAlpha::sShowDebugAlpha)
-                            {
-                                add_face(sAlphaFaces, alpha_count, facep);
-                            }
+							if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f)
+							{ //only treat as alpha in the pipeline if < 100% transparent
+								drawablep->setState(LLDrawable::HAS_ALPHA);
+								add_face(sAlphaFaces, alpha_count, facep);
+							}
+							else if (LLDrawPoolAlpha::sShowDebugAlpha ||
+								(gPipeline.sRenderHighlight && !drawablep->getParent() &&
+								//only root objects are highlighted with red color in this case
+								drawablep->getVObj() && drawablep->getVObj()->flagScripted() &&
+								(LLPipeline::getRenderScriptedBeacons() ||
+								(LLPipeline::getRenderScriptedTouchBeacons() && drawablep->getVObj()->flagHandleTouch()))))
+							{ //draw the transparent face for debugging purposes using a custom texture
+								add_face(sAlphaFaces, alpha_count, facep);
+							}
 						}
 					}
 					else
@@ -6595,7 +6601,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
                     { // HACK - this should never happen, but sometimes we get a material that thinks it has alpha blending when it ought not
                         alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
                     }
-					U32 mask = mat->getShaderMask(alpha_mode);
+                    U32 mask = mat->getShaderMask(alpha_mode, is_alpha);
 
                     U32 vb_mask = facep->getVertexBuffer()->getTypeMask();
 
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_beta.png b/indra/newview/skins/default/textures/icons/profile_badge_beta.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c8a723c47f4f0e2cb981a36e90be707d0e53af8
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_beta.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c38e9e2aee25fa181401e38ac6138ac135f9a4e
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png
new file mode 100644
index 0000000000000000000000000000000000000000..475edd080ef5037f7dd43f1b2978d379e9506aff
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_linden.png b/indra/newview/skins/default/textures/icons/profile_badge_linden.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b6ac03e868b7d05a674cb4ccda822833165ed24
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_linden.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png
new file mode 100644
index 0000000000000000000000000000000000000000..42869952020c8a952b5c2d2b18fab9c4fd3aecda
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png
new file mode 100644
index 0000000000000000000000000000000000000000..47e93c4fac777f2b4422a892694d1560ba9248bd
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 348b0cd118e88b7d705b9cea25a1de47624eae44..9372ec897d7715b1b17e7ce0fdb784967bedbfbb 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -535,7 +535,13 @@ with the same filename but different name
   <texture name="Play_Off" file_name="icons/Play_Off.png" preload="false" />
   <texture name="Play_Over" file_name="icons/Play_Over.png" preload="false" />
   <texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" />
-  
+
+  <texture name="Profile_Badge_Beta" file_name="icons/profile_badge_beta.png" preload="true"/>
+  <texture name="Profile_Badge_Beta_Lifetime" file_name="icons/profile_badge_beta_lifetime.png" preload="true"/>
+  <texture name="Profile_Badge_Lifetime" file_name="icons/profile_badge_lifetime.png" preload="true"/>
+  <texture name="Profile_Badge_Linden" file_name="icons/profile_badge_linden.png" preload="true"/>
+  <texture name="Profile_Badge_Pplus_Lifetime" file_name="icons/profile_badge_pplus_lifetime.png" preload="true"/>
+  <texture name="Profile_Badge_Premium_Lifetime" file_name="icons/profile_badge_premium_lifetime.png" preload="true"/>
   <texture name="Profile_Group_Visibility_Off" file_name="icons/profile_group_visibility_eye_off.png" preload="true"/>
   <texture name="Profile_Group_Visibility_Off_Pressed" file_name="icons/profile_group_visibility_eye_off_pressed.png" preload="true"/>
   <texture name="Profile_Group_Visibility_On" file_name="icons/profile_group_visibility_eye_on.png" preload="true"/>
diff --git a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml
index 37efbe654e6a80e69658a94ea1bd4e6f6fab01e8..b757f4eab80863313f1c2ec18c21273b56e055a7 100644
--- a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml
+++ b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml
@@ -414,7 +414,7 @@
         name="frame_stats"
         label="Frame breakdown"
         show_label="true">
-          <stat_bar name="packet_loss"
+          <stat_bar name="scenery_frame_pct"
             label="Scenery"
             orientation="horizontal"
             unit_label=" %"
@@ -422,7 +422,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-          <stat_bar name="packet_loss"
+          <stat_bar name="avatar_frame_pct"
             label="Avatar"
             orientation="horizontal"
             unit_label=" %"
@@ -430,7 +430,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-          <stat_bar name="packet_loss"
+          <stat_bar name="ui_frame_pct"
             label="UI"
             orientation="horizontal"
             unit_label=" %"
@@ -438,7 +438,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-          <stat_bar name="packet_loss"
+          <stat_bar name="huds_frame_pct"
             label="HUDs"
             orientation="horizontal"
             unit_label=" %"
@@ -446,7 +446,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-        <stat_bar name="packet_loss"
+        <stat_bar name="swap_frame_pct"
             label="Swap"
             orientation="horizontal"
             unit_label=" %"
@@ -454,7 +454,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-        <stat_bar name="packet_loss"
+        <stat_bar name="idle_frame_pct"
             label="Tasks"
             orientation="horizontal"
             unit_label=" %"
diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index a212ce78891f66412ca0a2af19aac111f03dfdac..3f3331b468af6cf720fa25f6ca39ff31d63bac2a 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
  legacy_header_height="18"
- height="310"
+ height="470"
  layout="topleft"
  name="floater_translation_settings"
  help_topic="translation_settings"
@@ -9,11 +9,13 @@
  title="CHAT TRANSLATION SETTINGS"
  width="485">
 
- <string name="bing_api_key_not_verified">Bing appID not verified. Please try again.</string>
- <string name="google_api_key_not_verified">Google API key not verified. Please try again.</string>
+ <string name="azure_api_key_not_verified">Azure service identifier not verified. Status: [STATUS]. Please check your settings and try again.</string>
+ <string name="google_api_key_not_verified">Google API key not verified. Status: [STATUS]. Please check your key and try again.</string>
+ <string name="deepl_api_key_not_verified">DeepL Auth Key key not verified. Status: [STATUS]. Please check your key and try again.</string>
 
- <string name="bing_api_key_verified">Bing appID verified.</string>
+ <string name="azure_api_key_verified">Azure service identifier verified.</string>
  <string name="google_api_key_verified">Google API key verified.</string>
+ <string name="deepl_api_key_verified">DeepL API key verified.</string>
 
  <check_box
   height="16"     
@@ -128,25 +130,86 @@
 
  <radio_group
   follows="top|left"
-  height="80"
+  height="260"
   layout="topleft"
   left_delta="10"
   name="translation_service_rg"
   top_pad="20"
   width="320">
   <radio_item
-   initial_value="bing"
-   label="Bing Translator"
+   initial_value="azure"
+   label="Azure Translator"
    layout="topleft"
-   name="bing" />
+   name="azure" />
   <radio_item
    initial_value="google"
    label="Google Translate"
    layout="topleft"
    name="google"
-   top_pad="55" />
+   top_pad="115" />
+  <radio_item
+   initial_value="deepl"
+   label="DeepL Translator"
+   layout="topleft"
+   name="deepl"
+   top_pad="61" />
  </radio_group>
 
+  <text
+   follows="top|right"
+   height="20"
+   layout="topleft"
+   left="185"
+   length="1"
+   name="google_links_text"
+   top_pad="-262"
+   type="string"
+   width="100">
+    [https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Setup]
+  </text>
+
+  <text
+   type="string"
+   length="1"
+   follows="top|right"
+   height="20"
+   layout="topleft"
+   left="70"
+   name="azure_api_endoint_label"
+   top_pad="8"
+   width="85">
+    Endpoint:
+  </text>
+  
+ <combo_box
+   allow_text_entry="true"
+   follows="left|top"
+   name="azure_api_endpoint_combo"
+   height="23"
+   left_pad="10"
+   right="-10"
+   top_delta="-4"
+   max_chars="512"
+   value="https://api.cognitive.microsofttranslator.com"
+   combo_button.scale_image="true">
+   <combo_box.item
+     label="https://api.cognitive.microsofttranslator.com"
+     name="global"
+     value="https://api.cognitive.microsofttranslator.com" />
+   <combo_box.item
+     label="https://api-apc.cognitive.microsofttranslator.com"
+     name="api-apc"
+     value="https://api-apc.cognitive.microsofttranslator.com" />
+   <combo_box.item
+     label="https://api-eur.cognitive.microsofttranslator.com"
+     name="api-eur"
+     value="https://api-eur.cognitive.microsofttranslator.com" />
+   <combo_box.item
+     label="https://api-nam.cognitive.microsofttranslator.com"
+     name="api-nam"
+     value="https://api-nam.cognitive.microsofttranslator.com" />
+  </combo_box>
+
  <text
   type="string"
   length="1"
@@ -154,30 +217,52 @@
   height="20"
   layout="topleft"
   left="70"
-  name="bing_api_key_label"
-  top_pad="-55"
+  name="azure_api_key_label"
+  top_pad="10"
   width="85">
-  Bing [http://www.bing.com/developers/createapp.aspx AppID]:
+  Azure Key:
   </text>
  <line_editor
-  default_text="Enter Bing AppID and click &quot;Verify&quot;"
+  default_text="Enter Translator Key and click &quot;Verify&quot;"
   follows="top|left"
   height="20"
   layout="topleft"
   left_pad="10"
   max_length_chars="50"
   top_delta="-4"
-  name="bing_api_key"
+  name="azure_api_key"
   width="210" />
- <button
-  follows="left|top"
-  height="23"
-  label="Verify"
-  layout="topleft"
-  left_pad="10"
-  name="verify_bing_api_key_btn"
-  top_delta="-2"
-  width="90" />	
+  <text
+   type="string"
+   length="1"
+   follows="top|right"
+   height="20"
+   layout="topleft"
+   left="70"
+   name="azure_api_region_label"
+   top_pad="11"
+   width="85">
+    Region:
+  </text>
+  <line_editor
+   default_text="Can be left empty for global services"
+   follows="top|left"
+   height="20"
+   layout="topleft"
+   left_pad="10"
+   max_length_chars="50"
+   top_delta="-4"
+   name="azure_api_region"
+   width="210" />
+  <button
+   follows="left|top"
+   height="23"
+   label="Verify"
+   layout="topleft"
+   left_pad="10"
+   name="verify_azure_api_key_btn"
+   top_delta="-2"
+   width="90" />
 
  <text
   follows="top|right"
@@ -186,7 +271,7 @@
   left="70"
   length="1"
   name="google_api_key_label"
-  top_pad="50"
+  top_pad="53"
   type="string"
   width="85">
   Google [http://code.google.com/apis/language/translate/v2/getting_started.html#auth API key]:
@@ -209,7 +294,7 @@
   left_pad="10"
   name="verify_google_api_key_btn"
   top_delta="-2"
-  width="90" />	
+  width="90" />
 
  <text
   follows="top|right"
@@ -224,6 +309,87 @@
   [http://code.google.com/apis/language/translate/v2/pricing.html Pricing] | [https://code.google.com/apis/console Stats] 
  </text>
 
+    <text
+     type="string"
+     length="1"
+     follows="top|right"
+     height="20"
+     layout="topleft"
+     left="70"
+     name="deepl_api_domain_label"
+     top_pad="80"
+     width="85">
+        Endpoint:
+    </text>
+
+    <combo_box
+      allow_text_entry="false"
+      follows="left|top"
+      name="deepl_api_domain_combo"
+      height="23"
+      left_pad="10"
+      width="140"
+      top_delta="-4"
+      max_chars="512"
+      value="https://api-free.deepl.com"
+      combo_button.scale_image="true">
+        <combo_box.item
+          label="DeepL Free"
+          name="global"
+          value="https://api-free.deepl.com" />
+        <combo_box.item
+          label="DeepL Pro"
+          name="api-apc"
+          value="https://api.deepl.com" />
+    </combo_box>
+    
+    <text
+     follows="top|right"
+     height="20"
+     layout="topleft"
+     left="70"
+     length="1"
+     name="deepl_api_key_label"
+     top_pad="11"
+     type="string"
+     width="85">
+      DeepL API key:
+    </text>
+
+    <line_editor
+     default_text="Enter DeepL API key and click &quot;Verify&quot;"
+     follows="top|left"
+     height="20"
+     layout="topleft"
+     left_pad="10"
+     max_length_chars="50"
+     top_delta="-4"
+     name="deepl_api_key"
+     width="210" />
+    
+    <button
+     follows="left|top"
+     height="23"
+     label="Verify"
+     layout="topleft"
+     left_pad="10"
+     name="verify_deepl_api_key_btn"
+     top_delta="-2"
+     width="90" />
+
+    <text
+     follows="top|right"
+     height="20"
+     layout="topleft"
+     left="185"
+     length="1"
+     name="deepl_links_text"
+     top_delta="-53"
+     type="string"
+     width="100">
+        [https://www.deepl.com/pro/select-country?cta=header-prices Pricing]
+    </text>
+
  <button
   follows="left|top"
   height="23"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 53a0bc4515617690adbcd770177347e9b794067f..7b833e2cf1a0b252e510b9d450b7f0b11a9216c1 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -192,7 +192,7 @@ No tutorial is currently available.
    icon="alertmodal.tga"
    name="BadInstallation"
    type="alertmodal">
- An error occurred while updating [APP_NAME].  Please [https://www.alchemyviewer.org/pages/downloads.html download the latest version] of the Viewer.
+ An error occurred while updating [APP_NAME].  Please [https://www.alchemyviewer.org/downloads download the latest version] of the Viewer.
     <tag>fail</tag>
     <usetemplate
      name="okbutton"
@@ -4322,7 +4322,7 @@ Finished download of raw terrain file to:
    name="RequiredUpdate"
    type="alertmodal">
 Version [VERSION] is required for login.
-Please download from https://www.alchemyviewer.org/pages/downloads.html
+Please download from https://www.alchemyviewer.org/downloads
     <tag>confirm</tag>
     <usetemplate
      name="okbutton"
@@ -6517,6 +6517,14 @@ Your trash is overflowing. This may cause problems logging in.
          yestext="Check trash folder"/>
   </notification>
 
+  <notification
+   icon="notifytip.tga"
+   name="InventoryLimitReachedAIS"
+   type="notifytip">
+Your inventory is experiencing issues. Please, contact support.
+  <tag>fail</tag>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="ConfirmClearBrowserCache"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
index 777b37d66675dcae63d5b23bd6906c3a43574810..cb6c1aec4d50a0e9830fde2008c57ffffd197c20 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
@@ -27,7 +27,33 @@
 Account: [ACCTTYPE]
 [PAYMENTINFO]
     </string>
-
+    
+    <!--Badges-->
+    <string
+     name="BadgeBeta"
+     value="Original Beta Tester" />
+    <string
+     name="BadgeBetaLifetime"
+     value="Beta Lifetime member" />
+    <string
+     name="BadgeLifetime"
+     value="Lifetime member" />
+    <string
+     name="BadgeLinden"
+     value="Linden Lab employee" />
+    <string
+     name="BadgePremiumLifetime"
+     value="Premium lifetime" />
+    <string
+     name="BadgePremiumPlusLifetime"
+     value="Premium Plus lifetime" />
+    <string
+     name="BadgePremium"
+     value="Premium" />
+    <string
+     name="BadgePremiumPlus"
+     value="Premium Plus" />
+	
   <layout_stack
    name="image_stack"
    top="8"
@@ -156,9 +182,39 @@ Account: [ACCTTYPE]
      user_resize="false"
      visible="true">
     </layout_panel>
-    
+
+    <layout_panel
+     name="badge_layout"
+     follows="all"
+     layout="topleft"
+     height="40"
+     auto_resize="false"
+     user_resize="false"
+     visible="false">
+      <icon
+       name="badge_icon"
+       image_name="Beta_Tester"
+       layout="topleft"
+       follows="left|top"
+       top="10"
+       left="5"
+       height="18"
+       width="18"/>
+      <text
+       name="badge_text"
+       value="Badge Tester"
+       top="13"
+       left_pad="3"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"
+       translate="false"
+       visible="true"/>
+    </layout_panel>
+
     <layout_panel
-     name="frind_layout"
+     name="friend_layout"
      follows="all"
      layout="topleft"
      height="16"
@@ -166,7 +222,7 @@ Account: [ACCTTYPE]
      user_resize="false"
      visible="false">
       <text
-       name="frind_text"
+       name="friend_text"
        value="You are friends"
        text_color="ConversationFriendColor"
        top="0"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index eae7dcb5590fc65c8741a2febec9d05299101a53..9df960a5a98a2ef53ee90913ca5217ea5a4dfee3 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -144,10 +144,9 @@ Voice Server Version: [VOICE_VERSION]
 	<string name="AgniGridLabel">Second Life Main Grid (Agni)</string>
 	<string name="AditiGridLabel">Second Life Beta Test Grid (Aditi)</string>
 	
-	<string name="ViewerDownloadURL">https://www.alchemyviewer.org/pages/downloads.html</string>
+	<string name="ViewerDownloadURL">https://www.alchemyviewer.org/downloads</string>
 	<string name="LoginFailedViewerNotPermitted">
-    The viewer you are using can no longer access [CURRENT_GRID]. Please visit the following page to download a new viewer:
-https://www.alchemyviewer.org/pages/downloads.html</string>
+    The viewer you are using can no longer access [CURRENT_GRID]. Please visit the following page to download a new viewer: https://www.alchemyviewer.org/downloads</string>
 	<string name="LoginFailed">"Login process did not complete due to system issues. Try again in a few minutes.
 If you feel this is an error, please contact support.</string>
 	<string name="LoginIntermediateOptionalUpdateAvailable">Optional viewer update available: [VERSION]</string>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
index 13f1f892f99811ab1d462a0656063695d63ab278..e9750a1c2e14690b13310473bdc458ed26e4a8ad 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
@@ -7,7 +7,7 @@
 		<accordion name="wearable_accordion">
 			<accordion_tab name="hair_color_tab" title="Cor"/>
 			<accordion_tab name="hair_style_tab" title="Estilo"/>
-			<accordion_tab name="hair_eyebrows_tab" title="Sombrancelhas"/>
+			<accordion_tab name="hair_eyebrows_tab" title="Sobrancelhas"/>
 			<accordion_tab name="hair_facial_tab" title="Faciais"/>
 		</accordion>
 	</panel>