diff --git a/autobuild.xml b/autobuild.xml
index b47dccde3c70f9855474e02b9ed56dd80a605da4..3a7b3cd23dc43b51300f75f8ee2a9a65cec1546d 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -3194,9 +3194,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c42575ac8997de979eadb082c33a578e</string>
+              <string>b97d0f6570104277de92d0d3f2d1111d</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81322/765512/uriparser-0.9.4-darwin64-559132.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89474/816487/uriparser-0.9.4-darwin64-564957.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3230,9 +3230,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>901b1063556fc6b2575e745eef2bf744</string>
+              <string>e2600c798e220cc98c1cc77341aee00d</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81323/765528/uriparser-0.9.4-windows-559132.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89476/816496/uriparser-0.9.4-windows-564957.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3242,9 +3242,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>962c01d553f286c430102998129fb0d6</string>
+              <string>50d857117d31844fc8b84b07b795fd00</string>
               <key>url</key>
-              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81324/765527/uriparser-0.9.4-windows64-559132.tar.bz2</string>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89475/816497/uriparser-0.9.4-windows64-564957.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 38bdecc5578855e502b323c38f93df89ef562a24..3a0fce5f7bc3e0b3309aaa100fc63eb3f342d2fe 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -278,6 +278,7 @@ Beq Janus
 	SL-14766
 	SL-14927
 	SL-11300
+	SL-16021
 Beth Walcher
 Bezilon Kasei
 Biancaluce Robbiani
@@ -1105,6 +1106,7 @@ Nicky Dasmijn
 	OPEN-187
 	STORM-1937
 	OPEN-187
+	SL-15234
     STORM-2010
 	STORM-2082
 	MAINT-6665
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index f8a93baf452c0bd4cb2bb4dadb647808f5523aba..100eb57555c8362ce46e0a4f44ba9753dbcc9d67 100644
--- a/indra/llcommon/llmetricperformancetester.cpp
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -189,7 +189,6 @@ LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()
 void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) 
 {
 	incrementCurrentCount() ;
-	(*sd)[getCurrentLabelName()]["Name"] = mName ;
 }
 
 void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 62b39d29a4a2fd67c30a2e254b5398652b1cbac9..13b65dfaa04278a4633cce5fddb061fe9e2aa909 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -5316,22 +5316,23 @@ bool LLVolumeFace::cacheOptimize()
 	{
 		triangle_data.resize(mNumIndices / 3);
 		vertex_data.resize(mNumVertices);
-	}
-	catch (std::bad_alloc&)
-	{
-		LL_WARNS("LLVOLUME") << "Resize failed" << LL_ENDL;
-		return false;
-	}
 
-	for (U32 i = 0; i < mNumIndices; i++)
-	{ //populate vertex data and triangle data arrays
-		U16 idx = mIndices[i];
-		U32 tri_idx = i/3;
+        for (U32 i = 0; i < mNumIndices; i++)
+        { //populate vertex data and triangle data arrays
+            U16 idx = mIndices[i];
+            U32 tri_idx = i / 3;
 
-		vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
-		vertex_data[idx].mIdx = idx;
-		triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]);
-	}
+            vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
+            vertex_data[idx].mIdx = idx;
+            triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]);
+        }
+    }
+    catch (std::bad_alloc&)
+    {
+        // resize or push_back failed
+        LL_WARNS("LLVOLUME") << "Resize for " << mNumVertices << " vertices failed" << LL_ENDL;
+        return false;
+    }
 
 	/*F32 pre_acmr = 1.f;
 	//measure cache misses from before rebuild
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index e50db69190fee86b647a20ccb43567bba85a1927..eef22156bc3c5044eb130f185677228e37a04f51 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -80,8 +80,29 @@ class LLPluginProcessParentPollThread: public LLThread
 
 };
 
+
+class LLPluginProcessCreationThread : public LLThread
+{
+public:
+    LLPluginProcessCreationThread(LLPluginProcessParent *parent) :
+        LLThread("LLPluginProcessCreationThread", gAPRPoolp),
+        pParent(parent)
+    {
+    }
+protected:
+    // Inherited from LLThread, should run once
+    /*virtual*/ void run(void)
+    {
+        pParent->createPluginProcess();
+    }
+private:
+    LLPluginProcessParent *pParent;
+
+};
+
 LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
-	mIncomingQueueMutex()
+    mIncomingQueueMutex(),
+    pProcessCreationThread(NULL)
 {
 	if(!sInstancesMutex)
 	{
@@ -110,6 +131,18 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
 LLPluginProcessParent::~LLPluginProcessParent()
 {
 	LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
+    if (pProcessCreationThread)
+    {
+        if (!pProcessCreationThread->isStopped())
+        {
+            // Shouldn't happen at this stage
+            LL_WARNS("Plugin") << "Shutting down active pProcessCreationThread" << LL_ENDL;
+            pProcessCreationThread->shutdown();
+            ms_sleep(20);
+        }
+        delete pProcessCreationThread;
+        pProcessCreationThread = NULL;
+    }
 
 	// Destroy any remaining shared memory regions
 	sharedMemoryRegionsType::iterator iter;
@@ -160,6 +193,7 @@ void LLPluginProcessParent::shutdown()
             && state != STATE_ERROR)
         {
             (*it).second->setState(STATE_GOODBYE);
+            (*it).second->mOwner = NULL;
         }
         if (state != STATE_DONE)
         {
@@ -314,6 +348,35 @@ bool LLPluginProcessParent::accept()
 	return result;	
 }
 
+bool LLPluginProcessParent::createPluginProcess()
+{
+    if (!mProcess)
+    {
+        // Only argument to the launcher is the port number we're listening on
+        mProcessParams.args.add(stringize(mBoundPort));
+        mProcess = LLProcess::create(mProcessParams);
+        return mProcess != NULL;
+    }
+
+    return false;
+}
+
+void LLPluginProcessParent::clearProcessCreationThread()
+{
+    if (pProcessCreationThread)
+    {
+        if (!pProcessCreationThread->isStopped())
+        {
+            pProcessCreationThread->shutdown();
+        }
+        else
+        {
+            delete pProcessCreationThread;
+            pProcessCreationThread = NULL;
+        }
+    }
+}
+
 void LLPluginProcessParent::idle(void)
 {
 	bool idle_again;
@@ -321,8 +384,9 @@ void LLPluginProcessParent::idle(void)
 	do
 	{
 		// process queued messages
-		mIncomingQueueMutex.lock();
-		while(!mIncomingQueue.empty())
+        // Inside main thread, it is preferable not to block it on mutex.
+		bool locked = mIncomingQueueMutex.trylock();
+		while(locked && !mIncomingQueue.empty())
 		{
 			LLPluginMessage message = mIncomingQueue.front();
 			mIncomingQueue.pop();
@@ -330,10 +394,13 @@ void LLPluginProcessParent::idle(void)
 				
 			receiveMessage(message);
 			
-			mIncomingQueueMutex.lock();
+			locked = mIncomingQueueMutex.trylock();
 		}
 
-		mIncomingQueueMutex.unlock();
+        if (locked)
+        {
+            mIncomingQueueMutex.unlock();
+        }
 		
 		// Give time to network processing
 		if(mMessagePipe)
@@ -342,7 +409,10 @@ void LLPluginProcessParent::idle(void)
 			mMessagePipe->pumpOutput();
 			
 			// Only do input processing here if this instance isn't in a pollset.
-			if(!mPolledInput)
+			// If viewer and plugin are both shutting down, don't process further
+			// input, viewer won't be able to handle it.
+			if(!mPolledInput
+			   && !(mState >= STATE_GOODBYE && LLApp::isExiting()))
 			{
 				mMessagePipe->pumpInput();
 			}
@@ -469,14 +539,30 @@ void LLPluginProcessParent::idle(void)
 			case STATE_LISTENING:
 			    {
 				    // Launch the plugin process.
+                    if (mDebug && !pProcessCreationThread)
+                    {
+                        createPluginProcess();
+                        if (!mProcess)
+                        {
+                            errorState();
+                        }
+                    }
+                    else if (pProcessCreationThread == NULL)
+                    {
+                        // exe plugin process allocation can be hindered by a number
+                        // of factors, don't hold whole viewer because of it, use thread
+                        pProcessCreationThread = new LLPluginProcessCreationThread(this);
+                        pProcessCreationThread->start();
+                    }
+                    else if (!mProcess && pProcessCreationThread->isStopped())
+                    {
+                        delete pProcessCreationThread;
+                        pProcessCreationThread = NULL;
+                        errorState();
+                    }
+
 				
-				    // Only argument to the launcher is the port number we're listening on
-				    mProcessParams.args.add(stringize(mBoundPort));
-				    if (! (mProcess = LLProcess::create(mProcessParams)))
-				    {
-					    errorState();
-				    }
-				    else
+				    if (mProcess)
 				    {
 					    if(mDebug)
 					    {
@@ -505,6 +591,15 @@ void LLPluginProcessParent::idle(void)
 					    // This will allow us to time out if the process never starts.
 					    mHeartbeat.start();
 					    mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
+
+                        // pProcessCreationThread should have stopped by this point,
+                        // but check just in case it paused on statistics sync
+                        if (pProcessCreationThread && pProcessCreationThread->isStopped())
+                        {
+                            delete pProcessCreationThread;
+                            pProcessCreationThread = NULL;
+                        }
+
 					    setState(STATE_LAUNCHED);
 				    }
 			    }
@@ -607,6 +702,7 @@ void LLPluginProcessParent::idle(void)
 				killSockets();
 				setState(STATE_DONE);
                 dirtyPollSet();
+                clearProcessCreationThread();
 			    break;
 			
 			case STATE_DONE:
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index df1630255cc52ff165c557cd9d85ba62519b1a18..1893c9e65746cf267f96dd4839678fedbfeba414 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -69,6 +69,11 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 			  const std::string &plugin_filename, 
 			  bool debug);
 
+    // Creates a process
+    // returns true if process already exists or if created,
+    // false if failed to create
+    bool createPluginProcess();
+
 	void idle(void);
 	
 	// returns true if the plugin is on its way to steady state
@@ -163,12 +168,15 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 
 	bool accept();
 
+    void clearProcessCreationThread();
+
 	LLSocket::ptr_t mListenSocket;
 	LLSocket::ptr_t mSocket;
 	U32 mBoundPort;
 
 	LLProcess::Params mProcessParams;
 	LLProcessPtr mProcess;
+	LLThread *pProcessCreationThread;
 
 	std::string mPluginFile;
 	std::string mPluginDir;
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 702a1b523843864d24d1f88690aed0cabfe5008d..1b34068eced2ca0753aedeb6aaf071d94fa0ac80 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -1262,6 +1262,14 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn
 		LL_INFOS("MESHSKININFO")<<"Material of model is not a subset of reference."<<LL_ENDL;
 		return false;
 	}
+
+    if (mMaterialList.size() > ref->mMaterialList.size())
+    {
+        LL_INFOS("MESHSKININFO") << "Material of model has more materials than a reference." << LL_ENDL;
+        // We passed isMaterialListSubset, so materials are a subset, but subset isn't supposed to be
+        // larger than original and if we keep going, reordering will cause a crash
+        return false;
+    }
 	
 	std::map<std::string, U32> index_map;
 	
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 36a0cb0fd01cfe50f5fa4c3c94bd6b5a3f017edd..f888d7ff68cf604d1e5466e442bca72ecea49add 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -530,6 +530,58 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD&
 	}
 }
 
+// static
+// Same as toggleInstanceOrBringToFront but does not close floater.
+// unlike showInstance() does not trigger onOpen() if already open
+void LLFloaterReg::showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)
+{
+    std::string name = sdname.asString();
+    LLFloater* instance = getInstance(name, key);
+
+
+    if (!instance)
+    {
+        LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL;
+        return;
+    }
+
+    // If hosted, we need to take that into account
+    LLFloater* host = instance->getHost();
+
+    if (host)
+    {
+        if (host->isMinimized() || !host->isShown() || !host->isFrontmost())
+        {
+            host->setMinimized(FALSE);
+            instance->openFloater(key);
+            instance->setVisibleAndFrontmost(true, key);
+        }
+        else if (!instance->getVisible())
+        {
+            instance->openFloater(key);
+            instance->setVisibleAndFrontmost(true, key);
+            instance->setFocus(TRUE);
+        }
+    }
+    else
+    {
+        if (instance->isMinimized())
+        {
+            instance->setMinimized(FALSE);
+            instance->setVisibleAndFrontmost(true, key);
+        }
+        else if (!instance->isShown())
+        {
+            instance->openFloater(key);
+            instance->setVisibleAndFrontmost(true, key);
+        }
+        else if (!instance->isFrontmost())
+        {
+            instance->setVisibleAndFrontmost(true, key);
+        }
+    }
+}
+
 // static
 U32 LLFloaterReg::getVisibleFloaterInstanceCount()
 {
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index a457a156737312d7209ed6cb9d1002a904cb1f4c..eaa59b1d6f3eedbb8ca049a1bd115502daa3f2c8 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -129,6 +129,7 @@ class LLFloaterReg
 
 	// Callback wrappers
 	static void toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());
+	static void showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());
 	
 	// Typed find / get / show
 	template <class T>
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index b791a19c2bfe4091cf37453065a3afc5e7709f36..a1f0e78bf3763d2b14f29fec452e63f101b9c974 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1700,6 +1700,20 @@ void LLNotifications::add(const LLNotificationPtr pNotif)
 	updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif);
 }
 
+void LLNotifications::load(const LLNotificationPtr pNotif)
+{
+	if (pNotif == NULL) return;
+
+	// first see if we already have it -- if so, that's a problem
+	LLNotificationSet::iterator it=mItems.find(pNotif);
+	if (it != mItems.end())
+	{
+		LL_ERRS() << "Notification loaded a second time to the master notification channel." << LL_ENDL;
+	}
+
+	updateItem(LLSD().with("sigtype", "load").with("id", pNotif->id()), pNotif);
+}
+
 void LLNotifications::cancel(LLNotificationPtr pNotif)
 {
 	if (pNotif == NULL || pNotif->isCancelled()) return;
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 1c4860aa99e1409993ea1698632a3be949713788..921398a69325f8f942795d256751df762540aad2 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -917,6 +917,7 @@ class LLNotifications :
 	LLNotificationPtr add(const LLNotification::Params& p);
 
 	void add(const LLNotificationPtr pNotif);
+	void load(const LLNotificationPtr pNotif);
 	void cancel(LLNotificationPtr pNotif);
 	void cancelByName(const std::string& name);
 	void cancelByOwner(const LLUUID ownerId);
@@ -1117,6 +1118,11 @@ class LLPersistentNotificationChannel : public LLNotificationChannel
 		mHistory.push_back(p);
 	}
 
+	void onLoad(LLNotificationPtr p) 
+	{
+		mHistory.push_back(p);
+	}
+
 	std::vector<LLNotificationPtr> mHistory;
 };
 
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 13839da400e504f3e369d034cf916e9d6c163eec..8dd552d2adeae1e6c10c98bf29c5cc5337f8976b 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -79,6 +79,14 @@ const LLSD LLScrollListCell::getValue() const
 	return LLStringUtil::null;
 }
 
+
+// virtual
+const LLSD LLScrollListCell::getAltValue() const
+{
+	return LLStringUtil::null;
+}
+
+
 //
 // LLScrollListIcon
 //
@@ -173,6 +181,7 @@ U32 LLScrollListText::sCount = 0;
 LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
 :	LLScrollListCell(p),
 	mText(p.label.isProvided() ? p.label() : p.value().asString()),
+	mAltText(p.alt_value().asString()),
 	mFont(p.font),
 	mColor(p.color),
 	mUseColor(p.color.isProvided()),
@@ -275,10 +284,22 @@ void LLScrollListText::setValue(const LLSD& text)
 	setText(text.asString());
 }
 
+//virtual
+void LLScrollListText::setAltValue(const LLSD& text)
+{
+	mAltText = text.asString();
+}
+
 //virtual 
 const LLSD LLScrollListText::getValue() const		
 { 
-	return LLSD(mText.getString()); 
+	return LLSD(mText.getString());  
+}
+
+//virtual 
+const LLSD LLScrollListText::getAltValue() const		
+{ 
+	return LLSD(mAltText.getString());
 }
 
 
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 19576fb247adf131a06e44c6e34cb06dbf74f368..ede8d847d9e9f73ba16a5d7ba50ab47101cbe95e 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -60,6 +60,7 @@ class LLScrollListCell
 
 		Optional<void*>				userdata;
 		Optional<LLSD>				value; // state of checkbox, icon id/name, date
+		Optional<LLSD>				alt_value;
 		Optional<std::string>		label; // description or text
 		Optional<std::string>		tool_tip;
 
@@ -76,6 +77,7 @@ class LLScrollListCell
 			enabled("enabled", true),
 			visible("visible", true),
 			value("value"),
+			alt_value("alt_value", ""),
 			label("label"),
 			tool_tip("tool_tip", ""),
 			font("font", LLFontGL::getFontSansSerifSmall()),
@@ -98,7 +100,9 @@ class LLScrollListCell
 	virtual S32				getContentWidth() const { return 0; }
 	virtual S32				getHeight() const { return 0; }
 	virtual const LLSD		getValue() const;
+	virtual const LLSD		getAltValue() const;
 	virtual void			setValue(const LLSD& value) { }
+	virtual void			setAltValue(const LLSD& value) { }
 	virtual const std::string &getToolTip() const { return mToolTip; }
 	virtual void			setToolTip(const std::string &str) { mToolTip = str; }
 	virtual BOOL			getVisible() const { return TRUE; }
@@ -138,7 +142,9 @@ class LLScrollListText : public LLScrollListCell
 	/*virtual*/ S32		getContentWidth() const;
 	/*virtual*/ S32		getHeight() const;
 	/*virtual*/ void	setValue(const LLSD& value);
+	/*virtual*/ void	setAltValue(const LLSD& value);
 	/*virtual*/ const LLSD getValue() const;
+	/*virtual*/ const LLSD getAltValue() const;
 	/*virtual*/ BOOL	getVisible() const;
 	/*virtual*/ void	highlightText(S32 offset, S32 num_chars);
 
@@ -156,6 +162,7 @@ class LLScrollListText : public LLScrollListCell
 
 protected:
 	LLUIString		mText;
+	LLUIString		mAltText;
 	S32				mTextWidth;
 	const LLFontGL*	mFont;
 	LLColor4		mColor;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index a63457bdeab1af3f3cf3742000b2cc75714ca073..cd87c44dc24f37133e2aa24cf8de2357fdb83ae4 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -66,9 +66,10 @@ static LLDefaultChildRegistry::Register<LLScrollListCtrl> r("scroll_list");
 // local structures & classes.
 struct SortScrollListItem
 {
-	SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders,const LLScrollListCtrl::sort_signal_t*	sort_signal)
+	SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders,const LLScrollListCtrl::sort_signal_t*	sort_signal, bool alternate_sort)
 	:	mSortOrders(sort_orders)
 	,   mSortSignal(sort_signal)
+	,	mAltSort(alternate_sort)
 	{}
 
 	bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2)
@@ -93,7 +94,14 @@ struct SortScrollListItem
 				}
 				else
 				{
-					sort_result = order * LLStringUtil::compareDict(cell1->getValue().asString(), cell2->getValue().asString());
+					if (mAltSort && !cell1->getAltValue().asString().empty() && !cell2->getAltValue().asString().empty())
+					{
+						sort_result = order * LLStringUtil::compareDict(cell1->getAltValue().asString(), cell2->getAltValue().asString());
+					}
+					else
+					{
+						sort_result = order * LLStringUtil::compareDict(cell1->getValue().asString(), cell2->getValue().asString());
+					}
 				}
 				if (sort_result != 0)
 				{
@@ -109,6 +117,7 @@ struct SortScrollListItem
 	typedef std::vector<std::pair<S32, BOOL> > sort_order_t;
 	const LLScrollListCtrl::sort_signal_t* mSortSignal;
 	const sort_order_t& mSortOrders;
+	const bool mAltSort;
 };
 
 //---------------------------------------------------------------------------
@@ -213,6 +222,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
 	mSearchColumn(p.search_column),
 	mColumnPadding(p.column_padding),
 	mRowPadding(p.row_padding),
+	mAlternateSort(false),
 	mContextMenuType(MENU_NONE),
 	mIsFriendSignal(NULL)
 {
@@ -2679,7 +2689,7 @@ void LLScrollListCtrl::updateSort() const
 		std::stable_sort(
 			mItemList.begin(), 
 			mItemList.end(), 
-			SortScrollListItem(mSortColumns,mSortCallback));
+			SortScrollListItem(mSortColumns,mSortCallback, mAlternateSort));
 
 		mSorted = true;
 	}
@@ -2695,7 +2705,7 @@ void LLScrollListCtrl::sortOnce(S32 column, BOOL ascending)
 	std::stable_sort(
 		mItemList.begin(), 
 		mItemList.end(), 
-		SortScrollListItem(sort_column,mSortCallback));
+		SortScrollListItem(sort_column,mSortCallback,mAlternateSort));
 }
 
 void LLScrollListCtrl::dirtyColumns() 
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 0cc481b113be1a82081f9c5ac3042a56c6142e06..08134bbfc83afc69538aeb339be8596b2a9d9d7c 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -398,6 +398,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	BOOL			hasSortOrder() const;
 	void			clearSortOrder();
 
+	void			setAlternateSort() { mAlternateSort = true; }
+
 	S32		selectMultiple( uuid_vec_t ids );
 	// conceptually const, but mutates mItemList
 	void			updateSort() const;
@@ -482,6 +484,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	bool			mColumnsDirty;
 	bool			mColumnWidthsDirty;
 
+	bool			mAlternateSort;
+
 	mutable item_list	mItemList;
 
 	LLScrollListItem *mLastSelected;
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index 51c615dd0037e23f0f5620ee07196c8470ce95f2..e1360f80cda7349fabcc66d115805834a18d85fb 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -44,7 +44,8 @@ LLScrollListItem::LLScrollListItem( const Params& p )
 	mSelectedIndex(-1),
 	mEnabled(p.enabled),
 	mUserdata(p.userdata),
-	mItemValue(p.value)
+	mItemValue(p.value),
+	mItemAltValue(p.alt_value)
 {
 }
 
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index d2c3dd7721b2c54fafd02b48cc0de7b9985f5e27..a3398305b176f42a8e86a0f8fba90d8d1f8c9973 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -55,6 +55,7 @@ class LLScrollListItem
 		Optional<bool>		enabled;
 		Optional<void*>		userdata;
 		Optional<LLSD>		value;
+		Optional<LLSD>		alt_value;
 		
 		Ignored				name; // use for localization tools
 		Ignored				type; 
@@ -65,6 +66,7 @@ class LLScrollListItem
 		Params()
 		:	enabled("enabled", true),
 			value("value"),
+			alt_value("alt_value"),
 			name("name"),
 			type("type"),
 			length("length"),
@@ -97,6 +99,7 @@ class LLScrollListItem
 
 	virtual LLUUID	getUUID() const			{ return mItemValue.asUUID(); }
 	LLSD	getValue() const				{ return mItemValue; }
+	LLSD	getAltValue() const				{ return mItemAltValue; }
 	
 	void	setRect(LLRect rect)			{ mRectangle = rect; }
 	LLRect	getRect() const					{ return mRectangle; }
@@ -131,6 +134,7 @@ class LLScrollListItem
 	BOOL	mEnabled;
 	void*	mUserdata;
 	LLSD	mItemValue;
+	LLSD	mItemAltValue;
 	std::vector<LLScrollListCell *> mColumns;
 	LLRect  mRectangle;
 };
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 05788f1b6c7798ca8045fcdbd2e944d4872a6f44..0532750dce801e6659d1cf29311b8103970ef4e5 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1564,11 +1564,14 @@ void LLTextBase::reflow()
 		{
 			// find first element whose end comes after start_index
 			line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare());
-			line_start_index = iter->mDocIndexStart;
-			line_count = iter->mLineNum;
-			cur_top = iter->mRect.mTop;
-			getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset);
-			mLineInfoList.erase(iter, mLineInfoList.end());
+            if (iter != mLineInfoList.end())
+            {
+                line_start_index = iter->mDocIndexStart;
+                line_count = iter->mLineNum;
+                cur_top = iter->mRect.mTop;
+                getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset);
+                mLineInfoList.erase(iter, mLineInfoList.end());
+            }
 		}
 
 		S32 line_height = 0;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 6f16745bd343bd9fafbc9c9429de769835928105..3f3ec7ee8b6f037dfc6ab15e0d8f4cbc29d91731 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -173,6 +173,7 @@ mHelpImpl(NULL)
 	reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleInstance, _2, LLSD()));
 	reg.add("Floater.ToggleOrBringToFront", boost::bind(&LLFloaterReg::toggleInstanceOrBringToFront, _2, LLSD()));
 	reg.add("Floater.Show", boost::bind(&LLFloaterReg::showInstance, _2, LLSD(), FALSE));
+	reg.add("Floater.ShowOrBringToFront", boost::bind(&LLFloaterReg::showInstanceOrBringToFront, _2, LLSD()));
 	reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideInstance, _2, LLSD()));
 	
 	// Button initialization callback for toggle buttons
diff --git a/indra/llwindow/llcursortypes.cpp b/indra/llwindow/llcursortypes.cpp
index ec60097195b64b3e00b5fe37e215c3a7a934e170..3079cc24198ef70d7ffdc531c1f4eb5358fdb661 100644
--- a/indra/llwindow/llcursortypes.cpp
+++ b/indra/llwindow/llcursortypes.cpp
@@ -42,6 +42,7 @@ ECursorType getCursorFromString(const std::string& cursor_string)
 		cursor_string_table["UI_CURSOR_SIZENESW"] = UI_CURSOR_SIZENESW;
 		cursor_string_table["UI_CURSOR_SIZEWE"] = UI_CURSOR_SIZEWE;
 		cursor_string_table["UI_CURSOR_SIZENS"] = UI_CURSOR_SIZENS;
+		cursor_string_table["UI_CURSOR_SIZEALL"] = UI_CURSOR_SIZEALL;
 		cursor_string_table["UI_CURSOR_NO"] = UI_CURSOR_NO;
 		cursor_string_table["UI_CURSOR_WORKING"] = UI_CURSOR_WORKING;
 		cursor_string_table["UI_CURSOR_TOOLGRAB"] = UI_CURSOR_TOOLGRAB;
@@ -61,6 +62,7 @@ ECursorType getCursorFromString(const std::string& cursor_string)
 		cursor_string_table["UI_CURSOR_TOOLCAMERA"] = UI_CURSOR_TOOLCAMERA;
 		cursor_string_table["UI_CURSOR_TOOLPAN"] = UI_CURSOR_TOOLPAN;
 		cursor_string_table["UI_CURSOR_TOOLZOOMIN"] = UI_CURSOR_TOOLZOOMIN;
+		cursor_string_table["UI_CURSOR_TOOLZOOMOUT"] = UI_CURSOR_TOOLZOOMOUT;
 		cursor_string_table["UI_CURSOR_TOOLPICKOBJECT3"] = UI_CURSOR_TOOLPICKOBJECT3;
 		cursor_string_table["UI_CURSOR_TOOLPLAY"] = UI_CURSOR_TOOLPLAY;
 		cursor_string_table["UI_CURSOR_TOOLPAUSE"] = UI_CURSOR_TOOLPAUSE;
diff --git a/indra/llwindow/llcursortypes.h b/indra/llwindow/llcursortypes.h
index cb6d6636a0f9307d4e6764338fd9260c0053e76f..d03b18e2757d3266826cb4447d84106768476715 100644
--- a/indra/llwindow/llcursortypes.h
+++ b/indra/llwindow/llcursortypes.h
@@ -38,6 +38,7 @@ enum ECursorType {
 	UI_CURSOR_SIZENESW,
 	UI_CURSOR_SIZEWE,
 	UI_CURSOR_SIZENS,
+	UI_CURSOR_SIZEALL,
 	UI_CURSOR_NO,
 	UI_CURSOR_WORKING,
 	UI_CURSOR_TOOLGRAB,
@@ -57,6 +58,7 @@ enum ECursorType {
 	UI_CURSOR_TOOLCAMERA,
 	UI_CURSOR_TOOLPAN,
 	UI_CURSOR_TOOLZOOMIN,
+	UI_CURSOR_TOOLZOOMOUT,
 	UI_CURSOR_TOOLPICKOBJECT3,
 	UI_CURSOR_TOOLPLAY,
 	UI_CURSOR_TOOLPAUSE,
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index dfdfe4aa3350dbd4acd571cb6d10169e681d22e4..24ce5131d557cc61ab662da318f4264398093946 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1432,6 +1432,7 @@ const char* cursorIDToName(int id)
 		case UI_CURSOR_SIZENESW:						return "UI_CURSOR_SIZENESW";
 		case UI_CURSOR_SIZEWE:							return "UI_CURSOR_SIZEWE";
 		case UI_CURSOR_SIZENS:							return "UI_CURSOR_SIZENS";
+		case UI_CURSOR_SIZEALL:							return "UI_CURSOR_SIZEALL";
 		case UI_CURSOR_NO:								return "UI_CURSOR_NO";
 		case UI_CURSOR_WORKING:							return "UI_CURSOR_WORKING";
 		case UI_CURSOR_TOOLGRAB:						return "UI_CURSOR_TOOLGRAB";
@@ -1451,6 +1452,7 @@ const char* cursorIDToName(int id)
 		case UI_CURSOR_TOOLCAMERA:						return "UI_CURSOR_TOOLCAMERA";
 		case UI_CURSOR_TOOLPAN:							return "UI_CURSOR_TOOLPAN";
 		case UI_CURSOR_TOOLZOOMIN:						return "UI_CURSOR_TOOLZOOMIN";
+		case UI_CURSOR_TOOLZOOMOUT:						return "UI_CURSOR_TOOLZOOMOUT";
 		case UI_CURSOR_TOOLPICKOBJECT3:					return "UI_CURSOR_TOOLPICKOBJECT3";
 		case UI_CURSOR_TOOLPLAY:						return "UI_CURSOR_TOOLPLAY";
 		case UI_CURSOR_TOOLPAUSE:						return "UI_CURSOR_TOOLPAUSE";
@@ -1620,6 +1622,7 @@ void LLWindowMacOSX::initCursors()
 	initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6);
 	initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6);
 	initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6);
+    initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6);
 	initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1);
 	initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1);
 	initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1);
@@ -1638,6 +1641,7 @@ void LLWindowMacOSX::initCursors()
 	initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10);
 	initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10);
 	initPixmapCursor(UI_CURSOR_SIZENS, 10, 10);
+    initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10);
 
 }
 
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index 85eb9d6d1b17e47eda95d9e7c6e0225a5ef54538..7ea87f588476151115b51126ee853833e3f70e3d 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -2078,6 +2078,7 @@ void LLWindowSDL::initCursors()
 	mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17);
 	mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14);
 	mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16);
+    mSDLCursors[UI_CURSOR_SIZEALL] = makeSDLCursorFromBMP("sizeall.BMP", 17, 17);
 	mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8);
 	mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15);
 	mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13);
@@ -2097,6 +2098,7 @@ void LLWindowSDL::initCursors()
 	mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5);
 	mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5);
 	mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5);
+    mSDLCursors[UI_CURSOR_TOOLZOOMOUT] = makeSDLCursorFromBMP("lltoolzoomout.BMP", 7, 5);
 	mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0);
 	mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0);
 	mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0);
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index b2b123f0da0764e297b46ac67d82bcac22ba9044..f303d1bb210fda1a31d8639bd785e42e090352c7 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1915,8 +1915,9 @@ void LLWindowWin32::initCursors()
 	mCursor[ UI_CURSOR_CROSS ]		= LoadCursor(NULL, IDC_CROSS);
 	mCursor[ UI_CURSOR_SIZENWSE ]	= LoadCursor(NULL, IDC_SIZENWSE);
 	mCursor[ UI_CURSOR_SIZENESW ]	= LoadCursor(NULL, IDC_SIZENESW);
-	mCursor[ UI_CURSOR_SIZEWE ]		= LoadCursor(NULL, IDC_SIZEWE);  
-	mCursor[ UI_CURSOR_SIZENS ]		= LoadCursor(NULL, IDC_SIZENS);  
+	mCursor[ UI_CURSOR_SIZEWE ]		= LoadCursor(NULL, IDC_SIZEWE);
+	mCursor[ UI_CURSOR_SIZENS ]		= LoadCursor(NULL, IDC_SIZENS);
+	mCursor[ UI_CURSOR_SIZEALL ]	= LoadCursor(NULL, IDC_SIZEALL);
 	mCursor[ UI_CURSOR_NO ]			= LoadCursor(NULL, IDC_NO);
 	mCursor[ UI_CURSOR_WORKING ]	= LoadCursor(NULL, IDC_APPSTARTING); 
 
@@ -1938,6 +1939,7 @@ void LLWindowWin32::initCursors()
 	mCursor[ UI_CURSOR_TOOLCAMERA ]	= LoadCursor(module, TEXT("TOOLCAMERA"));
 	mCursor[ UI_CURSOR_TOOLPAN ]	= LoadCursor(module, TEXT("TOOLPAN"));
 	mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN"));
+	mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT"));
 	mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3"));
 	mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE"));
 	mCursor[ UI_CURSOR_TOOLSIT ]	= LoadCursor(module, TEXT("TOOLSIT"));
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 0b3d14fb166917375c73deba7608f18bcbf7edf5..e33330c1bb9f7ffe86f0fcb6cdcc9df63c6acf83 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -120,6 +120,9 @@ class LLWindowWin32 : public LLWindow
 
     /*virtual*/ void* getDirectInput8();
     /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata);
+
+    U32 getRawWParam() { return mRawWParam; }
+
 protected:
 	LLWindowWin32(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, 
diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp
index 656b23fa1ed74ee3f95918475646b2b518a4d19e..ea70e214145fe06ecc10087789561d69198984b9 100644
--- a/indra/media_plugins/cef/media_plugin_cef.cpp
+++ b/indra/media_plugins/cef/media_plugin_cef.cpp
@@ -402,21 +402,86 @@ void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type)
 
 	switch (type)
 	{
-		case dullahan::CT_POINTER:
-			name = "arrow";
-			break;
+        case dullahan::CT_POINTER:
+            name = "UI_CURSOR_ARROW";
+            break;
+        case dullahan::CT_CROSS:
+            name = "UI_CURSOR_CROSS";
+            break;
+        case dullahan::CT_HAND:
+            name = "UI_CURSOR_HAND";
+            break;
 		case dullahan::CT_IBEAM:
-			name = "ibeam";
-			break;
-		case dullahan::CT_NORTHSOUTHRESIZE:
-			name = "splitv";
-			break;
-		case dullahan::CT_EASTWESTRESIZE:
-			name = "splith";
-			break;
-		case dullahan::CT_HAND:
-			name = "hand";
+			name = "UI_CURSOR_IBEAM";
 			break;
+        case dullahan::CT_WAIT:
+            name = "UI_CURSOR_WAIT";
+            break;
+        //case dullahan::CT_HELP:
+        case dullahan::CT_ROWRESIZE:
+        case dullahan::CT_NORTHRESIZE:
+        case dullahan::CT_SOUTHRESIZE:
+        case dullahan::CT_NORTHSOUTHRESIZE:
+            name = "UI_CURSOR_SIZENS";
+            break;
+        case dullahan::CT_COLUMNRESIZE:
+        case dullahan::CT_EASTRESIZE:
+        case dullahan::CT_WESTRESIZE:
+        case dullahan::CT_EASTWESTRESIZE:
+            name = "UI_CURSOR_SIZEWE";
+            break;
+        case dullahan::CT_NORTHEASTRESIZE:
+        case dullahan::CT_SOUTHWESTRESIZE:
+        case dullahan::CT_NORTHEASTSOUTHWESTRESIZE:
+            name = "UI_CURSOR_SIZENESW";
+            break;
+        case dullahan::CT_SOUTHEASTRESIZE:
+        case dullahan::CT_NORTHWESTRESIZE:
+        case dullahan::CT_NORTHWESTSOUTHEASTRESIZE:
+            name = "UI_CURSOR_SIZENWSE";
+            break;
+        case dullahan::CT_MOVE:
+            name = "UI_CURSOR_SIZEALL";
+            break;
+        //case dullahan::CT_MIDDLEPANNING:
+        //case dullahan::CT_EASTPANNING:
+        //case dullahan::CT_NORTHPANNING:
+        //case dullahan::CT_NORTHEASTPANNING:
+        //case dullahan::CT_NORTHWESTPANNING:
+        //case dullahan::CT_SOUTHPANNING:
+        //case dullahan::CT_SOUTHEASTPANNING:
+        //case dullahan::CT_SOUTHWESTPANNING:
+        //case dullahan::CT_WESTPANNING:
+        //case dullahan::CT_VERTICALTEXT:
+        //case dullahan::CT_CELL:
+        //case dullahan::CT_CONTEXTMENU:
+        case dullahan::CT_ALIAS:
+            name = "UI_CURSOR_TOOLMEDIAOPEN";
+            break;
+        case dullahan::CT_PROGRESS:
+            name = "UI_CURSOR_WORKING";
+            break;
+        case dullahan::CT_COPY:
+            name = "UI_CURSOR_ARROWCOPY";
+            break;
+        case dullahan::CT_NONE:
+            name = "UI_CURSOR_NO";
+            break;
+        case dullahan::CT_NODROP:
+        case dullahan::CT_NOTALLOWED:
+            name = "UI_CURSOR_NOLOCKED";
+            break;
+        case dullahan::CT_ZOOMIN:
+            name = "UI_CURSOR_TOOLZOOMIN";
+            break;
+        case dullahan::CT_ZOOMOUT:
+            name = "UI_CURSOR_TOOLZOOMOUT";
+            break;
+        case dullahan::CT_GRAB:
+            name = "UI_CURSOR_TOOLGRAB";
+            break;
+        //case dullahan::CT_GRABING:
+        //case dullahan::CT_CUSTOM:
 
 		default:
 			LL_WARNS() << "Unknown cursor ID: " << (int)type << LL_ENDL;
diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index 1a5157838cd7a2f0d5858e5b6ce59af32853091b..2ec9a2586c693bbefcc4b4ff1cfd0e7320024489 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -32,7 +32,7 @@
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="MMB" command="voice_follow_key"/>
   </first_person>
   <third_person>
     <binding key="A" mask="NONE" command="turn_left"/>
@@ -125,7 +125,8 @@
     <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
     <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
 
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="MMB" command="voice_follow_key"/>
+    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </third_person>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
@@ -222,7 +223,7 @@
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="MMB" command="voice_follow_key"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
@@ -249,6 +250,6 @@
     <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
     <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
 
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="MMB" command="voice_follow_key"/>
   </edit_avatar>
 </keys>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a40919c1e98533d440744ab6d9de042b5b4f4b56..dc8c7b79678d2617c8eb6759c8c91f36e62afadb 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8341,13 +8341,13 @@
     <key>PushToTalkToggle</key>
     <map>
       <key>Comment</key>
-      <string>Should the push-to-talk button behave as a toggle</string>
+      <string>Should the push-to-talk toolbar button behave as a toggle</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
     <key>QAMode</key>
     <map>
@@ -12568,6 +12568,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>TextureFetchMinTimeToLog</key>
+    <map>
+      <key>Comment</key>
+      <string>If texture fetching time exceeds this value, texture fetch tester will log info</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>2.0</real>
+    </map>
   <key>TextureFetchFakeFailureRate</key>
   <map>
     <key>Comment</key>
@@ -12656,6 +12667,17 @@
       <key>Value</key>
       <integer>32</integer>
     </map>
+    <key>TextureListFetchingThreshold</key>
+    <map>
+      <key>Comment</key>
+      <string>If the ratio between fetched and all textures in the list is greater than this threshold, which we assume that almost all textures are fetched</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>0.97</real>
+    </map>
     <key>TextureLoadFullRes</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/cursors_mac/UI_CURSOR_SIZEALL.tif b/indra/newview/cursors_mac/UI_CURSOR_SIZEALL.tif
new file mode 100644
index 0000000000000000000000000000000000000000..85fec76fca2beb5a196141f290adc14227dfede4
Binary files /dev/null and b/indra/newview/cursors_mac/UI_CURSOR_SIZEALL.tif differ
diff --git a/indra/newview/cursors_mac/UI_CURSOR_TOOLZOOMOUT.tif b/indra/newview/cursors_mac/UI_CURSOR_TOOLZOOMOUT.tif
new file mode 100644
index 0000000000000000000000000000000000000000..d64a7f2b68b2b66b388476b99cf9359459ea648b
Binary files /dev/null and b/indra/newview/cursors_mac/UI_CURSOR_TOOLZOOMOUT.tif differ
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 50e0d1d93541cfbd236b4d97c00f5ffb7a3575a9..9cae1dd930f5cf4c765c0778833857fb33eec6f2 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -3911,16 +3911,6 @@ bool LLAgent::teleportCore(bool is_local)
 	// hide the Region/Estate floater
 	LLFloaterReg::hideInstance("region_info");
 
-	// minimize the Search floater (STORM-1474)
-	{
-		LLFloater* instance = LLFloaterReg::getInstance("search");
-
-		if (instance && instance->getVisible())
-		{
-			instance->setMinimized(TRUE);
-		}
-	}
-
 	LLViewerParcelMgr::getInstance()->deselectLand();
 	LLViewerMediaFocus::getInstance()->clearFocus();
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 29a034133e3f8d5f329d4619757a0ac70c35a3cb..8951213f717f87020e3b1d920840dda631ea2963 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1736,12 +1736,14 @@ bool LLAppViewer::cleanup()
 	// one because it happens just after mFastTimerLogThread is deleted. This
 	// comment is in case we guessed wrong, so we can move it here instead.
 
+#if LL_LINUX
 	// remove any old breakpad minidump files from the log directory
 	if (! isError())
 	{
 		std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
 		gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
 	}
+#endif
 
 	// Kill off LLLeap objects. We can find them all because LLLeap is derived
 	// from LLInstanceTracker.
@@ -4611,6 +4613,10 @@ void LLAppViewer::idle()
 	//
 	// Special case idle if still starting up
 	//
+	if (LLStartUp::getStartupState() >= STATE_WORLD_INIT)
+	{
+		update_texture_time();
+	}
 	if (LLStartUp::getStartupState() < STATE_STARTED)
 	{
 		// Skip rest if idle startup returns false (essentially, no world yet)
diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index 0460bff1b4859f923f7b8a584ee5a5318fcf1a9a..7614624306bca3ddd3a10f3b53a09147e5be607c 100644
--- a/indra/newview/llbrowsernotification.cpp
+++ b/indra/newview/llbrowsernotification.cpp
@@ -40,7 +40,7 @@ LLBrowserNotification::LLBrowserNotification()
 {
 }
 
-bool LLBrowserNotification::processNotification(const LLNotificationPtr& notification)
+bool LLBrowserNotification::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
 	LLUUID media_id = notification->getPayload()["media_id"].asUUID();
 	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(media_id);
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index 9201c6bc0082cb678b1d38ea6fb14e0c67d32aff..aceedda07eb83c1ce5379308d2e4083b7239cf96 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -546,6 +546,7 @@ class LLNotificationChiclet : public LLSysWellChiclet
 		static bool filterNotification(LLNotificationPtr notify);
 		// connect counter updaters to the corresponding signals
 		/*virtual*/ void onAdd(LLNotificationPtr p) { mChiclet->setCounter(++mChiclet->mUreadSystemNotifications); }
+		/*virtual*/ void onLoad(LLNotificationPtr p) { mChiclet->setCounter(++mChiclet->mUreadSystemNotifications); }
 		/*virtual*/ void onDelete(LLNotificationPtr p) { mChiclet->setCounter(--mChiclet->mUreadSystemNotifications); }
 				
 		LLNotificationChiclet* const mChiclet;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index eb0bd0de4ecb72de8a8caa4787d1ef247ea12486..76cbe85b7e3ced9ca065a406868f7060e4d514c8 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -574,10 +574,9 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
 	}
 	LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance();
 	BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor();
-	if (oa == LLVOAvatar::AOA_INVISIBLE ||
-		(impostor && oa == LLVOAvatar::AOA_JELLYDOLL))
+	if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE))
 	{
-		// No shadows for jellydolled or invisible avs.
+		// No shadows for impostored (including jellydolled) or invisible avs.
 		return;
 	}
 	
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 4a802ad9aa774462f5faa92d06c1f9dd7cc6567d..f1b64a58993f6c38490f62cf984006d652ad6075 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1074,6 +1074,13 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to,  LLVector2* res_st_offs
 
     F32 map_rot = 0.f, map_scaleS = 0.f, map_scaleT = 0.f, map_offsS = 0.f, map_offsT = 0.f;
 
+    LLMaterial* mat = orig_tep->getMaterialParams();
+    if (!mat && map != LLRender::DIFFUSE_MAP)
+    {
+        LL_WARNS_ONCE("llface") << "Face is set to use specular or normal map but has no material, defaulting to diffuse" << LL_ENDL;
+        map = LLRender::DIFFUSE_MAP;
+    }
+
     switch (map)
     {
     case LLRender::DIFFUSE_MAP:
@@ -1084,26 +1091,26 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to,  LLVector2* res_st_offs
         map_offsT = orig_tep->mOffsetT;
         break;
     case LLRender::NORMAL_MAP:
-        if (orig_tep->getMaterialParams()->getNormalID().isNull())
+        if (mat->getNormalID().isNull())
         {
             return false;
         }
-        map_rot = orig_tep->getMaterialParams()->getNormalRotation();
-        map_scaleS = orig_tep->getMaterialParams()->getNormalRepeatX();
-        map_scaleT = orig_tep->getMaterialParams()->getNormalRepeatY();
-        map_offsS = orig_tep->getMaterialParams()->getNormalOffsetX();
-        map_offsT = orig_tep->getMaterialParams()->getNormalOffsetY();
+        map_rot = mat->getNormalRotation();
+        map_scaleS = mat->getNormalRepeatX();
+        map_scaleT = mat->getNormalRepeatY();
+        map_offsS = mat->getNormalOffsetX();
+        map_offsT = mat->getNormalOffsetY();
         break;
     case LLRender::SPECULAR_MAP:
-        if (orig_tep->getMaterialParams()->getSpecularID().isNull())
+        if (mat->getSpecularID().isNull())
         {
             return false;
         }
-        map_rot = orig_tep->getMaterialParams()->getSpecularRotation();
-        map_scaleS = orig_tep->getMaterialParams()->getSpecularRepeatX();
-        map_scaleT = orig_tep->getMaterialParams()->getSpecularRepeatY();
-        map_offsS = orig_tep->getMaterialParams()->getSpecularOffsetX();
-        map_offsT = orig_tep->getMaterialParams()->getSpecularOffsetY();
+        map_rot = mat->getSpecularRotation();
+        map_scaleS = mat->getSpecularRepeatX();
+        map_scaleT = mat->getSpecularRepeatY();
+        map_offsS = mat->getSpecularOffsetX();
+        map_offsT = mat->getSpecularOffsetY();
         break;
     default: /*make compiler happy*/
         break;
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 441979389e735ebb874bdb170038ee0615b91b18..43dc304c1076039d180468a37dbd0d6dbab15372 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -384,13 +384,16 @@ void LLFloaterIMSessionTab::draw()
 
 void LLFloaterIMSessionTab::enableDisableCallBtn()
 {
-    mVoiceButton->setEnabled(
-    		mSessionID.notNull()
-    		&& mSession
-    		&& mSession->mSessionInitialized
-    		&& LLVoiceClient::getInstance()->voiceEnabled()
-    		&& LLVoiceClient::getInstance()->isVoiceWorking()
-    		&& mSession->mCallBackEnabled);
+    if (LLVoiceClient::instanceExists())
+    {
+        mVoiceButton->setEnabled(
+            mSessionID.notNull()
+            && mSession
+            && mSession->mSessionInitialized
+            && LLVoiceClient::getInstance()->voiceEnabled()
+            && LLVoiceClient::getInstance()->isVoiceWorking()
+            && mSession->mCallBackEnabled);
+    }
 }
 
 void LLFloaterIMSessionTab::onFocusReceived()
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index af0e56e4480cb4c85aebb877dd5d3cc6a113eba2..04133f27109d73b1e0e3164b2cfeed77fcf9bc06 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -2468,6 +2468,7 @@ BOOL LLPanelLandAccess::postBuild()
 	{
 		mListBanned->sortByColumnIndex(0, TRUE); // ascending
 		mListBanned->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
+		mListBanned->setAlternateSort();
 	}
 
 	return TRUE;
@@ -2570,11 +2571,12 @@ void LLPanelLandAccess::refresh()
 			{
 				const LLAccessEntry& entry = (*cit).second;
 				std::string duration;
+				S32 seconds = -1;
 				if (entry.mTime != 0)
 				{
 					LLStringUtil::format_map_t args;
 					S32 now = time(NULL);
-					S32 seconds = entry.mTime - now;					
+					seconds = entry.mTime - now;					
 					if (seconds < 0) seconds = 0;
 
 					if (seconds >= 7200)
@@ -2611,6 +2613,7 @@ void LLPanelLandAccess::refresh()
 				columns[0]["column"] = "name"; // to be populated later
 				columns[1]["column"] = "duration";
 				columns[1]["value"] = duration;
+				columns[1]["alt_value"] = entry.mTime != 0 ? std::to_string(seconds) : "Always";
 				mListBanned->addElement(item);
 			}
 			mListBanned->sortByName(TRUE);
diff --git a/indra/newview/llfloaterlandholdings.cpp b/indra/newview/llfloaterlandholdings.cpp
index 749a3d26862f9c9c1cbdc4e8fde28f2c6bf006b3..8633fe4e5e58d487a38f63c93dfb86d54defca51 100644
--- a/indra/newview/llfloaterlandholdings.cpp
+++ b/indra/newview/llfloaterlandholdings.cpp
@@ -108,6 +108,9 @@ LLFloaterLandHoldings::~LLFloaterLandHoldings()
 
 void LLFloaterLandHoldings::onOpen(const LLSD& key)
 {
+    LLScrollListCtrl *list = getChild<LLScrollListCtrl>("parcel list");
+    list->clearRows();
+
 	// query_id null is known to be us
 	const LLUUID& query_id = LLUUID::null;
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 64b24d54c3d69d8c1141c908eb52d744c1cb3b75..abc64a7ad9a83359da225035fbd6d6d7b66f9e48 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -343,7 +343,7 @@ void LLFloaterModelPreview::initModelPreview()
 
 	mModelPreview = new LLModelPreview(tex_width, tex_height, this);
     mModelPreview->setPreviewTarget(PREVIEW_CAMERA_DISTANCE);
-	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5));
+	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3));
 	mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::modelUpdated, this, _1));
 }
 
@@ -804,9 +804,6 @@ void LLFloaterModelPreview::draw()
 		}
 	}
 
-	childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost));
-	childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size()));
-
     if (!isMinimized() && mModelPreview->lodsReady())
 	{
 		draw3dPreview();
@@ -1546,7 +1543,7 @@ void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash
 	}
 	}
 
-void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)
+void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z)
 {
 	assert_main_thread();
 	childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x));
@@ -1719,9 +1716,20 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)
 void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
 {
 	mModelPreview->updateLodControls(lod);
-	refresh();
 
 	LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
+
+    if (lod_source_combo->getCurrentIndex() == LLModelPreview::LOD_FROM_FILE
+        && mModelPreview->mLODFile[lod].empty())
+    {
+        // File wasn't selected, so nothing to do yet, refreshing
+        // hovewer will cause a small freeze with large meshes
+        // Might be good idea to open filepicker here
+        return;
+    }
+
+	refresh();
+
 	if (lod_source_combo->getCurrentIndex() == LLModelPreview::GENERATE)
 	{ //rebuild LoD to update triangle counts
 		onLODParamCommit(lod, true);
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 8a01b0c30773c2448e22554ae3c2fc3c3d1f98fa..bb8cf1c58705c22b8655cff6ff23588c5df87b01 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -90,7 +90,7 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase
 	void clearAvatarTab(); // clears table
 	void updateAvatarTab(bool highlight_overrides); // populates table and data as nessesary
 
-	void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost);
+	void setDetails(F32 x, F32 y, F32 z);
 	void setPreviewLOD(S32 lod);
 	
 	void onBrowseLOD(S32 lod);
diff --git a/indra/newview/llfloatertexturefetchdebugger.cpp b/indra/newview/llfloatertexturefetchdebugger.cpp
index 9a23d99802e660db68c0d4420da57937f6aa5e9e..cda4dc8bccb2949ca31334131babe8a2c6116054 100644
--- a/indra/newview/llfloatertexturefetchdebugger.cpp
+++ b/indra/newview/llfloatertexturefetchdebugger.cpp
@@ -38,6 +38,7 @@
 #include "llappviewer.h"
 #include "lltexturefetch.h"
 #include "llviewercontrol.h"
+#include "llviewerassetstats.h" //gTextureTimer
 
 LLFloaterTextureFetchDebugger::LLFloaterTextureFetchDebugger(const LLSD& key)
 	: LLFloater(key),
@@ -50,6 +51,7 @@ LLFloaterTextureFetchDebugger::LLFloaterTextureFetchDebugger(const LLSD& key)
 	mCommitCallbackRegistrar.add("TexFetchDebugger.Start",	boost::bind(&LLFloaterTextureFetchDebugger::onClickStart, this));
 	mCommitCallbackRegistrar.add("TexFetchDebugger.Clear",	boost::bind(&LLFloaterTextureFetchDebugger::onClickClear, this));
 	mCommitCallbackRegistrar.add("TexFetchDebugger.Close",	boost::bind(&LLFloaterTextureFetchDebugger::onClickClose, this));
+	mCommitCallbackRegistrar.add("TexFetchDebugger.ResetFetchTime",	boost::bind(&LLFloaterTextureFetchDebugger::onClickResetFetchTime, this));
 
 	mCommitCallbackRegistrar.add("TexFetchDebugger.CacheRead",	boost::bind(&LLFloaterTextureFetchDebugger::onClickCacheRead, this));
 	mCommitCallbackRegistrar.add("TexFetchDebugger.CacheWrite",	boost::bind(&LLFloaterTextureFetchDebugger::onClickCacheWrite, this));
@@ -228,6 +230,12 @@ void LLFloaterTextureFetchDebugger::onClickClose()
 	delete this;
 }
 
+void LLFloaterTextureFetchDebugger::onClickResetFetchTime()
+{
+	gTextureTimer.start();
+	gTextureTimer.pause();
+}
+
 void LLFloaterTextureFetchDebugger::onClickClear()
 {
 	mButtonStateMap["start_btn"] = true;
diff --git a/indra/newview/llfloatertexturefetchdebugger.h b/indra/newview/llfloatertexturefetchdebugger.h
index 096ad88e07e5c1520f5fd28e5b1e5526937806ee..637f3b03e5ef452a5a0a99f677ad9a22c944b2f8 100644
--- a/indra/newview/llfloatertexturefetchdebugger.h
+++ b/indra/newview/llfloatertexturefetchdebugger.h
@@ -44,6 +44,7 @@ class LLFloaterTextureFetchDebugger : public LLFloater
 	void onClickStart();
 	void onClickClear();
 	void onClickClose();
+	void onClickResetFetchTime();
 
 	void onClickCacheRead();
 	void onClickCacheWrite();
diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp
index 63bce3d2eb715425ee884e44f164e5b6d2c68a8c..d5c2ad5f81f7f74dbe2f7caf03d5a57ce4424ed0 100644
--- a/indra/newview/llfloaterurlentry.cpp
+++ b/indra/newview/llfloaterurlentry.cpp
@@ -204,6 +204,7 @@ void LLFloaterURLEntry::onBtnOK( void* userdata )
 	self->getChildView("ok_btn")->setEnabled(false);
 	self->getChildView("cancel_btn")->setEnabled(false);
 	self->getChildView("media_entry")->setEnabled(false);
+    self->getChildView("clear_btn")->setEnabled(false);
 }
 
 // static
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 7c957ac71212359526f97d3634ecdbb7800ec4dd..598a8d4c050cd9523643ce176372febfb2c0d53c 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -333,7 +333,7 @@ void LLHUDText::updateVisibility()
 
 	if (!mSourceObject)
 	{
-		//LL_WARNS() << "LLHUDText::updateScreenPos -- mSourceObject is NULL!" << LL_ENDL;
+		LL_WARNS() << "HUD text: mSourceObject is NULL,  mOnHUDAttachment: " << mOnHUDAttachment << LL_ENDL;
 		mVisible = TRUE;
 		if (mOnHUDAttachment)
 		{
diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp
index c2b29f36e8ab463731384da680ce6893bc0443b7..0fa3dc1110134feca200284177b87b5cffd008a4 100644
--- a/indra/newview/llimhandler.cpp
+++ b/indra/newview/llimhandler.cpp
@@ -60,7 +60,7 @@ void LLIMHandler::initChannel()
 }
 
 //--------------------------------------------------------------------------
-bool LLIMHandler::processNotification(const LLNotificationPtr& notification)
+bool LLIMHandler::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
     if(notification->isDND())
     {
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 1059324a1671bb44a17436a27052eb632dcd4714..3017d927e5771dc7aeb07e81fa5e5258fb1d855e 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -900,7 +900,7 @@ bool LLIMModel::LLIMSession::isOutgoingAdHoc() const
 
 bool LLIMModel::LLIMSession::isAdHoc()
 {
-	return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID));
+	return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID, TRUE));
 }
 
 bool LLIMModel::LLIMSession::isP2P()
@@ -910,7 +910,7 @@ bool LLIMModel::LLIMSession::isP2P()
 
 bool LLIMModel::LLIMSession::isGroupChat()
 {
-	return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID));
+	return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID, TRUE));
 }
 
 bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
@@ -1701,7 +1701,7 @@ LLUUID LLIMMgr::computeSessionID(
 		}
 	}
 
-	if (gAgent.isInGroup(session_id) && (session_id != other_participant_id))
+	if (gAgent.isInGroup(session_id, TRUE) && (session_id != other_participant_id))
 	{
 		LL_WARNS() << "Group session id different from group id: IM type = " << dialog << ", session id = " << session_id << ", group id = " << other_participant_id << LL_ENDL;
 	}
@@ -2035,7 +2035,7 @@ void LLCallDialog::setIcon(const LLSD& session_id, const LLSD& participant_id)
 	// *NOTE: 12/28/2009: check avaline calls: LLVoiceClient::isParticipantAvatar returns false for them
 	bool participant_is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id);
 
-	bool is_group = participant_is_avatar && gAgent.isInGroup(session_id);
+	bool is_group = participant_is_avatar && gAgent.isInGroup(session_id, TRUE);
 
 	LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon");
 	LLGroupIconCtrl* group_icon = getChild<LLGroupIconCtrl>("group_icon");
@@ -2330,7 +2330,7 @@ BOOL LLIncomingCallDialog::postBuild()
 	}
 
 	std::string call_type;
-	if (gAgent.isInGroup(session_id))
+	if (gAgent.isInGroup(session_id, TRUE))
 	{
 		LLStringUtil::format_map_t args;
 		LLGroupData data;
@@ -2507,8 +2507,8 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload
 				switch(type){
 				case IM_SESSION_CONFERENCE_START:
 				case IM_SESSION_GROUP_START:
-				case IM_SESSION_INVITE:		
-					if (gAgent.isInGroup(session_id))
+				case IM_SESSION_INVITE:
+					if (gAgent.isInGroup(session_id, TRUE))
 					{
 						LLGroupData data;
 						if (!gAgent.getGroupData(session_id, data)) break;
@@ -3055,7 +3055,7 @@ void LLIMMgr::inviteToSession(
 		notify_box_type = "VoiceInviteP2P";
 		voice_invite = TRUE;
 	}
-	else if ( gAgent.isInGroup(session_id) )
+	else if ( gAgent.isInGroup(session_id, TRUE) )
 	{
 		//only really old school groups have voice invitations
 		notify_box_type = "VoiceInviteGroup";
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 9cc67766ca0f54f63b0d72ba7d8623de920725a2..d239b23e83da281636e8f275bdf9cc57f9841ae5 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -255,7 +255,7 @@ void update_marketplace_folder_hierarchy(const LLUUID cat_id)
     return;
 }
 
-void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistency_enforcement)
+void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistency_enforcement, bool skip_clear_listing)
 {
     // When changing the marketplace status of an item, we usually have to change the status of all
     // folders in the same listing. This is because the display of each folder is affected by the
@@ -327,7 +327,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc
     else
     {
         // If the folder is outside the marketplace listings root, clear its SLM data if needs be
-        if (perform_consistency_enforcement && LLMarketplaceData::instance().isListed(cur_uuid))
+        if (perform_consistency_enforcement && !skip_clear_listing && LLMarketplaceData::instance().isListed(cur_uuid))
         {
             LL_INFOS("SLM") << "Disassociate as the listing folder is not under the marketplace folder anymore!!" << LL_ENDL;
             LLMarketplaceData::instance().clearListing(cur_uuid);
@@ -1843,7 +1843,7 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
 		result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1);
 	}
     
-    update_marketplace_category(cat->getUUID());
+    update_marketplace_category(cat->getUUID(), true, true);
     gInventory.notifyObservers();
     return result && !has_bad_items;
 }
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 2cb2b1e8773fa0a0e9d4dd75a903a3ebdcc57b8f..8915bfa1e050d26f224a88dc8b883ab6e83a4b68 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -68,7 +68,7 @@ void show_item_original(const LLUUID& item_uuid);
 void reset_inventory_filter();
 
 // Nudge the listing categories in the inventory to signal that their marketplace status changed
-void update_marketplace_category(const LLUUID& cat_id, bool perform_consistency_enforcement = true);
+void update_marketplace_category(const LLUUID& cat_id, bool perform_consistency_enforcement = true, bool skip_clear_listing = false);
 // Nudge all listing categories to signal that their marketplace status changed
 void update_all_marketplace_count();
 
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index 7c942e8b530a4d84b3d783050bdee824c62cea12..3566ca7a351b8bf467709619fed0681096f8e04b 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -1556,7 +1556,10 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y )
 	
 				LLVector3 object_axis;
 				getObjectAxisClosestToMouse(object_axis);
-				object_axis = object_axis * first_object_node->mSavedRotation;
+                if (first_object_node)
+                {
+                    object_axis = object_axis * first_object_node->mSavedRotation;
+                }
 	
 				// project onto constraint plane
 				object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index aa0c7fb73bcbe46d739a249d0fe020fedbf1c28a..044c76ce2c3c807d9a8483a5851cc2de0109c274 100644
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -1025,6 +1025,12 @@ void LLMarketplaceData::createSLMListingCoro(LLUUID folderId, LLUUID versionId,
     
     log_SLM_infos("Post /listings", status.getType(), result);
 
+    if (!result.has("listings") || !result["listings"].isArray() || result["listings"].size() == 0)
+    {
+        LL_INFOS("SLM") << "Received an empty response for folder " << folderId << LL_ENDL;
+        return;
+    }
+
     // Extract the info from the results
     for (LLSD::array_iterator it = result["listings"].beginArray();
         it != result["listings"].endArray(); ++it)
@@ -1092,6 +1098,19 @@ void LLMarketplaceData::updateSLMListingCoro(LLUUID folderId, S32 listingId, LLU
 
     log_SLM_infos("Put /listing", status.getType(), result);
 
+    if (!result.has("listings") || !result["listings"].isArray() || result["listings"].size() == 0)
+    {
+        LL_INFOS("SLM") << "Received an empty response for listing " << listingId << " folder " << folderId << LL_ENDL;
+        // Try to get listing more directly after a delay
+        const float FORCE_UPDATE_TIMEOUT = 5.0;
+        llcoro::suspendUntilTimeout(FORCE_UPDATE_TIMEOUT);
+        if (!LLApp::isExiting() && LLMarketplaceData::instanceExists())
+        {
+            getSLMListing(listingId);
+        }
+        return;
+    }
+
     // Extract the info from the Json string
     for (LLSD::array_iterator it = result["listings"].beginArray();
         it != result["listings"].endArray(); ++it)
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index a9e80ab5da107dcd7ea1ae10c3edaf030561c50a..6b50e1f800c8f64536f87be6f6b9f52f568cc1f9 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -253,27 +253,14 @@ LLModelPreview::~LLModelPreview()
     }
 }
 
-U32 LLModelPreview::calcResourceCost()
+void LLModelPreview::updateDimentionsAndOffsets()
 {
     assert_main_thread();
 
     rebuildUploadData();
 
-    //Upload skin is selected BUT check to see if the joints coming in from the asset were malformed.
-    if (mFMP && mFMP->childGetValue("upload_skin").asBoolean())
-    {
-        bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean();
-        if (uploadingJointPositions && !isRigValidForJointPositionUpload())
-        {
-            mFMP->childDisable("ok_btn");
-        }
-    }
-
     std::set<LLModel*> accounted;
-    U32 num_points = 0;
-    U32 num_hulls = 0;
 
-    F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f;
     mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f;
 
     if (mFMP && mFMP->childGetValue("upload_joints").asBoolean())
@@ -285,8 +272,6 @@ U32 LLModelPreview::calcResourceCost()
         getPreviewAvatar()->addPelvisFixup(mPelvisZOffset, fake_mesh_id);
     }
 
-    F32 streaming_cost = 0.f;
-    F32 physics_cost = 0.f;
     for (U32 i = 0; i < mUploadData.size(); ++i)
     {
         LLModelInstance& instance = mUploadData[i];
@@ -295,11 +280,6 @@ U32 LLModelPreview::calcResourceCost()
         {
             accounted.insert(instance.mModel);
 
-            LLModel::Decomposition& decomp =
-                instance.mLOD[LLModel::LOD_PHYSICS] ?
-                instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
-                instance.mModel->mPhysics;
-
             //update instance skin info for each lods pelvisZoffset 
             for (int j = 0; j<LLModel::NUM_LODS; ++j)
             {
@@ -308,58 +288,14 @@ U32 LLModelPreview::calcResourceCost()
                     instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset;
                 }
             }
-
-            std::stringstream ostr;
-            LLSD ret = LLModel::writeModel(ostr,
-                instance.mLOD[4],
-                instance.mLOD[3],
-                instance.mLOD[2],
-                instance.mLOD[1],
-                instance.mLOD[0],
-                decomp,
-                mFMP->childGetValue("upload_skin").asBoolean(),
-                mFMP->childGetValue("upload_joints").asBoolean(),
-                mFMP->childGetValue("lock_scale_if_joint_position").asBoolean(),
-                TRUE,
-                FALSE,
-                instance.mModel->mSubmodelID);
-
-            num_hulls += decomp.mHull.size();
-            for (U32 i = 0; i < decomp.mHull.size(); ++i)
-            {
-                num_points += decomp.mHull[i].size();
-            }
-
-            //calculate streaming cost
-            LLMatrix4 transformation = instance.mTransform;
-
-            LLVector3 position = LLVector3(0, 0, 0) * transformation;
-
-            LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position;
-            LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position;
-            LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position;
-            F32 x_length = x_transformed.normalize();
-            F32 y_length = y_transformed.normalize();
-            F32 z_length = z_transformed.normalize();
-            LLVector3 scale = LLVector3(x_length, y_length, z_length);
-
-            F32 radius = scale.length()*0.5f*debug_scale;
-
-            LLMeshCostData costs;
-            if (gMeshRepo.getCostData(ret, costs))
-            {
-                streaming_cost += costs.getRadiusBasedStreamingCost(radius);
-            }
         }
     }
 
     F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f;
 
-    mDetailsSignal(mPreviewScale[0] * scale, mPreviewScale[1] * scale, mPreviewScale[2] * scale, streaming_cost, physics_cost);
+    mDetailsSignal((F32)(mPreviewScale[0] * scale), (F32)(mPreviewScale[1] * scale), (F32)(mPreviewScale[2] * scale));
 
     updateStatusMessages();
-
-    return (U32)streaming_cost;
 }
 
 void LLModelPreview::rebuildUploadData()
@@ -1694,8 +1630,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
         }
     }
 
-    mResourceCost = calcResourceCost();
-
     LLVertexBuffer::unbind();
     LLGLSLShader::sNoFixedFunction = no_ff;
     if (shader)
@@ -2533,9 +2467,8 @@ void LLModelPreview::update()
     if (mDirty && mLodsQuery.empty())
     {
         mDirty = false;
-        mResourceCost = calcResourceCost();
+        updateDimentionsAndOffsets();
         refresh();
-        updateStatusMessages();
     }
 }
 
@@ -2811,8 +2744,6 @@ BOOL LLModelPreview::render()
                 {
                     // auto enable weight upload if weights are present
                     // (note: all these UI updates need to be somewhere that is not render)
-                    mViewOption["show_skin_weight"] = true;
-                    skin_weight = true;
                     fmp->childSetValue("upload_skin", true);
                     mFirstSkinUpdate = false;
                 }
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index 3664a27a72487d8c5faae31fd8ac7854fe9dd559..8e59c71a55070653252482579136dc64192d37cb 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -115,7 +115,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 {
     LOG_CLASS(LLModelPreview);
 
-    typedef boost::signals2::signal<void(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t;
+    typedef boost::signals2::signal<void(F32 x, F32 y, F32 z)> details_signal_t;
     typedef boost::signals2::signal<void(void)> model_loaded_signal_t;
     typedef boost::signals2::signal<void(bool)> model_updated_signal_t;
 
@@ -158,7 +158,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
     void generateNormals();
     void restoreNormals();
-    U32 calcResourceCost();
+    void updateDimentionsAndOffsets();
     void rebuildUploadData();
     void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
     void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
@@ -239,7 +239,6 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     LLVector3	mPreviewScale;
     S32			mPreviewLOD;
     S32			mPhysicsSearchLOD;
-    U32			mResourceCost;
     std::string mLODFile[LLModel::NUM_LODS];
     bool		mLoading;
     U32			mLoadState;
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 3209d23e430b7f127165c19fcee7444301871561..5215126789a9ece96e47ece0e32b59f2a241cf8d 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -398,6 +398,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
 	if (cell)
 	{
 		cell->setValue(prefix + fullname);
+		cell->setAltValue(name_item.alt_value());
 	}
 
 	dirtyColumns();
diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp
index 58a9b01a45944df8e232110ac02650f7eee0a33d..90b9cdc133c930ee5d106f3f97aa148ccad3aa3b 100644
--- a/indra/newview/llnotificationalerthandler.cpp
+++ b/indra/newview/llnotificationalerthandler.cpp
@@ -69,7 +69,7 @@ void LLAlertHandler::initChannel()
 }
 
 //--------------------------------------------------------------------------
-bool LLAlertHandler::processNotification(const LLNotificationPtr& notification)
+bool LLAlertHandler::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
 	if(mChannel.isDead())
 	{
@@ -131,7 +131,7 @@ LLViewerAlertHandler::LLViewerAlertHandler(const std::string& name, const std::s
 {
 }
 
-bool LLViewerAlertHandler::processNotification(const LLNotificationPtr& p)
+bool LLViewerAlertHandler::processNotification(const LLNotificationPtr& p, bool should_log)
 {
 	if (gHeadlessClient)
 	{
diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp
index 8fef102cf889236b44222e49954d84735ef7cf1a..f87ebf219b616aed672bf11d694cb3303d8eac51 100644
--- a/indra/newview/llnotificationgrouphandler.cpp
+++ b/indra/newview/llnotificationgrouphandler.cpp
@@ -62,7 +62,7 @@ void LLGroupHandler::initChannel()
 }
 
 //--------------------------------------------------------------------------
-bool LLGroupHandler::processNotification(const LLNotificationPtr& notification)
+bool LLGroupHandler::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
 	if(mChannel.isDead())
 	{
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index ef4aced2c712280fea33889d95d962f41d1865a2..ddc957c941462d9d99a2ac6520428a8aebfee7f6 100644
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -96,10 +96,10 @@ class LLNotificationHandler : public LLEventHandler, public LLNotificationChanne
 	// base interface functions
 	virtual void onAdd(LLNotificationPtr p) { processNotification(p); }
 	virtual void onChange(LLNotificationPtr p) { processNotification(p); }
-	virtual void onLoad(LLNotificationPtr p) { processNotification(p); }
+	virtual void onLoad(LLNotificationPtr p) { processNotification(p, false); }
 	virtual void onDelete(LLNotificationPtr p) { if (mChannel.get()) mChannel.get()->removeToastByNotificationID(p->getID());}
 
-	virtual bool processNotification(const LLNotificationPtr& notify) = 0;
+	virtual bool processNotification(const LLNotificationPtr& notify, bool should_log = true) = 0;
 };
 
 class LLSystemNotificationHandler : public LLNotificationHandler
@@ -136,7 +136,7 @@ class LLIMHandler : public LLCommunicationNotificationHandler
 public:
 	LLIMHandler();
 	virtual ~LLIMHandler();
-	bool processNotification(const LLNotificationPtr& p);
+	bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel();
@@ -152,7 +152,7 @@ class LLTipHandler : public LLSystemNotificationHandler
 	LLTipHandler();
 	virtual ~LLTipHandler();
 
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel();
@@ -170,7 +170,7 @@ class LLScriptHandler : public LLSystemNotificationHandler
 
 	virtual void onDelete(LLNotificationPtr p);
 	virtual void onChange(LLNotificationPtr p);
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 	virtual void addToastWithNotification(const LLNotificationPtr& p);
 
 protected:
@@ -188,7 +188,7 @@ class LLGroupHandler : public LLCommunicationNotificationHandler
 	LLGroupHandler();
 	virtual ~LLGroupHandler();
 	
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel();
@@ -204,7 +204,7 @@ class LLAlertHandler : public LLSystemNotificationHandler
 	virtual ~LLAlertHandler();
 
 	virtual void onChange(LLNotificationPtr p);
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel();
@@ -220,7 +220,7 @@ class LLViewerAlertHandler  : public LLSystemNotificationHandler
 	virtual ~LLViewerAlertHandler() {};
 
 	virtual void onDelete(LLNotificationPtr p) {};
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel() {};
@@ -238,7 +238,7 @@ class LLOfferHandler : public LLCommunicationNotificationHandler
 
 	virtual void onChange(LLNotificationPtr p);
 	virtual void onDelete(LLNotificationPtr notification);
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel();
@@ -256,7 +256,7 @@ class LLHintHandler : public LLSystemNotificationHandler
 	virtual void onAdd(LLNotificationPtr p);
 	virtual void onLoad(LLNotificationPtr p);
 	virtual void onDelete(LLNotificationPtr p);
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel() {};
@@ -271,7 +271,7 @@ class LLBrowserNotification : public LLSystemNotificationHandler
 	LLBrowserNotification();
 	virtual ~LLBrowserNotification() {}
 
-	virtual bool processNotification(const LLNotificationPtr& p);
+	virtual bool processNotification(const LLNotificationPtr& p, bool should_log = true);
 
 protected:
 	virtual void initChannel() {};
diff --git a/indra/newview/llnotificationhinthandler.cpp b/indra/newview/llnotificationhinthandler.cpp
index f1226c53ffe0b20c135f70d02e16a6d5bc858474..44ebc5ed47ed0e8e87177eb0ca9bc9aeb1a0400b 100644
--- a/indra/newview/llnotificationhinthandler.cpp
+++ b/indra/newview/llnotificationhinthandler.cpp
@@ -53,7 +53,7 @@ void LLHintHandler::onDelete(LLNotificationPtr p)
 	LLHints::getInstance()->hide(p);
 }
 
-bool LLHintHandler::processNotification(const LLNotificationPtr& p)
+bool LLHintHandler::processNotification(const LLNotificationPtr& p, bool should_log)
 {
 	return false;
 }
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index a9678b1e93818bc749e4af063adbb5cc230a2b83..201eaeb9f86eef3847e646d2efa49695cfd1bdf0 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -68,7 +68,7 @@ void LLOfferHandler::initChannel()
 }
 
 //--------------------------------------------------------------------------
-bool LLOfferHandler::processNotification(const LLNotificationPtr& notification)
+bool LLOfferHandler::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
 	if(mChannel.isDead())
 	{
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index ba831ab2ed3cf9995e6222a1ed88bb202cf45cf2..43c3ee3ce20f6f92894739d47fd1196c388127a9 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -92,7 +92,7 @@ void LLScriptHandler::addToastWithNotification(const LLNotificationPtr& notifica
 }
 
 //--------------------------------------------------------------------------
-bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
+bool LLScriptHandler::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
 	if(mChannel.isDead())
 	{
@@ -105,7 +105,7 @@ bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
 		initChannel();
 	}
 	
-	if (notification->canLogToIM())
+	if (should_log && notification->canLogToIM())
 	{
 		LLHandlerUtil::logToIMP2P(notification);
 	}
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index a6ef130cd006b61ad457a3921c284f538e5c79db..91f93067deb477532d44ccf49ad3a3f4496fc484 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -66,7 +66,7 @@ void LLTipHandler::initChannel()
 }
 
 //--------------------------------------------------------------------------
-bool LLTipHandler::processNotification(const LLNotificationPtr& notification)
+bool LLTipHandler::processNotification(const LLNotificationPtr& notification, bool should_log)
 {
 	if(mChannel.isDead())
 	{
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 1f7bfbbf8a1956f27e6e6e0547d838adc5f2fd40..4febb72c6c7ae97d1fdfd58b51ec5352a1b9c274 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -61,6 +61,8 @@ static LLPanelInjector<LLOutfitGallery> t_outfit_gallery("outfit_gallery");
 #define MAX_OUTFIT_PHOTO_WIDTH 256
 #define MAX_OUTFIT_PHOTO_HEIGHT 256
 
+const S32 GALLERY_ITEMS_PER_ROW_MIN = 2;
+
 LLOutfitGallery::LLOutfitGallery(const LLOutfitGallery::Params& p)
     : LLOutfitListBase(),
       mTexturesObserver(NULL),
@@ -95,7 +97,7 @@ LLOutfitGallery::Params::Params()
       item_width("item_width", 150),
       item_height("item_height", 175),
       item_horizontal_gap("item_horizontal_gap", 16),
-      items_in_row("items_in_row", 3),
+      items_in_row("items_in_row", GALLERY_ITEMS_PER_ROW_MIN),
       row_panel_width_factor("row_panel_width_factor", 166),
       gallery_width_factor("gallery_width_factor", 163)
 {
@@ -153,7 +155,7 @@ void LLOutfitGallery::updateRowsIfNeeded()
     {
         reArrangeRows(1);
     }
-    else if((mRowPanelWidth > (getRect().getWidth() + mItemHorizontalGap)) && mItemsInRow > 3)
+    else if((mRowPanelWidth > (getRect().getWidth() + mItemHorizontalGap)) && mItemsInRow > GALLERY_ITEMS_PER_ROW_MIN)
     {
         reArrangeRows(-1);
     }
diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp
index f95ab9928d54737ca17b52b204568f2abdbbcc43..18888f2723d0e1af3e69976b5815c172913d7fd2 100644
--- a/indra/newview/llpersistentnotificationstorage.cpp
+++ b/indra/newview/llpersistentnotificationstorage.cpp
@@ -150,7 +150,7 @@ void LLPersistentNotificationStorage::loadNotifications()
 		LLNotificationResponderPtr responder(createResponder(notification_params["name"], notification_params["responder"]));
 		notification->setResponseFunctor(responder);
 
-		instance.add(notification);
+		instance.load(notification);
 
 		// hide script floaters so they don't confuse the user and don't overlap startup toast
 		LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index f64db7beb54e73e77f43f0279aa74cacb74560d2..e7b756bf4a8c318ce7db60aac11b0e5bc044a14e 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -70,8 +70,12 @@ LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > LLTextureFetch::sCacheH
 
 LLTrace::SampleStatHandle<F32Seconds> LLTextureFetch::sCacheReadLatency("texture_cache_read_latency");
 LLTrace::SampleStatHandle<F32Seconds> LLTextureFetch::sTexDecodeLatency("texture_decode_latency");
+LLTrace::SampleStatHandle<F32Seconds> LLTextureFetch::sCacheWriteLatency("texture_write_latency");
 LLTrace::SampleStatHandle<F32Seconds> LLTextureFetch::sTexFetchLatency("texture_fetch_latency");
 
+LLTextureFetchTester* LLTextureFetch::sTesterp = NULL ;
+const std::string sTesterName("TextureFetchTester");
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // Introduction
@@ -438,6 +442,29 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 	// Threads:  Ttf
 	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
 
+	enum e_state // mState
+	{
+		// *NOTE:  Do not change the order/value of state variables, some code
+		// depends upon specific ordering/adjacency.
+
+		// NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
+		INVALID = 0,
+		INIT,
+		LOAD_FROM_TEXTURE_CACHE,
+		CACHE_POST,
+		LOAD_FROM_NETWORK,
+		LOAD_FROM_SIMULATOR,
+		WAIT_HTTP_RESOURCE,				// Waiting for HTTP resources
+		WAIT_HTTP_RESOURCE2,			// Waiting for HTTP resources
+		SEND_HTTP_REQ,					// Commit to sending as HTTP
+		WAIT_HTTP_REQ,					// Request sent, wait for completion
+		DECODE_IMAGE,
+		DECODE_IMAGE_UPDATE,
+		WRITE_TO_CACHE,
+		WAIT_ON_WRITE,
+		DONE
+	};
+
 protected:
 	LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type,
 						 const std::string& url, const LLUUID& id, const LLHost& host,
@@ -517,28 +544,6 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 		}
 	
 private:
-	enum e_state // mState
-	{
-		// *NOTE:  Do not change the order/value of state variables, some code
-		// depends upon specific ordering/adjacency.
-		
-		// NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
-		INVALID = 0,
-		INIT,
-		LOAD_FROM_TEXTURE_CACHE,
-		CACHE_POST,
-		LOAD_FROM_NETWORK,
-		LOAD_FROM_SIMULATOR,
-		WAIT_HTTP_RESOURCE,				// Waiting for HTTP resources
-		WAIT_HTTP_RESOURCE2,			// Waiting for HTTP resources
-		SEND_HTTP_REQ,					// Commit to sending as HTTP
-		WAIT_HTTP_REQ,					// Request sent, wait for completion
-		DECODE_IMAGE,
-		DECODE_IMAGE_UPDATE,
-		WRITE_TO_CACHE,
-		WAIT_ON_WRITE,
-		DONE
-	};
 	enum e_request_state // mSentRequest
 	{
 		UNSENT = 0,
@@ -551,7 +556,7 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 		CAN_WRITE = 1,
 		SHOULD_WRITE = 2
 	};
-	static const char* sStateDescs[];
+
 	e_state mState;
 	void setState(e_state new_state);
 
@@ -579,10 +584,15 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 	LLFrameTimer mFetchDeltaTimer;
 	LLTimer mCacheReadTimer;
     LLTimer mDecodeTimer;
+	LLTimer mCacheWriteTimer;
     LLTimer mFetchTimer;
+	LLTimer mStateTimer;
 	F32 mCacheReadTime; // time for cache read only
     F32 mDecodeTime;    // time for decode only
+	F32 mCacheWriteTime;
     F32 mFetchTime;     // total time from req to finished fetch
+	std::map<S32, F32> mStateTimersMap;
+	F32 mSkippedStatesTime;
 	LLTextureCache::handle_t    mCacheReadHandle,
 								mCacheWriteHandle;
 	S32                         mRequestedSize,
@@ -866,8 +876,7 @@ bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
 
 //////////////////////////////////////////////////////////////////////////////
 
-//static
-const char* LLTextureFetchWorker::sStateDescs[] = {
+const char* sStateDescs[] = {
 	"INVALID",
 	"INIT",
 	"LOAD_FROM_TEXTURE_CACHE",
@@ -885,6 +894,9 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
 	"DONE"
 };
 
+const std::set<S32> LOGGED_STATES = { LLTextureFetchWorker::LOAD_FROM_TEXTURE_CACHE, LLTextureFetchWorker::LOAD_FROM_NETWORK, LLTextureFetchWorker::LOAD_FROM_SIMULATOR, 
+										LLTextureFetchWorker::WAIT_HTTP_REQ, LLTextureFetchWorker::DECODE_IMAGE_UPDATE, LLTextureFetchWorker::WAIT_ON_WRITE };
+
 // static
 volatile bool LLTextureFetch::svMetricsDataBreak(true);	// Start with a data break
 
@@ -916,6 +928,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mLoadedDiscard(-1),
 	  mDecodedDiscard(-1),
 	  mCacheReadTime(0.f),
+	  mCacheWriteTime(0.f),
 	  mDecodeTime(0.f),
       mFetchTime(0.f),
 	  mCacheReadHandle(LLTextureCache::nullHandle()),
@@ -924,6 +937,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mRequestedOffset(0),
 	  mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE),
 	  mFileSize(0),
+	  mSkippedStatesTime(0),
 	  mCachedSize(0),
 	  mLoaded(FALSE),
 	  mSentRequest(UNSENT),
@@ -1184,6 +1198,13 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 	if (mState == INIT)
 	{		
+		mStateTimer.reset();
+		mFetchTimer.reset();
+		for(auto i : LOGGED_STATES) 
+		{
+			mStateTimersMap[i] = 0;
+		}
+		mSkippedStatesTime = 0;
 		mRawImage = NULL ;
 		mRequestedDiscard = -1;
 		mLoadedDiscard = -1;
@@ -1241,9 +1262,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				++mCacheReadCount;
 				std::string filename = mUrl.substr(7, std::string::npos);
 				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
+				mCacheReadTimer.reset();  
 				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
 																		  offset, size, responder);
-                mCacheReadTimer.reset();                
+              
 			}
 			else if ((mUrl.empty() || mFTType==FTT_SERVER_BAKE) && mFetcher->canLoadFromCache())
 			{
@@ -1251,9 +1273,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 				++mCacheReadCount;
 				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
-				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
-																		  offset, size, responder);
 				mCacheReadTimer.reset();
+				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
+																		  offset, size, responder);;
 			}
 			else if(!mUrl.empty() && mCanUseHTTP)
 			{
@@ -1275,6 +1297,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				mCacheReadHandle = LLTextureCache::nullHandle();
 				setState(CACHE_POST);
                 add(LLTextureFetch::sCacheHit, 1.0);
+				mCacheReadTime = mCacheReadTimer.getElapsedTimeF32();
 				// fall through
 			}
 			else
@@ -1888,7 +1911,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			LL_DEBUGS(LOG_TXT) << mID << " DECODE_IMAGE abort: mLoadedDiscard < 0" << LL_ENDL;
 			return true;
 		}
-
+		mDecodeTimer.reset();
 		mRawImage = NULL;
 		mAuxImage = NULL;
 		llassert_always(mFormattedImage.notNull());
@@ -1982,6 +2005,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
         // be protected by work mutex and won't be safe to use here nor in cache worker.
         // So make sure users of getRequestFinished() does not attempt to modify image while
         // fetcher is working
+		mCacheWriteTimer.reset();
 		mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority,
 																  mFormattedImage->getData(), datasize,
 																  mFileSize, mRawImage, mDecodedDiscard, responder);
@@ -1992,6 +2016,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	{
 		if (writeToCacheComplete())
 		{
+			mCacheWriteTime = mCacheWriteTimer.getElapsedTimeF32();
 			setState(DONE);
 			// fall through
 		}
@@ -2500,7 +2525,6 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag
 	mDecoded = TRUE;
 // 	LL_INFOS(LOG_TXT) << mID << " : DECODE COMPLETE " << LL_ENDL;
 	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-	mCacheReadTime = mCacheReadTimer.getElapsedTimeF32();
 }																		// -Mw
 
 //////////////////////////////////////////////////////////////////////////////
@@ -2625,6 +2649,17 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 		}
 		mOriginFetchSource = mFetchSource;
 	}
+
+	// If that test log has ben requested but not yet created, create it
+	if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName))
+	{
+		sTesterp = new LLTextureFetchTester() ;
+		if (!sTesterp->isValid())
+		{
+			delete sTesterp;
+			sTesterp = NULL;
+		}
+	}
 }
 
 LLTextureFetch::~LLTextureFetch()
@@ -2966,20 +3001,51 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
 		}
 		else if (worker->checkWork())
 		{
+			F32 decode_time;
+			F32 fetch_time;
+			F32 cache_read_time;
+			F32 cache_write_time;
+			S32 file_size;
+			std::map<S32, F32> logged_state_timers;
+			F32 skipped_states_time;
 			worker->lockWorkMutex();									// +Mw
 			last_http_get_status = worker->mGetStatus;
 			discard_level = worker->mDecodedDiscard;
 			raw = worker->mRawImage;
 			aux = worker->mAuxImage;
-			sample(sTexDecodeLatency, worker->mDecodeTime);
-            sample(sTexFetchLatency, worker->mFetchTime);
-            sample(sCacheReadLatency, worker->mCacheReadTime);
+
+			decode_time = worker->mDecodeTime;
+			fetch_time = worker->mFetchTime;
+			cache_read_time = worker->mCacheReadTime;
+			cache_write_time = worker->mCacheWriteTime;
+			file_size = worker->mFileSize;
             worker->mCacheReadTimer.reset();
             worker->mDecodeTimer.reset();
+			worker->mCacheWriteTimer.reset();
             worker->mFetchTimer.reset();
+			logged_state_timers = worker->mStateTimersMap;
+			skipped_states_time = worker->mSkippedStatesTime;
+			worker->mStateTimer.reset();
 			res = true;
 			LL_DEBUGS(LOG_TXT) << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL;
 			worker->unlockWorkMutex();									// -Mw
+			
+			sample(sTexDecodeLatency, decode_time);
+			sample(sTexFetchLatency, fetch_time);
+			sample(sCacheReadLatency, cache_read_time);
+			sample(sCacheWriteLatency, cache_write_time);
+			
+			static LLCachedControl<F32> min_time_to_log(gSavedSettings, "TextureFetchMinTimeToLog", 2.f);
+			if (fetch_time > min_time_to_log)
+			{
+				//LL_INFOS() << "fetch_time: " << fetch_time << " cache_read_time: " << cache_read_time << " decode_time: " << decode_time << " cache_write_time: " << cache_write_time << LL_ENDL;
+
+				LLTextureFetchTester* tester = (LLTextureFetchTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+				if (tester)
+				{
+					tester->updateStats(logged_state_timers, fetch_time, skipped_states_time, file_size) ;
+				}
+			}
 		}
 		else
 		{
@@ -3464,6 +3530,21 @@ void LLTextureFetchWorker::setState(e_state new_state)
 
 //		LL_INFOS(LOG_TXT) << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << LL_ENDL;
 	}
+	
+	F32 d_time = mStateTimer.getElapsedTimeF32();
+	if (d_time >= 0.0001F)
+	{
+		if (LOGGED_STATES.count(mState))
+		{
+			mStateTimersMap[mState] = d_time;
+		}
+		else
+		{
+			mSkippedStatesTime += d_time;
+		}
+	}
+	
+	mStateTimer.reset();
 	mState = new_state;
 }
 
@@ -3679,7 +3760,7 @@ void LLTextureFetch::dump()
 		LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass();
 		LL_INFOS(LOG_TXT) << " ID: " << worker->mID
 						  << " PRI: " << llformat("0x%08x",wreq->getPriority())
-						  << " STATE: " << worker->sStateDescs[worker->mState]
+						  << " STATE: " << sStateDescs[worker->mState]
 						  << LL_ENDL;
 	}
 
@@ -5121,4 +5202,40 @@ void LLTextureFetchDebugger::callbackHTTP(FetchEntry & fetch, LLCore::HttpRespon
 //End LLTextureFetchDebugger
 ///////////////////////////////////////////////////////////////////////////////////////////
 
+LLTextureFetchTester::LLTextureFetchTester() : LLMetricPerformanceTesterBasic(sTesterName) 
+{
+	mTextureFetchTime = 0;
+	mSkippedStatesTime = 0;
+	mFileSize = 0;
+}
+
+LLTextureFetchTester::~LLTextureFetchTester()
+{
+	outputTestResults();
+	LLTextureFetch::sTesterp = NULL;
+}
+
+//virtual 
+void LLTextureFetchTester::outputTestRecord(LLSD *sd) 
+{	
+	std::string currentLabel = getCurrentLabelName();
+
+	(*sd)[currentLabel]["Texture Fetch Time"]	= (LLSD::Real)mTextureFetchTime;
+	(*sd)[currentLabel]["File Size"]			= (LLSD::Integer)mFileSize;
+	(*sd)[currentLabel]["Skipped States Time"]	= (LLSD::String)llformat("%.6f", mSkippedStatesTime);
+
+	for(auto i : LOGGED_STATES) 
+	{
+		(*sd)[currentLabel][sStateDescs[i]] = mStateTimersMap[i];
+	}
+}
+
+void LLTextureFetchTester::updateStats(const std::map<S32, F32> state_timers, const F32 fetch_time, const F32 skipped_states_time, const S32 file_size)
+{
+	mTextureFetchTime = fetch_time;
+	mStateTimersMap = state_timers;
+	mFileSize = file_size;
+	mSkippedStatesTime = skipped_states_time;
+	outputTestResults();
+}
 
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 2aa194e1418a2e592c85a088b2966f56db402be8..bf6732963f99c8e22ca152bb9801f61e4d3d5d2c 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -50,6 +50,7 @@ class LLHost;
 class LLViewerAssetStats;
 class LLTextureFetchDebugger;
 class LLTextureCache;
+class LLTextureFetchTester;
 
 // Interface class
 
@@ -312,6 +313,7 @@ class LLTextureFetch : public LLWorkerThread
     static LLTrace::CountStatHandle<F64>        sCacheAttempt;
     static LLTrace::SampleStatHandle<F32Seconds> sCacheReadLatency;
     static LLTrace::SampleStatHandle<F32Seconds> sTexDecodeLatency;
+	static LLTrace::SampleStatHandle<F32Seconds> sCacheWriteLatency;
     static LLTrace::SampleStatHandle<F32Seconds> sTexFetchLatency;
     static LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > sCacheHitRate;
 
@@ -403,6 +405,9 @@ class LLTextureFetch : public LLWorkerThread
 		FROM_HTTP_ONLY,
 		INVALID_SOURCE
 	};
+
+	static LLTextureFetchTester* sTesterp;
+
 private:
 	//debug use
 	LLTextureFetchDebugger* mFetchDebugger;
@@ -635,5 +640,26 @@ class LLTextureFetchDebugger : public LLCore::HttpHandler
 public:
 	static bool isEnabled() {return sDebuggerEnabled;}
 };
+
+
+class LLTextureFetchTester : public LLMetricPerformanceTesterBasic
+{
+public:
+	LLTextureFetchTester();
+	~LLTextureFetchTester();
+
+	void updateStats(const std::map<S32, F32> states_timers, const F32 fetch_time, const F32 other_states_time, const S32 file_size);
+
+protected:
+	/*virtual*/ void outputTestRecord(LLSD* sd);
+
+private:
+
+	F32 mTextureFetchTime;
+	F32 mSkippedStatesTime;
+	S32 mFileSize;
+
+	std::map<S32, F32> mStateTimersMap;
+};
 #endif // LL_LLTEXTUREFETCH_H
 
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 0ac8d487e48795c81cf97a3811c184718f4354f0..1e960ed5368c63fa5c0a47c15744843f27a15727 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -815,7 +815,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 			gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
 			LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
 		}
-		else if ((!object || !object->isAttachment() || object->getClickAction() != CLICK_ACTION_DISABLED)
+		else if ((!object || object->getClickAction() != CLICK_ACTION_DISABLED)
 				 && ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch()))
 				 && (!object || !object->isAvatar()))
 		{
diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h
index 782c523d4f68a87c6d7a9b91a6e89d45a07c37b0..3b4f8987100069727df93030225efb671336e3b8 100644
--- a/indra/newview/llviewerjoystick.h
+++ b/indra/newview/llviewerjoystick.h
@@ -47,6 +47,7 @@ class LLViewerJoystick : public LLSingleton<LLViewerJoystick>
 {
 	LLSINGLETON(LLViewerJoystick);
 	virtual ~LLViewerJoystick();
+    LOG_CLASS(LLViewerJoystick);
 
 public:
 	void init(bool autoenable);
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index c99fccc3c68f45e5d73f16dc7a77a6f93b4706e9..55a8489f250aae89a67d7988811ebffb518dc4bc 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -3220,19 +3220,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL;
 
 			std::string cursor = plugin->getCursorName();
-
-			if(cursor == "arrow")
-				mLastSetCursor = UI_CURSOR_ARROW;
-			else if(cursor == "ibeam")
-				mLastSetCursor = UI_CURSOR_IBEAM;
-			else if(cursor == "splith")
-				mLastSetCursor = UI_CURSOR_SIZEWE;
-			else if(cursor == "splitv")
-				mLastSetCursor = UI_CURSOR_SIZENS;
-			else if(cursor == "hand")
-				mLastSetCursor = UI_CURSOR_HAND;
-			else // for anything else, default to the arrow
-				mLastSetCursor = UI_CURSOR_ARROW;
+			mLastSetCursor = getCursorFromString(cursor);
 		}
 		break;
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 17bf82e8297be6082b0fd9128e799d2de7a42f3a..4ca449b6acaaeba3181106fc795a4f2b31075171 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -6274,6 +6274,32 @@ class LLAvatarToggleMyProfile : public view_listener_t
 	}
 };
 
+class LLAvatarToggleSearch : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		LLFloater* instance = LLFloaterReg::findInstance("search");
+		if (LLFloater::isMinimized(instance))
+		{
+			instance->setMinimized(FALSE);
+			instance->setFocus(TRUE);
+		}
+		else if (!LLFloater::isShown(instance))
+		{
+			LLFloaterReg::showInstance("search");
+		}
+		else if (!instance->hasFocus() && !instance->getIsChrome())
+		{
+			instance->setFocus(TRUE);
+		}
+		else
+		{
+			instance->closeFloater();
+		}
+		return true;
+	}
+};
+
 class LLAvatarResetSkeleton: public view_listener_t
 {
     bool handleEvent(const LLSD& userdata)
@@ -9422,6 +9448,7 @@ void initialize_menus()
 	enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
 	view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
 	view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile");
+	view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch");
 	view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton");
 	view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton");
 	view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations");
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 8986a34e60c513854584fe8510f4bf9b77a570b1..27fbf39673a044c5b311c8a762f4269aa2aa6b95 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1453,7 +1453,12 @@ void LLViewerRegion::clearCachedVisibleObjects()
 	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin();
 		iter != mImpl->mActiveSet.end(); ++iter)
 	{
-		LLDrawable* drawablep = (LLDrawable*)(*iter)->getEntry()->getDrawable();
+        LLVOCacheEntry* vo_entry = *iter;
+        if (!vo_entry || !vo_entry->getEntry())
+        {
+            continue;
+        }
+        LLDrawable* drawablep = (LLDrawable*)vo_entry->getEntry()->getDrawable();
 	
 		if(drawablep && !drawablep->getParent())
 		{
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 0642615c50a76ab24fc694cb959d6755b420ea42..0ca4a3712dd7bf32b2159b995257e5fc11c7c051 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -206,6 +206,7 @@ LLTrace::EventStatHandle<F64Seconds >	AVATAR_EDIT_TIME("avataredittime", "Second
 
 LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > OBJECT_CACHE_HIT_RATE("object_cache_hits");
 
+LLTrace::EventStatHandle<F64Seconds >	TEXTURE_FETCH_TIME("texture_fetch_time");
 }
 
 LLViewerStats::LLViewerStats() 
@@ -386,15 +387,6 @@ void update_statistics()
 	add(LLStatViewer::ASSET_UDP_DATA_RECEIVED, F64Bits(gTransferManager.getTransferBitsIn(LLTCT_ASSET)));
 	gTransferManager.resetTransferBitsIn(LLTCT_ASSET);
 
-	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
-	{
-		gTextureTimer.pause();
-	}
-	else
-	{
-		gTextureTimer.unpause();
-	}
-	
 	sample(LLStatViewer::VISIBLE_AVATARS, LLVOAvatar::sNumVisibleAvatars);
 	LLWorld::getInstance()->updateNetStats();
 	LLWorld::getInstance()->requestCacheMisses();
@@ -416,6 +408,19 @@ void update_statistics()
 	}
 }
 
+void update_texture_time()
+{
+	if (gTextureList.isPrioRequestsFetched())
+	{
+		gTextureTimer.pause();
+	}
+	else
+	{		
+		gTextureTimer.unpause();
+	}
+
+	record(LLStatViewer::TEXTURE_FETCH_TIME, gTextureTimer.getElapsedTimeF32());
+}
 /*
  * The sim-side LLSD is in newsim/llagentinfo.cpp:forwardViewerStats.
  *
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 72ce3366646f9acd6c409615b7a7d21b19bef112..4468e44ea8917020e2050f5c979390b36b222a7e 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -294,6 +294,7 @@ static const F32 SEND_STATS_PERIOD = 300.0f;
 // The following are from (older?) statistics code found in appviewer.
 void update_statistics();
 void send_viewer_stats(bool include_preferences);
+void update_texture_time();
 
 extern LLFrameTimer gTextureTimer;
 extern U32Bytes	gTotalTextureData;
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 07997e02a5c2ba680f4c1564a9577af2c24b3208..0de49073c8fa062421de07f776e3709da1fb49cb 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -415,6 +415,7 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	BOOL		isFullyLoaded() const;
 
 	BOOL        hasFetcher() const { return mHasFetcher;}
+	bool        isFetching() const { return mIsFetching;}
 	void        setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
 
 	void        forceToDeleteRequest();
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 38fccba169429023140b39a3ef6d506999f244f1..37344056e10ac4c600c4d84a48ebfb60e0f0757c 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -203,6 +203,9 @@ static std::string get_texture_list_name()
 
 void LLViewerTextureList::doPrefetchImages()
 {
+	gTextureTimer.start();
+	gTextureTimer.pause();
+
 	if (LLAppViewer::instance()->getPurgeCache())
 	{
 		// cache was purged, no point
@@ -1400,6 +1403,33 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl
 	return max_texmem;
 }
 
+bool LLViewerTextureList::isPrioRequestsFetched()
+{
+	static LLCachedControl<F32> prio_threshold(gSavedSettings, "TextureFetchUpdatePriorityThreshold", 0.0f);
+	static LLCachedControl<F32> fetching_textures_threshold(gSavedSettings, "TextureListFetchingThreshold", 0.97f);
+	S32 fetching_tex_count = 0;
+	S32 tex_count_threshold = gTextureList.mImageList.size() * (1 - fetching_textures_threshold);
+
+	for (LLViewerTextureList::image_priority_list_t::iterator iter = gTextureList.mImageList.begin();
+		iter != gTextureList.mImageList.end(); )
+	{
+		LLPointer<LLViewerFetchedTexture> imagep = *iter++;
+		if (imagep->getDecodePriority() > prio_threshold)
+		{
+			if (imagep->hasFetcher() || imagep->isFetching())
+			{
+				fetching_tex_count++;
+				if (fetching_tex_count >= tex_count_threshold)
+				{
+					return false;
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
 const S32Megabytes VIDEO_CARD_FRAMEBUFFER_MEM(12);
 const S32Megabytes MIN_MEM_FOR_NON_TEXTURE(512);
 void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem)
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index 281d23c671c862e11b58ddd7c11d8ae029535ab1..fead2e52b29ea9381b465afd30ebc122ce349bbb 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -138,6 +138,8 @@ class LLViewerTextureList
 
 	static S32Megabytes getMinVideoRamSetting();
 	static S32Megabytes getMaxVideoRamSetting(bool get_recommended, float mem_multiplier);
+
+	static bool isPrioRequestsFetched();
 	
 private:
 	void updateImagesDecodePriorities();
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 92e8f8026dd4670474c4388135c56859c7d43fc8..050fb454ad37e36d41faae651c990ee0c4306f1f 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -215,6 +215,7 @@
 
 #if LL_WINDOWS
 #include <tchar.h> // For Unicode conversion methods
+#include "llwindowwin32.h" // For AltGr handling
 #endif
 
 //
@@ -2890,57 +2891,64 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
     if (keyboard_focus
         && !gFocusMgr.getKeystrokesOnly())
     {
-#ifdef LL_WINDOWS
-        // On windows Alt Gr key generates additional Ctrl event, as result handling situations
-        // like 'AltGr + D' will result in 'Alt+Ctrl+D'. If it results in WM_CHAR, don't let it
-        // pass into menu or it will trigger 'develop' menu assigned to this combination on top
-        // of character handling.
-        // Alt Gr can be additionally modified by Shift
-        const MASK alt_gr = MASK_CONTROL | MASK_ALT;
-        if ((mask & alt_gr) != 0
-            && key >= 0x30
-            && key <= 0x5A
-            && (GetKeyState(VK_RMENU) & 0x8000) != 0
-            && (GetKeyState(VK_RCONTROL) & 0x8000) == 0) // ensure right control is not pressed, only left one
+        LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(keyboard_focus);
+        if (cur_focus && cur_focus->acceptsTextInput())
         {
-            // Alt Gr key is represented as right alt and left control.
-            // Any alt+ctrl combination is treated as Alt Gr by TranslateMessage() and
-            // will generate a WM_CHAR message, but here we only treat virtual Alt Graph
-            // key by checking if this specific combination has unicode char.
-            //
-            // I decided to handle only virtual RAlt+LCtrl==AltGr combination to minimize
-            // impact on menu, but the right way might be to handle all Alt+Ctrl calls.
-
-            BYTE keyboard_state[256];
-            if (GetKeyboardState(keyboard_state))
+#ifdef LL_WINDOWS
+            // On windows Alt Gr key generates additional Ctrl event, as result handling situations
+            // like 'AltGr + D' will result in 'Alt+Ctrl+D'. If it results in WM_CHAR, don't let it
+            // pass into menu or it will trigger 'develop' menu assigned to this combination on top
+            // of character handling.
+            // Alt Gr can be additionally modified by Shift
+            const MASK alt_gr = MASK_CONTROL | MASK_ALT;
+            LLWindowWin32 *window = static_cast<LLWindowWin32*>(mWindow);
+            U32 raw_key = window->getRawWParam();
+            if ((mask & alt_gr) != 0
+                && ((raw_key >= 0x30 && raw_key <= 0x5A) //0-9, plus normal chartacters
+                    || (raw_key >= 0xBA && raw_key <= 0xE4)) // Misc/OEM characters that can be covered by AltGr, ex: -, =, ~
+                && (GetKeyState(VK_RMENU) & 0x8000) != 0
+                && (GetKeyState(VK_RCONTROL) & 0x8000) == 0) // ensure right control is not pressed, only left one
             {
-                const int char_count = 6;
-                wchar_t chars[char_count];
-                HKL layout = GetKeyboardLayout(0);
-                // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable,
-                // but since we already did a TranslateMessage() in gatherInput(), this
-                // should have no negative effect
-                int res = ToUnicodeEx(key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout);
-                if (res == 1 && chars[0] >= 0x20)
+                // Alt Gr key is represented as right alt and left control.
+                // Any alt+ctrl combination is treated as Alt Gr by TranslateMessage() and
+                // will generate a WM_CHAR message, but here we only treat virtual Alt Graph
+                // key by checking if this specific combination has unicode char.
+                //
+                // I decided to handle only virtual RAlt+LCtrl==AltGr combination to minimize
+                // impact on menu, but the right way might be to handle all Alt+Ctrl calls.
+
+                BYTE keyboard_state[256];
+                if (GetKeyboardState(keyboard_state))
                 {
-                    // Let it fall through to character handler and get a WM_CHAR.
-                    return TRUE;
+                    const int char_count = 6;
+                    wchar_t chars[char_count];
+                    HKL layout = GetKeyboardLayout(0);
+                    // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable,
+                    // but since we already did a TranslateMessage() in gatherInput(), this
+                    // should have no negative effect
+                    // ToUnicodeEx works with virtual key codes
+                    int res = ToUnicodeEx(raw_key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout);
+                    if (res == 1 && chars[0] >= 0x20)
+                    {
+                        // Let it fall through to character handler and get a WM_CHAR.
+                        return TRUE;
+                    }
                 }
             }
-        }
 #endif
 
-        if (!(mask & (MASK_CONTROL | MASK_ALT)))
-        {
-            // We have keyboard focus, and it's not an accelerator
-            if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
-            {
-                return keyboard_focus->handleKey(key, mask, FALSE);
-            }
-            else if (key < 0x80)
+            if (!(mask & (MASK_CONTROL | MASK_ALT)))
             {
-                // Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
-                return TRUE;
+                // We have keyboard focus, and it's not an accelerator
+                if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+                {
+                    return keyboard_focus->handleKey(key, mask, FALSE);
+                }
+                else if (key < 0x80)
+                {
+                    // Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
+                    return TRUE;
+                }
             }
         }
     }
diff --git a/indra/newview/res-sdl/lltoolzoomout.BMP b/indra/newview/res-sdl/lltoolzoomout.BMP
index 7f958383ab820ad0860cbf3482cba82216492bba..5bdf96f80d16aa3f742d3fbdd6ef44eff54e10fc 100644
Binary files a/indra/newview/res-sdl/lltoolzoomout.BMP and b/indra/newview/res-sdl/lltoolzoomout.BMP differ
diff --git a/indra/newview/res-sdl/sizeall.BMP b/indra/newview/res-sdl/sizeall.BMP
new file mode 100644
index 0000000000000000000000000000000000000000..03d9bf4654030a405d8553640c77c19072c85f89
Binary files /dev/null and b/indra/newview/res-sdl/sizeall.BMP differ
diff --git a/indra/newview/res/lltoolzoomout.cur b/indra/newview/res/lltoolzoomout.cur
index b33e68d1a6a9d6c13a8787b310321dc016c95381..21e0ee9702e5cf183e55bab391bc361a2b37dcd8 100644
Binary files a/indra/newview/res/lltoolzoomout.cur and b/indra/newview/res/lltoolzoomout.cur differ
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index ff2d8b4943abfa9f26144b80c46a82621bc6b8fe..4ee26a312a985c66f7c6fb01d092d47aeda054b5 100755
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -99,6 +99,7 @@ END
 TOOLGRAB                CURSOR                  "lltoolgrab.cur"
 TOOLLAND                CURSOR                  "lltoolland.cur"
 TOOLZOOMIN              CURSOR                  "lltoolzoomin.cur"
+TOOLZOOMOUT             CURSOR                  "lltoolzoomout.cur"
 TOOLCREATE              CURSOR                  "lltoolcreate.cur"
 ARROWDRAG               CURSOR                  "llarrowdrag.cur"
 ARROW                   CURSOR                  "llarrow.cur"
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 35d43854879a82c409e54951c3d7ab8392f78458..2abd8ec5c05fee2ca1e92dabe272d88aa5e0b2f1 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
@@ -36,16 +36,14 @@
                   stat="FramePixelDifference"
                   bar_max="100"
                   tick_spacing="10"
-                  unit_scale="100"
-                  precision="0"/>
+                  unit_scale="100"/>
         <stat_bar name="bandwidth"
                   label="UDP Data Received"
                   orientation="horizontal"
                   unit_label="kbps"
                   stat="activemessagedatareceived"
                   bar_max="5000"
-                  tick_spacing="500"
-                  precision="0"/>
+                  tick_spacing="500"/>
 			  <stat_bar name="packet_loss"
                   label="Packet Loss"
                   orientation="horizontal"
@@ -53,9 +51,7 @@
                   stat="packetslostpercentstat"
                   bar_max="5"
                   tick_spacing="0.5"
-                  precision="3"
-                  show_bar="false"
-                  show_mean="true"/>
+                  show_bar="false"/>
 		  </stat_view>
 <!--Advanced Section-->
       <stat_view name="advanced"
@@ -73,7 +69,6 @@
                     stat="numobjectsstat"
                     bar_max="50000"
                     tick_spacing="5000"
-                    precision="0"
                     show_bar="false"/>
           <stat_bar name="newobjs"
                     label="New Objects"
@@ -109,12 +104,48 @@
           <stat_bar name="texture_cache_read_latency"
                     label="Cache Read Latency"
                     orientation="horizontal"
-                    unit_label="msec"
+                    unit_label="sec"
                     stat="texture_cache_read_latency"
                     bar_max="1000.f"
                     tick_spacing="100"
                     show_history="true"
                     show_bar="false"/>
+          <stat_bar name="texture_decode_latency"
+                    label="Cache Decode Latency"
+                    orientation="horizontal"
+                    unit_label="sec"
+                    stat="texture_decode_latency"
+                    bar_max="1000.f"
+                    tick_spacing="100"
+                    show_history="true"
+                    show_bar="false"/>
+          <stat_bar name="texture_decode_latency"
+                    label="Cache Write Latency"
+                    orientation="horizontal"
+                    unit_label="sec"
+                    stat="texture_write_latency"
+                    bar_max="1000.f"
+                    tick_spacing="100"
+                    show_history="true"
+                    show_bar="false"/>
+          <stat_bar name="texture_fetch_latency"
+                    label="Cache Fetch Latency"
+                    orientation="horizontal"
+                    unit_label="sec"
+                    stat="texture_fetch_latency"
+                    bar_max="1000.f"
+                    tick_spacing="100"
+                    show_history="true"
+                    show_bar="false"/>
+          <stat_bar name="texture_fetch_time"
+                    label="Cache Fetch Time"
+                    orientation="horizontal"
+                    unit_label="sec"
+                    stat="texture_fetch_time"
+                    bar_max="1000.f"
+                    tick_spacing="100"
+                    show_history="true"
+                    show_bar="false"/>
           <stat_bar name="numimagesstat"
                     label="Count"
                     orientation="horizontal"
@@ -142,7 +173,6 @@
                     unit_label="/sec" 
                     bar_max="1024.f" 
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			    <stat_bar name="packetsoutstat"
                     label="Packets Out"
@@ -151,7 +181,6 @@
                     unit_label="/sec"  
                     bar_max="1024.f" 
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			    <stat_bar name="objectdatareceived"
                     label="Objects"
@@ -160,7 +189,6 @@
                     unit_label="kbps"
                     bar_max="1024.f"
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			    <stat_bar name="texturedatareceived"
                     label="Texture"
@@ -169,7 +197,6 @@
                     unit_label="kbps"
                     bar_max="1024.f"
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			    <stat_bar name="assetudpdatareceived"
                     label="Asset"
@@ -178,7 +205,6 @@
                     unit_label="kbps"
                     bar_max="1024.f"
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			    <stat_bar name="layersdatareceived"
                     label="Layers"
@@ -187,7 +213,6 @@
                     unit_label="kbps"
                     bar_max="1024.f"
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			    <stat_bar name="messagedatain"
                     label="Actual In"
@@ -196,7 +221,6 @@
                     unit_label="kbps"
                     bar_max="1024.f"
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			    <stat_bar name="messagedataout"
                     label="Actual Out"
@@ -205,7 +229,6 @@
                     unit_label="kbps"
                     bar_max="1024.f"
                     tick_spacing="128.f"
-                    precision="1"
                     show_bar="false"/>
 			  </stat_view>
 		  </stat_view>
@@ -218,77 +241,61 @@
                   label="Objects"
                   orientation="horizontal"
                   stat="simobjects"
-                  precision="0"
                   bar_max="30000.f" 
                   tick_spacing="5000.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_bar name="simactiveobjects"
                   label="Active Objects"
                   orientation="horizontal"
                   stat="simactiveobjects"
-                  precision="0"
                   bar_max="5000.f" 
                   tick_spacing="750.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_bar name="simactivescripts"
                   label="Active Scripts"
                   orientation="horizontal"
                   stat="simactivescripts"
-                  precision="0"
                   bar_max="15000.f" 
                   tick_spacing="1875.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_bar name="siminpps"
                   label="Packets In"
                   orientation="horizontal"
                   stat="siminpps"
                   unit_label="pps"
-                  precision="0"
                   bar_max="2000.f" 
                   tick_spacing="250.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_bar name="simoutpps"
                   label="Packets Out"
                   orientation="horizontal"
                   stat="simoutpps"
                   unit_label="pps" 
-                  precision="0"
                   bar_max="2000.f" 
                   tick_spacing="250.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_bar name="simpendingdownloads"
                   label="Pending Downloads"
                   orientation="horizontal"
                   stat="simpendingdownloads"
-                  precision="0"
                   bar_max="800.f" 
                   tick_spacing="100.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_bar name="simpendinguploads"
                   label="Pending Uploads"
                   orientation="horizontal"
                   stat="simpendinguploads"
-                  precision="0"
                   bar_max="100.f" 
                   tick_spacing="25.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_bar name="simtotalunackedbytes"
                   label="Total Unacked Bytes"
                   orientation="horizontal"
                   stat="simtotalunackedbytes"
                   unit_label="kb"
-                  precision="1"
                   bar_max="100000.f" 
                   tick_spacing="25000.f"
-                  show_bar="false"
-                  show_mean="false"/>
+                  show_bar="false"/>
 			  <stat_view name="simperf"
                    label="Time (ms)"
                    show_label="true">
@@ -297,81 +304,65 @@
                     orientation="horizontal"
                     stat="simframemsec"
                     unit_label="ms"
-                    precision="3"
                     bar_max="40.f" 
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
 			    <stat_bar name="simnetmsec"
                     label="Net Time"
                     orientation="horizontal"
                     stat="simnetmsec"
                     unit_label="ms"
-                    precision="3"
                     bar_max="40.f" 
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
 			    <stat_bar name="simsimphysicsmsec"
                     label="Physics Time"
                     orientation="horizontal"
                     stat="simsimphysicsmsec"
                     unit_label="ms"
-                    precision="3"
                     bar_max="40.f" 
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
 			    <stat_bar name="simsimothermsec"
                     label="Simulation Time"
                     orientation="horizontal"
                     stat="simsimothermsec"
                     unit_label="ms"
-                    precision="3"
                     bar_max="40.f" 
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
 			    <stat_bar name="simagentmsec"
                     label="Agent Time"
                     orientation="horizontal"
                     stat="simagentmsec"
                     unit_label="ms"
-                    precision="3"
-                    bar_max="40.f" 
+                     bar_max="40.f" 
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
 			    <stat_bar name="simimagesmsec"
                     label="Images Time"
                     orientation="horizontal"
                     stat="simimagesmsec"
                     unit_label="ms"
-                    precision="3"
                     bar_max="40.f" 
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
 			    <stat_bar name="simscriptmsec"
                     label="Script Time"
                     orientation="horizontal"
                     stat="simscriptmsec"
                     unit_label="ms"
-                    precision="3"
                     bar_max="40.f" 
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
           <stat_bar name="simsparemsec"
                     label="Spare Time"
                     orientation="horizontal"
                     stat="simsparemsec"
                     unit_label="ms"
-                    precision="3"
                     bar_max="40.f"
                     tick_spacing="10.f"
-                    show_bar="false"
-                    show_mean="false"/>
+                    show_bar="false"/>
 <!--2nd level time blocks under 'Details' second-->
           <stat_view name="timedetails"
                      label="Time Details (ms)"
@@ -381,51 +372,41 @@
                       orientation="horizontal"
                       stat="simsimphysicsstepmsec"
                       unit_label="ms"
-                      precision="3"
                       bar_max="40.f"
                       tick_spacing="10.f"
-                      show_bar="false"
-                      show_mean="false"/>
+                      show_bar="false"/>
             <stat_bar name="simsimphysicsshapeupdatemsec"
                       label="  Update Phys Shapes"
                       orientation="horizontal"
                       stat="simsimphysicsshapeupdatemsec"
                       unit_label="ms"
-                      precision="3"
-                      bar_max="40.f"
+                        bar_max="40.f"
                       tick_spacing="10.f"
-                      show_bar="false"
-                      show_mean="false"/>
+                      show_bar="false"/>
             <stat_bar name="simsimphysicsothermsec"
                       label="  Physics Other"
                       orientation="horizontal"
                       stat="simsimphysicsothermsec"
                       unit_label="ms"
-                      precision="3"
                       bar_max="40.f"
                       tick_spacing="10.f"
-                      show_bar="false"
-                      show_mean="false"/>
+                      show_bar="false"/>
             <stat_bar name="simsleepmsec"
                       label="  Sleep Time"
                       orientation="horizontal"
                       stat="simsleepmsec"
                       unit_label="ms"
-                      precision="3"
                       bar_max="40.f"
                       tick_spacing="10.f"
-                      show_bar="false"
-                      show_mean="false"/>
+                      show_bar="false"/>
             <stat_bar name="simpumpiomsec"
                       label="  Pump IO"
                       orientation="horizontal"
                       stat="simpumpiomsec"
                       unit_label="ms"
-                      precision="3"
                       bar_max="40.f"
                       tick_spacing="10.f"
-                      show_bar="false"
-                      show_mean="false"/>
+                      show_bar="false"/>
           </stat_view>
 			  </stat_view>
 		  </stat_view>
diff --git a/indra/newview/skins/default/xui/en/floater_texture_fetch_debugger.xml b/indra/newview/skins/default/xui/en/floater_texture_fetch_debugger.xml
index 1ea256b8b310dd5cfb18b0ee4a0efde237d3124f..9278a1a59824da2736c21a7eda8a0745a22a2358 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_fetch_debugger.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_fetch_debugger.xml
@@ -317,6 +317,18 @@
     <button.commit_callback
 		function="TexFetchDebugger.Close" />
   </button>
+  <button
+   follows="left|top"
+   height="22"
+   label="Reset Fetching Time"
+   layout="topleft"
+   left_pad="175"
+   name="reset_time_btn"
+   top_delta="0"
+   width="120">
+    <button.commit_callback
+		function="TexFetchDebugger.ResetFetchTime" />
+  </button>
   <button
    follows="left|top"
    height="20"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 2a5f88539595bd3601ee59d333bbc0600236aab6..8d7cfe1116f75079f329abb816d677c6ee1861cb 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -703,8 +703,7 @@
              function="Floater.Visible"
              parameter="search" />
             <menu_item_check.on_click
-             function="Floater.Toggle"
-             parameter="search" />
+             function="Avatar.ToggleSearch"/>
             </menu_item_check>
         <menu_item_separator/>
         <menu_item_call
@@ -774,7 +773,7 @@
              label="My land holdings..."
              name="My Land">
             <menu_item_call.on_click
-             function="Floater.Show"
+             function="Floater.ShowOrBringToFront"
              parameter="land_holdings" />
       </menu_item_call>
         <menu_item_call
diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml
index 898e92e0305421adbd11f201d2003751899e966f..d1cfb8ead6ee0876ba8487d32174670f0ee3e7dd 100644
--- a/indra/newview/skins/default/xui/en/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_general.xml
@@ -51,7 +51,7 @@
      left_delta="50"
      name="version_channel_text"
      top_delta="0"
-     width="225">
+     width="400">
         unknown
     </text>
     <text
diff --git a/scripts/metrics/slp_conv.py b/scripts/metrics/slp_conv.py
new file mode 100644
index 0000000000000000000000000000000000000000..27f922b74ac3dd66e8015fbef72f80e81851f905
--- /dev/null
+++ b/scripts/metrics/slp_conv.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+"""\
+@file   slp_conv.py
+@author Callum Prentice
+@date   2021-01-26
+@brief  Convert a Second Life Performance (SLP) file generated
+        by the Viewer into an comma separated value (CSV) file
+        for import into spreadsheets and other data analytics tools.
+
+$LicenseInfo:firstyear=2021&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2021, 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$
+"""
+
+from llbase import llsd
+import argparse
+
+parser = argparse.ArgumentParser(
+    description="Converts Viewer SLP files into CSV for import into spreadsheets etc."
+)
+parser.add_argument(
+    "infilename",
+    help="Name of SLP file to read",
+)
+parser.add_argument(
+    "outfilename",
+    help="Name of CSV file to create",
+)
+args = parser.parse_args()
+
+with open(args.infilename, "r") as slp_file:
+    slps = slp_file.readlines()
+    print "Reading from %s - %d items" % (args.infilename, len(slps))
+
+    with open(args.outfilename, "w") as csv_file:
+
+        print "Writing to %s" % args.outfilename
+
+        for index, each_slp in enumerate(slps):
+            slp_entry = llsd.parse(each_slp)
+
+            first_key = slp_entry.keys()[0]
+
+            # first entry so write column headers
+            if index == 0:
+                line = ""
+                for key, value in slp_entry[first_key].iteritems():
+                    line += key
+                    line += ", "
+                csv_file.write("entry, %s, \n" % line)
+            # write line of data
+            line = ""
+            for key, value in slp_entry[first_key].iteritems():
+                line += str(value)
+                line += ", "
+            csv_file.write("%s, %s, \n" % (first_key, str(line)))