diff --git a/.hgtags b/.hgtags
index 9dd6783e6b9fb1ce10087f5ec12c8d805cc43db0..06d289325d6be8cc12b23f01fdfc4b7ab72d9e13 100755
--- a/.hgtags
+++ b/.hgtags
@@ -540,3 +540,4 @@ ad0e15543836d64d6399d28b32852510435e344a 5.1.0-release
 04538b8157c1f5cdacd9403f0a395452d4a93689 5.1.6-release
 ac3b1332ad4f55b7182a8cbcc1254535a0069f75 5.1.7-release
 23ea0fe36fadf009a60c080392ce80e4bf8af8d9 5.1.8-release
+52422540bfe54b71155aa455360bee6e3ef1fd96 5.1.9-release
diff --git a/autobuild.xml b/autobuild.xml
index bd1b88b2ebfa7d5d9dc7eac631540c1577e126d6..6ab50ab1839367738561bc102184b60c445eb379 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -3326,9 +3326,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f45c0a5e7b4601b355e163bf62f5718e</string>
+              <string>ce95944fb842849108102263a25fc794</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/20587/147509/viewer_manager-1.0.517052-darwin64-517052.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/23237/178332/viewer_manager-1.0.518840-darwin64-518840.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3350,9 +3350,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d2443caf062697430071d458a965f611</string>
+              <string>642f847a9ac45551af65a55826974334</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/20588/147516/viewer_manager-1.0.517052-windows-517052.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/23236/178338/viewer_manager-1.0.518840-windows-518840.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3363,7 +3363,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>1.0.517052</string>
+        <string>1.0.518840</string>
       </map>
       <key>vlc-bin</key>
       <map>
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index e5089f028fe1cb9f12c4eaf72b76e9634a3b7d9a..60359ca304df1aceedb38150dc52e5f149e8ffb0 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -1566,9 +1566,10 @@ BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
         delete_and_clear_array(mCollisionVolumes);
         mNumCollisionVolumes = 0;
 
-        mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
+        mCollisionVolumes = new(std::nothrow) LLAvatarJointCollisionVolume[num];
         if (!mCollisionVolumes)
         {
+            LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL;
             return FALSE;
         }
         
diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp
index 85d3caecced74075b00bd2395b6d51055d64df50..4daf34eca62df135b74f92952b6bbf3611e2efa2 100644
--- a/indra/llappearance/llwearabletype.cpp
+++ b/indra/llappearance/llwearabletype.cpp
@@ -94,7 +94,7 @@ LLWearableDictionary::LLWearableDictionary()
 
 	addEntry(LLWearableType::WT_PHYSICS,      new WearableEntry("physics",     "New Physics",		LLAssetType::AT_CLOTHING, 	LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
 
-	addEntry(LLWearableType::WT_INVALID,      new WearableEntry("invalid",     "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
+	addEntry(LLWearableType::WT_INVALID,      new WearableEntry("invalid",     "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
 	addEntry(LLWearableType::WT_NONE,      	  new WearableEntry("none",        "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
 }
 
diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp
index 77e57b14f5d05d0979ff965cd95456422dfb4780..6ab61689fd0532a8f67c65576ed2cd0c7bfcda94 100644
--- a/indra/llaudio/llaudiodecodemgr.cpp
+++ b/indra/llaudio/llaudiodecodemgr.cpp
@@ -265,9 +265,19 @@ BOOL LLVorbisDecodeState::initDecode()
 		mInFilep = NULL;
 		return FALSE;
 	}
-	
-	mWAVBuffer.reserve(size_guess);
-	mWAVBuffer.resize(WAV_HEADER_SIZE);
+
+	try
+	{
+		mWAVBuffer.reserve(size_guess);
+		mWAVBuffer.resize(WAV_HEADER_SIZE);
+	}
+	catch (std::bad_alloc)
+	{
+		LL_WARNS("AudioEngine") << "Out of memory when trying to alloc buffer: " << size_guess << LL_ENDL;
+		delete mInFilep;
+		mInFilep = NULL;
+		return FALSE;
+	}
 
 	{
 		// write the .wav format header
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index f12c64023ab66a9be6013fd294f879d484439169..330d81298565d08fb5689571af6d17e2a0cebdf8 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -579,8 +579,15 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact
 	else
 	{
 		anim_file_size = anim_file->getSize();
-		anim_data = new U8[anim_file_size];
-		success = anim_file->read(anim_data, anim_file_size);	/*Flawfinder: ignore*/
+		anim_data = new(std::nothrow) U8[anim_file_size];
+		if (anim_data)
+		{
+			success = anim_file->read(anim_data, anim_file_size);	/*Flawfinder: ignore*/
+		}
+		else
+		{
+			LL_WARNS() << "Failed to allocate buffer: " << anim_file_size << mID << LL_ENDL;
+		}
 		delete anim_file;
 		anim_file = NULL;
 	}
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 2bab557e3e52864e55e53f37a4bd12da71a7fb8d..d455805aea189d2dd51c1e4b7fcd05255c27e003 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -96,6 +96,8 @@ LLAssetDictionary::LLAssetDictionary()
     addEntry(LLAssetType::AT_WIDGET,            new AssetEntry("WIDGET",            "widget",   "widget",           false,      false,      false));
     addEntry(LLAssetType::AT_PERSON,            new AssetEntry("PERSON",            "person",   "person",           false,      false,      false));
     addEntry(LLAssetType::AT_SETTINGS,          new AssetEntry("SETTINGS",          "settings", "settings blob",    true,       true,       false)); 
+	
+	addEntry(LLAssetType::AT_UNKNOWN,           new AssetEntry("UNKNOWN",           "invalid",  NULL,               false,      false,      false));
     addEntry(LLAssetType::AT_NONE,              new AssetEntry("NONE",              "-1",		NULL,		  		FALSE,		FALSE,		FALSE));
 
 };
@@ -159,7 +161,7 @@ LLAssetType::EType LLAssetType::lookup(const std::string& type_name)
 			return iter->first;
 		}
 	}
-	return AT_NONE;
+	return AT_UNKNOWN;
 }
 
 // static
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 32502d5e33c247e1bf6b38edfe454a87d8405937..652c548d59a54c91998540a10679534e35a22621 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -139,7 +139,7 @@ class LL_COMMON_API LLAssetType
 			// | 4. ADD TO LLViewerAssetType.cpp                         |
 			// | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp  |
 			// +*********************************************************+
-
+		AT_UNKNOWN = 255,
 		AT_NONE = -1
 	};
 
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 29de79dc6423efc167280989a1d86fe966aa8030..06c7aef8ab2fbce110eef72aed0b93d78e0e71cd 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -40,6 +40,7 @@
 # include <unistd.h>
 #endif // !LL_WINDOWS
 #include <vector>
+#include "string.h"
 
 #include "llapp.h"
 #include "llapr.h"
@@ -530,21 +531,16 @@ namespace LLError
 		mTags(new const char* [tag_count]),
 		mTagCount(tag_count)
 	{
-		for (int i = 0; i < tag_count; i++)
-		{
-			mTags[i] = tags[i];
-		}
-
 		switch (mLevel)
 		{
-		case LEVEL_DEBUG:		mLevelString = "DEBUG:";	break;
-		case LEVEL_INFO:		mLevelString = "INFO:";		break;
-		case LEVEL_WARN:		mLevelString = "WARNING:";	break;
-		case LEVEL_ERROR:		mLevelString = "ERROR:";	break;
-		default:				mLevelString = "XXX:";		break;
+        case LEVEL_DEBUG: mLevelString = "DEBUG";   break;
+        case LEVEL_INFO:  mLevelString = "INFO";    break;
+        case LEVEL_WARN:  mLevelString = "WARNING"; break;
+        case LEVEL_ERROR: mLevelString = "ERROR";   break;
+        default:          mLevelString = "XXX";     break;
 		};
 
-		mLocationString = llformat("%s(%d) :", abbreviateFile(mFile).c_str(), mLine);
+		mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine);
 #if LL_WINDOWS
 		// DevStudio: __FUNCTION__ already includes the full class name
 #else
@@ -558,13 +554,23 @@ namespace LLError
 			mFunctionString = className(mClassInfo) + "::";
 		}
 #endif
-		mFunctionString += std::string(mFunction) + ":";
-        const std::string tag_hash("#");
+		mFunctionString += std::string(mFunction);
+
+		for (int i = 0; i < tag_count; i++)
+		{
+            if (strchr(tags[i], ' '))
+            {
+                LL_ERRS() << "Space is not allowed in a log tag at " << mLocationString << LL_ENDL;
+            }
+			mTags[i] = tags[i];
+		}
+
+        mTagString.append("#");
+        // always construct a tag sequence; will be just a single # if no tag
 		for (size_t i = 0; i < mTagCount; i++)
 		{
-            mTagString.append(tag_hash);
 			mTagString.append(mTags[i]);
-            mTagString.append((i == mTagCount - 1) ? ";" : ",");
+            mTagString.append("#");
 		}
 	}
 
@@ -899,7 +905,46 @@ namespace LLError
 
 namespace
 {
-	void writeToRecorders(const LLError::CallSite& site, const std::string& message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true)
+    void addEscapedMessage(std::ostream& out, const std::string& message)
+    {
+        size_t written_out = 0;
+        size_t all_content = message.length();
+        size_t escape_char_index; // always relative to start of message
+        // Use find_first_of to find the next character in message that needs escaping
+        for ( escape_char_index = message.find_first_of("\\\n\r");
+              escape_char_index != std::string::npos && written_out < all_content;
+              // record what we've written this iteration, scan for next char that needs escaping
+              written_out = escape_char_index + 1, escape_char_index = message.find_first_of("\\\n\r", written_out)
+             )
+        {
+            // found a character that needs escaping, so write up to that with the escape prefix
+            // note that escape_char_index is relative to the start, not to the written_out offset
+            out << message.substr(written_out, escape_char_index - written_out) << '\\';
+
+            // write out the appropriate second character in the escape sequence
+            char found = message[escape_char_index];
+            switch ( found )
+            {
+            case '\\':
+                out << '\\';
+                break;
+            case '\n':
+                out << 'n';
+                break;
+            case '\r':
+                out << 'r';
+                break;
+            }
+        }
+
+        if ( written_out < all_content ) // if the loop above didn't write everything
+        {
+            // write whatever was left
+            out << message.substr(written_out, std::string::npos);
+        }
+    }
+
+	void writeToRecorders(const LLError::CallSite& site, const std::string& escaped_message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true)
 	{
 		LLError::ELevel level = site.mLevel;
 		LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
@@ -912,32 +957,37 @@ namespace
 			
 			std::ostringstream message_stream;
 
-			if (show_time && r->wantsTime() && s->mTimeFunction != NULL)
+			if (r->wantsTime() && s->mTimeFunction != NULL)
 			{
-				message_stream << s->mTimeFunction() << " ";
+				message_stream << s->mTimeFunction();
 			}
-
+            message_stream << " ";
+            
 			if (show_level && r->wantsLevel())
             {
-				message_stream << site.mLevelString << " ";
+				message_stream << site.mLevelString;
             }
+            message_stream << " ";
 				
-			if (show_tags && r->wantsTags())
+			if (r->wantsTags())
 			{
 				message_stream << site.mTagString;
 			}
+            message_stream << " ";
 
-            if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation))
+            if (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)
             {
-                message_stream << site.mLocationString << " ";
+                message_stream << site.mLocationString;
             }
+            message_stream << " ";
 
 			if (show_function && r->wantsFunctionName())
 			{
-				message_stream << site.mFunctionString << " ";
+				message_stream << site.mFunctionString;
 			}
+            message_stream << " : ";
 
-			message_stream << message;
+			message_stream << escaped_message;
 
 			r->recordMessage(level, message_stream.str());
 		}
@@ -1180,11 +1230,6 @@ namespace LLError
 			delete out;
 		}
 
-		if (site.mLevel == LEVEL_ERROR)
-		{
-			writeToRecorders(site, "error", true, true, true, false, false);
-		}
-		
 		std::ostringstream message_stream;
 
 		if (site.mPrintOnce)
@@ -1210,8 +1255,8 @@ namespace LLError
 			}
 		}
 		
-		message_stream << message;
-		
+		addEscapedMessage(message_stream, message);
+
 		writeToRecorders(site, message_stream.str());
 		
 		if (site.mLevel == LEVEL_ERROR  &&  s->mCrashFunction)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index ceb1fd2c5f02aaee8685546c9857b0e8b1410bd6..0a7822955503a9a3a62de67a8b82ff1f83b841c6 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -146,11 +146,22 @@ const int LL_ERR_NOERR = 0;
 	
 	will result in messages like:
 	
-		WARN: LLFoo::doSomething: called with a big value for i: 283
+		WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283
 	
+    the syntax is:
+        <timestamp> SPACE <level> SPACE <tags> SPACE <location> SPACE <function> SPACE COLON SPACE <message>
+
+    where each SPACE is a single space character; note that if a field is empty (such as when no
+    tags are specified), all the SPACEs are still present.
+
+    The tags must be a single word (may not contain a space); if more than one tag is specified,
+    they are all surrounded by '#' ( #FooTag#BarTag# ).
+
 	Which messages are logged and which are suppressed can be controlled at run
-	time from the live file logcontrol.xml based on function, class and/or 
-	source file.  See etc/logcontrol-dev.xml for details.
+	time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml
+    A copy of that file named logcontrol-dev.xml can be made in the users personal settings
+    directory; that will override the installed default file.  See the logcontrol.xml
+    file or http://wiki.secondlife.com/wiki/Logging_System_Overview for configuration details.
 	
 	Lastly, logging is now very efficient in both compiled code and execution
 	when skipped.  There is no need to wrap messages, even debugging ones, in
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 446c312ca9e89b0f5d0d9cf41d2b0306356ecefb..a618a1cc709b75bdf7e6b65020ca361083b6556d 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -610,7 +610,7 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl
 				value =  (uint64_t)(( uint8_t *)&value); 
 			else
 			{
-				LL_WARNS("Unknown type returned from sysctl!") << LL_ENDL;
+				LL_WARNS() << "Unknown type returned from sysctl" << LL_ENDL;
 			}
 		}
 				
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 1f4aa9b3a63ab122976ba2ee359ee944bf4719b4..f066e9a4cdd43006a531453e6bae33a19b8fa586 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -249,9 +249,10 @@ void LLThread::shutdown()
             // This thread just wouldn't stop, even though we gave it time
             //LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL;
             // Put a stake in its heart.
-            delete mRecorder;
-
             apr_thread_exit(mAPRThreadp, -1);
+            delete mRecorder;
+            mRecorder = NULL;
+            mStatus = STOPPED;
             return;
         }
         mAPRThreadp = NULL;
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index 20de2054547b97d051393ce2b06c85d73ea08a1e..ce0dbce07596088c9a98e7eec1adc405e0c279ce 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -36,6 +36,26 @@
 
 #include "../test/lltut.h"
 
+enum LogFieldIndex
+{
+    TIME_FIELD,
+    LEVEL_FIELD,
+    TAGS_FIELD,
+    LOCATION_FIELD,
+    FUNCTION_FIELD,
+    MSG_FIELD
+};
+
+static const char* FieldName[] = 
+{
+    "TIME",
+    "LEVEL",
+    "TAGS",
+    "LOCATION",
+    "FUNCTION",
+    "MSG"
+};
+
 namespace
 {
 #ifdef __clang__
@@ -58,7 +78,7 @@ namespace tut
 	class TestRecorder : public LLError::Recorder
 	{
 	public:
-		TestRecorder() { mWantsTime = false; }
+		TestRecorder() { mWantsTime = false; mWantsTags = true; }
 		virtual ~TestRecorder() {  }
 
 		virtual void recordMessage(LLError::ELevel level,
@@ -133,13 +153,64 @@ namespace tut
 			ensure_equals("message count", countMessages(), expectedCount);
 		}
 
-		void ensure_message_contains(int n, const std::string& expectedText)
-		{
-			std::ostringstream test_name;
-			test_name << "testing message " << n;
-
-			ensure_contains(test_name.str(), message(n), expectedText);
-		}
+        std::string message_field(int msgnum, LogFieldIndex fieldnum)
+        {
+            std::ostringstream test_name;
+            test_name << "testing message " << msgnum << ", not enough messages";            
+            tut::ensure(test_name.str(), msgnum < countMessages());
+
+            std::string msg(message(msgnum));
+
+            std::string field_value;
+
+            // find the start of the field; fields are separated by a single space
+            size_t scan = 0;
+            int on_field = 0;
+            while ( scan < msg.length() && on_field < fieldnum )
+            {
+                // fields are delimited by one space
+                if ( ' ' == msg[scan] )
+                {
+                    if ( on_field < FUNCTION_FIELD )
+                    {
+                        on_field++;
+                    }
+                    // except function, which may have embedded spaces so ends with " : "
+                    else if (   ( on_field == FUNCTION_FIELD ) 
+                             && ( ':' == msg[scan+1] && ' ' == msg[scan+2] )
+                             )
+                    {
+                        on_field++;
+                        scan +=2;
+                    }
+                }
+                scan++;
+            }
+            size_t start_field = scan;
+            size_t fieldlen = 0;
+            if ( fieldnum < FUNCTION_FIELD )
+            {
+                fieldlen = msg.find(' ', start_field) - start_field;
+            }
+            else if ( fieldnum == FUNCTION_FIELD ) 
+            {
+                fieldlen = msg.find(" : ", start_field) - start_field;                
+            }
+            else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end
+            {
+                fieldlen = msg.length() - start_field;
+            }
+
+            return msg.substr(start_field, fieldlen);
+        }
+        
+		void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText)
+         {
+             std::ostringstream test_name;
+             test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n  message: \"" << message(msgnum) << "\"\n  ";
+
+             ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText);
+         }
 
 		void ensure_message_does_not_contain(int n, const std::string& expectedText)
 		{
@@ -162,8 +233,8 @@ namespace tut
 		LL_INFOS() << "test" << LL_ENDL;
 		LL_INFOS() << "bob" << LL_ENDL;
 
-		ensure_message_contains(0, "test");
-		ensure_message_contains(1, "bob");
+		ensure_message_field_equals(0, MSG_FIELD, "test");
+		ensure_message_field_equals(1, MSG_FIELD, "bob");
 	}
 }
 
@@ -171,11 +242,10 @@ namespace
 {
 	void writeSome()
 	{
-		LL_DEBUGS() << "one" << LL_ENDL;
-		LL_INFOS() << "two" << LL_ENDL;
-		LL_WARNS() << "three" << LL_ENDL;
-		// fatal messages write out an additional "error" message
-		LL_ERRS() << "four" << LL_ENDL;
+		LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL;
+		LL_INFOS("WriteTag") << "two" << LL_ENDL;
+		LL_WARNS("WriteTag") << "three" << LL_ENDL;
+		LL_ERRS("WriteTag") << "four" << LL_ENDL;
 	}
 };
 
@@ -187,37 +257,41 @@ namespace tut
 	{
 		LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
 		writeSome();
-		ensure_message_contains(0, "one");
-		ensure_message_contains(1, "two");
-		ensure_message_contains(2, "three");
-		ensure_message_contains(3, "error");
-		ensure_message_contains(4, "four");
-		ensure_message_count(5);
+		ensure_message_field_equals(0, MSG_FIELD, "one");
+		ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG");
+		ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#");
+		ensure_message_field_equals(1, MSG_FIELD, "two");
+		ensure_message_field_equals(1, LEVEL_FIELD, "INFO");
+		ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#");
+		ensure_message_field_equals(2, MSG_FIELD, "three");
+		ensure_message_field_equals(2, LEVEL_FIELD, "WARNING");
+		ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#");
+		ensure_message_field_equals(3, MSG_FIELD, "four");
+		ensure_message_field_equals(3, LEVEL_FIELD, "ERROR");
+		ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#");
+		ensure_message_count(4);
 
 		LLError::setDefaultLevel(LLError::LEVEL_INFO);
 		writeSome();
-		ensure_message_contains(5, "two");
-		ensure_message_contains(6, "three");
-		ensure_message_contains(7, "error");
-		ensure_message_contains(8, "four");
-		ensure_message_count(9);
+		ensure_message_field_equals(4, MSG_FIELD, "two");
+		ensure_message_field_equals(5, MSG_FIELD, "three");
+		ensure_message_field_equals(6, MSG_FIELD, "four");
+		ensure_message_count(7);
 
 		LLError::setDefaultLevel(LLError::LEVEL_WARN);
 		writeSome();
-		ensure_message_contains(9, "three");
-		ensure_message_contains(10, "error");
-		ensure_message_contains(11, "four");
-		ensure_message_count(12);
+		ensure_message_field_equals(7, MSG_FIELD, "three");
+		ensure_message_field_equals(8, MSG_FIELD, "four");
+		ensure_message_count(9);
 
 		LLError::setDefaultLevel(LLError::LEVEL_ERROR);
 		writeSome();
-		ensure_message_contains(12, "error");
-		ensure_message_contains(13, "four");
-		ensure_message_count(14);
+		ensure_message_field_equals(9, MSG_FIELD, "four");
+		ensure_message_count(10);
 
 		LLError::setDefaultLevel(LLError::LEVEL_NONE);
 		writeSome();
-		ensure_message_count(14);
+		ensure_message_count(10);
 	}
 
 	template<> template<>
@@ -225,12 +299,11 @@ namespace tut
 		// error type string in output
 	{
 		writeSome();
-		ensure_message_contains(0, "DEBUG: ");
-		ensure_message_contains(1, "INFO: ");
-		ensure_message_contains(2, "WARNING: ");
-		ensure_message_does_not_contain(3, "ERROR");
-		ensure_message_contains(4, "ERROR: ");
-		ensure_message_count(5);
+		ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG");
+		ensure_message_field_equals(1, LEVEL_FIELD, "INFO");
+		ensure_message_field_equals(2, LEVEL_FIELD, "WARNING");
+		ensure_message_field_equals(3, LEVEL_FIELD, "ERROR");
+		ensure_message_count(4);
 	}
 
 	template<> template<>
@@ -280,7 +353,7 @@ namespace
 	{
 		std::ostringstream location;
 		location << LLError::abbreviateFile(__FILE__)
-				 << "(" << line << ") : ";
+				 << "(" << line << ")";
 
 		return location.str();
 	}
@@ -321,7 +394,7 @@ namespace tut
 		writeReturningLocation();
 
 		ensure_message_does_not_contain(0, location);
-		ensure_message_contains(1, location);
+		ensure_message_field_equals(1, LOCATION_FIELD, location);
 		ensure_message_does_not_contain(2, location);
 	}
 }
@@ -496,13 +569,13 @@ namespace tut
 	void ErrorTestObject::test<7>()
 	{
 		outerLogger();
-		ensure_message_contains(0, "inside");
-		ensure_message_contains(1, "outside(moo)");
+		ensure_message_field_equals(0, MSG_FIELD, "inside");
+		ensure_message_field_equals(1, MSG_FIELD, "outside(moo)");
 		ensure_message_count(2);
 
 		metaLogger();
-		ensure_message_contains(2, "logging");
-		ensure_message_contains(3, "meta(baz)");
+		ensure_message_field_equals(2, MSG_FIELD, "logging");
+		ensure_message_field_equals(3, MSG_FIELD, "meta(baz)");
 		ensure_message_count(4);
 	}
 
@@ -513,9 +586,9 @@ namespace tut
 		LLError::setPrintLocation(false);
 		std::string location = errorReturningLocation();
 
-		ensure_message_contains(0, location + "error");
-		ensure_message_contains(1, "die");
-		ensure_message_count(2);
+		ensure_message_field_equals(0, LOCATION_FIELD, location);
+		ensure_message_field_equals(0, MSG_FIELD, "die");
+		ensure_message_count(1);
 
 		ensure("fatal callback called", fatalWasCalled);
 	}
@@ -544,13 +617,13 @@ namespace tut
 
 		setWantsTime(false);
 		ufoSighting();
-		ensure_message_contains(0, "ufo");
+		ensure_message_field_equals(0, MSG_FIELD, "ufo");
 		ensure_message_does_not_contain(0, roswell());
 
 		setWantsTime(true);
 		ufoSighting();
-		ensure_message_contains(1, "ufo");
-		ensure_message_contains(1, roswell());
+		ensure_message_field_equals(1, MSG_FIELD, "ufo");
+		ensure_message_field_equals(1, TIME_FIELD, roswell());
 	}
 
 	template<> template<>
@@ -564,9 +637,9 @@ namespace tut
 					function;
 		writeReturningLocationAndFunction(location, function);
 
-		ensure_equals("order is time location type function message",
+		ensure_equals("order is time level tags location function message",
 			message(0),
-			roswell() + " INFO: " + location + function + ": apple");
+                      roswell() + " INFO " + "# " /* no tag */ + location + " " + function + " : " + "apple");
 	}
 
 	template<> template<>
@@ -578,7 +651,7 @@ namespace tut
 
 		LL_INFOS() << "boo" << LL_ENDL;
 
-		ensure_message_contains(0, "boo");
+		ensure_message_field_equals(0, MSG_FIELD, "boo");
 		ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1);
 		ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo");
 
@@ -637,14 +710,12 @@ namespace tut
 		TestAlpha::doAll();
 		TestBeta::doAll();
 
-		ensure_message_contains(0, "aim west");
-		ensure_message_contains(1, "error");
-		ensure_message_contains(2, "ate eels");
-		ensure_message_contains(3, "buy iron");
-		ensure_message_contains(4, "bad word");
-		ensure_message_contains(5, "error");
-		ensure_message_contains(6, "big easy");
-		ensure_message_count(7);
+		ensure_message_field_equals(0, MSG_FIELD, "aim west");
+		ensure_message_field_equals(1, MSG_FIELD, "ate eels");
+		ensure_message_field_equals(2, MSG_FIELD, "buy iron");
+		ensure_message_field_equals(3, MSG_FIELD, "bad word");
+		ensure_message_field_equals(4, MSG_FIELD, "big easy");
+		ensure_message_count(5);
 	}
 
 	template<> template<>
@@ -657,8 +728,8 @@ namespace tut
 		LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE);
 
 		TestBeta::doAll();
-		ensure_message_contains(0, "buy iron");
-		ensure_message_contains(1, "bad word");
+		ensure_message_field_equals(0, MSG_FIELD, "buy iron");
+		ensure_message_field_equals(1, MSG_FIELD, "bad word");
 		ensure_message_count(2);
 	}
 
@@ -678,9 +749,9 @@ namespace tut
 
 		TestAlpha::doAll();
 		TestBeta::doAll();
-		ensure_message_contains(0, "any idea");
-		ensure_message_contains(1, "aim west");
-		ensure_message_contains(2, "bad word");
+		ensure_message_field_equals(0, MSG_FIELD, "any idea");
+		ensure_message_field_equals(1, MSG_FIELD, "aim west");
+		ensure_message_field_equals(2, MSG_FIELD, "bad word");
 		ensure_message_count(3);
 	}
 
@@ -718,14 +789,13 @@ namespace tut
 		// configuration from LLSD
 	void ErrorTestObject::test<16>()
 	{
-		std::string this_file = LLError::abbreviateFile(__FILE__);
 		LLSD config;
 		config["print-location"] = true;
 		config["default-level"] = "DEBUG";
 
 		LLSD set1;
 		set1["level"] = "WARN";
-		set1["files"][0] = this_file;
+        set1["files"][0] = LLError::abbreviateFile(__FILE__);
 
 		LLSD set2;
 		set2["level"] = "INFO";
@@ -744,10 +814,9 @@ namespace tut
 
 		TestAlpha::doAll();
 		TestBeta::doAll();
-		ensure_message_contains(0, "any idea");
-		ensure_message_contains(0, this_file);
-		ensure_message_contains(1, "aim west");
-		ensure_message_contains(2, "bad word");
+		ensure_message_field_equals(0, MSG_FIELD, "any idea");
+		ensure_message_field_equals(1, MSG_FIELD, "aim west");
+		ensure_message_field_equals(2, MSG_FIELD, "bad word");
 		ensure_message_count(3);
 
 		// make sure reconfiguring works
@@ -758,15 +827,73 @@ namespace tut
 
 		TestAlpha::doAll();
 		TestBeta::doAll();
-		ensure_message_contains(3, "aim west");
-		ensure_message_does_not_contain(3, this_file);
-		ensure_message_contains(4, "error");
-		ensure_message_contains(5, "ate eels");
-		ensure_message_contains(6, "bad word");
-		ensure_message_contains(7, "error");
-		ensure_message_contains(8, "big easy");
-		ensure_message_count(9);
+		ensure_message_field_equals(3, MSG_FIELD, "aim west");
+		ensure_message_field_equals(4, MSG_FIELD, "ate eels");
+		ensure_message_field_equals(5, MSG_FIELD, "bad word");
+		ensure_message_field_equals(6, MSG_FIELD, "big easy");
+		ensure_message_count(7);
+	}
+}
+
+namespace
+{
+    void writeMsgNeedsEscaping()
+    {
+        LL_DEBUGS("WriteTag") << "backslash\\" << LL_ENDL;
+        LL_INFOS("WriteTag") << "newline\nafternewline" << LL_ENDL;
+        LL_WARNS("WriteTag") << "return\rafterreturn" << LL_ENDL;
+
+        LL_DEBUGS("WriteTag") << "backslash\\backslash\\" << LL_ENDL;
+        LL_INFOS("WriteTag") << "backslash\\newline\nanothernewline\nafternewline" << LL_ENDL;
+        LL_WARNS("WriteTag") << "backslash\\returnnewline\r\n\\afterbackslash" << LL_ENDL;
+    }
+};
+
+namespace tut
+{
+    template<> template<>
+    void ErrorTestObject::test<17>()
+        // backslash, return, and newline are escaped with backslashes
+    {
+        LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+        writeMsgNeedsEscaping();
+        ensure_message_field_equals(0, MSG_FIELD, "backslash\\\\");
+        ensure_message_field_equals(1, MSG_FIELD, "newline\\nafternewline");
+        ensure_message_field_equals(2, MSG_FIELD, "return\\rafterreturn");
+        ensure_message_field_equals(3, MSG_FIELD, "backslash\\\\backslash\\\\");
+        ensure_message_field_equals(4, MSG_FIELD, "backslash\\\\newline\\nanothernewline\\nafternewline");
+        ensure_message_field_equals(5, MSG_FIELD, "backslash\\\\returnnewline\\r\\n\\\\afterbackslash");
+        ensure_message_count(6);
+    }
+}
+
+namespace
+{
+    std::string writeTagWithSpaceReturningLocation()
+	{
+        LL_DEBUGS("Write Tag") << "not allowed" << LL_ENDL;	int this_line = __LINE__;
+        
+        std::ostringstream location;
+        location << LLError::abbreviateFile(__FILE__).c_str() << "(" << this_line << ")";
+        return location.str();
 	}
+};
+
+namespace tut
+{
+    template<> template<>
+    void ErrorTestObject::test<18>()
+        // space character is not allowed in a tag
+    {
+        LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+        fatalWasCalled = false;
+
+        std::string location = writeTagWithSpaceReturningLocation();
+        std::string expected = "Space is not allowed in a log tag at " + location;
+		ensure_message_field_equals(0, LEVEL_FIELD, "ERROR");
+		ensure_message_field_equals(0, MSG_FIELD, expected);
+		ensure("fatal callback called", fatalWasCalled);
+    }
 }
 
 /* Tests left:
diff --git a/indra/llcorehttp/httpstats.cpp b/indra/llcorehttp/httpstats.cpp
index b2de7f51ff0111e86eb44089564339722574b7b0..19eceae5ef2bd58a146280da5c00cd2373cf28c6 100644
--- a/indra/llcorehttp/httpstats.cpp
+++ b/indra/llcorehttp/httpstats.cpp
@@ -101,7 +101,7 @@ void HTTPStats::dumpStats()
         out << (*it).first << " " << (*it).second << std::endl;
     }
 
-    LL_WARNS("HTTP Core") << out.str() << LL_ENDL;
+    LL_WARNS("HTTPCore") << out.str() << LL_ENDL;
 }
 
 
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index dca03cfe04fb7c279040e72a52ec38e1fdace852..1a4dd2ca9943c67b2383580972cd3883147b75dd 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -889,7 +889,7 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components)
 
 bool LLImageRaw::resize(U16 width, U16 height, S8 components)
 {
-	if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components))
+	if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components) && !isBufferInvalid())
 	{
 		return true;
 	}
@@ -898,7 +898,7 @@ bool LLImageRaw::resize(U16 width, U16 height, S8 components)
 
 	allocateDataSize(width,height,components);
 
-	return true;
+	return !isBufferInvalid();
 }
 
 bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp
index 2cdd26c22b4616c07a212821f9d9a632b4222403..867b2bb47bac2311de1ea1c6a24be455163c9ce2 100644
--- a/indra/llimage/llimagebmp.cpp
+++ b/indra/llimage/llimagebmp.cpp
@@ -318,7 +318,7 @@ bool LLImageBMP::updateData()
 
 	if( 0 != mColorPaletteColors )
 	{
-		mColorPalette = new U8[color_palette_size];
+		mColorPalette = new(std::nothrow) U8[color_palette_size];
 		if (!mColorPalette)
 		{
 			LL_ERRS() << "Out of memory in LLImageBMP::updateData()" << LL_ENDL;
@@ -344,7 +344,11 @@ bool LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time)
 		return false;
 	}
 	
-	raw_image->resize(getWidth(), getHeight(), 3);
+	if (!raw_image->resize(getWidth(), getHeight(), 3))
+	{
+		setLastError("llimagebmp failed to resize image!");
+		return false;
+	}
 
 	U8* src = mdata + mBitmapOffset;
 	U8* dst = raw_image->getData();
diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp
index 3a7319d765d674d20592370931a9086ee764efce..36317a5ba883c39cd973549c308ba66a658e7f73 100644
--- a/indra/llimage/llimagedxt.cpp
+++ b/indra/llimage/llimagedxt.cpp
@@ -289,7 +289,11 @@ bool LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
 		return false;
 	}
 
-	raw_image->resize(width, height, ncomponents);
+	if (!raw_image->resize(width, height, ncomponents))
+	{
+		setLastError("llImageDXT failed to resize image!");
+		return false;
+	}
 	memcpy(raw_image->getData(), data, image_size);	/* Flawfinder: ignore */
 
 	return true;
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index 60b2d0faa53fc2c11c90c24a36b6c23d18c6efdc..3b1b060c023b4ffe4146bcb8f972bf20644d5852 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -29,6 +29,7 @@
 #include "llimagejpeg.h"
 
 #include "llerror.h"
+#include "llexception.h"
 
 jmp_buf	LLImageJPEG::sSetjmpBuffer ;
 LLImageJPEG::LLImageJPEG(S32 quality) 
@@ -256,7 +257,10 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 
 		setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB)
 
-		raw_image->resize(getWidth(), getHeight(), getComponents());
+		if (!raw_image->resize(getWidth(), getHeight(), getComponents()))
+		{
+			throw std::bad_alloc();
+		}
 		raw_image_data = raw_image->getData();
 		
 		
@@ -311,6 +315,13 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 		jpeg_destroy_decompress(&cinfo);
 	}
 
+	catch (std::bad_alloc)
+	{
+		setLastError( "Out of memory");
+		jpeg_destroy_decompress(&cinfo);
+		return true; // done
+	}
+
 	catch (int)
 	{
 		jpeg_destroy_decompress(&cinfo);
@@ -370,10 +381,11 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )
   
   // Double the buffer size;
   S32 new_buffer_size = self->mOutputBufferSize * 2;
-  U8* new_buffer = new U8[ new_buffer_size ];
+  U8* new_buffer = new(std::nothrow) U8[ new_buffer_size ];
   if (!new_buffer)
   {
-  	LL_ERRS() << "Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )" << LL_ENDL;
+    self->setLastError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )");
+    LLTHROW(LLContinueError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )"));
   	return false;
   }
   memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize );	/* Flawfinder: ignore */
@@ -493,7 +505,14 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
 	disclaimMem(mOutputBufferSize);
 	mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024;
 	claimMem(mOutputBufferSize);
-	mOutputBuffer = new U8[ mOutputBufferSize ];
+	mOutputBuffer = new(std::nothrow) U8[ mOutputBufferSize ];
+	if (mOutputBuffer == NULL)
+	{
+		disclaimMem(mOutputBufferSize);
+		mOutputBufferSize = 0;
+		setLastError("Failed to allocate output buffer");
+		return false;
+	}
 
 	const U8* raw_image_data = NULL;
 	S32 row_stride = 0;
diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp
index a4823ed859d7a1e4fced1f677bece0cf9b379697..c4b98d82603780527a2d0fc24e8d5969b3087ec9 100644
--- a/indra/llimage/llimagepng.cpp
+++ b/indra/llimage/llimagepng.cpp
@@ -125,7 +125,12 @@ bool LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)
 	// Temporary buffer to hold the encoded image. Note: the final image
 	// size should be much smaller due to compression.
 	U32 bufferSize = getWidth() * getHeight() * getComponents() + 8192;
-    U8* tmpWriteBuffer = new U8[ bufferSize ];
+	U8* tmpWriteBuffer = new(std::nothrow) U8[ bufferSize ];
+	if (!tmpWriteBuffer)
+	{
+		setLastError("LLImagePNG::out of memory");
+		return false;
+	}
 
 	// Delegate actual encoding work to wrapper
 	LLPngWrapper pngWrapper;
diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp
index 7c75aa1e2a7791ffdf83cd4e4ce6d6cd049d6486..88bdae9b80f4fe3f1247759bb4a2f98a51a275ac 100644
--- a/indra/llimage/llimagetga.cpp
+++ b/indra/llimage/llimagetga.cpp
@@ -263,7 +263,7 @@ bool LLImageTGA::updateData()
 		// only allocate memory for one if _we_ intend to use it.
 		if ( (1 == mImageType) || (9 == mImageType)  )
 		{
-			mColorMap = new U8[ color_map_bytes ];  
+			mColorMap = new(std::nothrow) U8[ color_map_bytes ];  
 			if (!mColorMap)
 			{
 				LL_ERRS() << "Out of Memory in bool LLImageTGA::updateData()" << LL_ENDL;
@@ -336,7 +336,11 @@ bool LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time)
 
 	// Copy everything after the header.
 
-	raw_image->resize(getWidth(), getHeight(), getComponents());
+	if( !raw_image->resize(getWidth(), getHeight(), getComponents()))
+	{
+		setLastError("LLImageTGA::out of memory");
+		return false;
+	}
 
 	if( (getComponents() != 1) &&
 		(getComponents() != 3) &&
@@ -346,6 +350,11 @@ bool LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time)
 		return false;
 	}
 
+	if( raw_image->isBufferInvalid())
+	{
+		setLastError("LLImageTGA::out of memory");
+		return false;
+	}
 
 	if( mOriginRightBit )
 	{
@@ -395,6 +404,11 @@ bool LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, bool rle, bool flipped
 				// alpha was entirely opaque
 				// convert to 24 bit image
 				LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3);
+				if (compacted_image->isBufferInvalid())
+				{
+					success = false;
+					break;
+				}
 				compacted_image->copy(raw_image);
 				raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3);
 				raw_image->copy(compacted_image);
@@ -411,9 +425,16 @@ bool LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, bool rle, bool flipped
 			// alpha was entirely opaque
 			// convert to 24 bit image
 			LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3);
-			compacted_image->copy(raw_image);
-			raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3);
-			raw_image->copy(compacted_image);
+			if (compacted_image->isBufferInvalid())
+			{
+				success = false;
+			}
+			else
+			{
+				compacted_image->copy(raw_image);
+				raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3);
+				raw_image->copy(compacted_image);
+			}
 		}
 	}
 	
@@ -1053,7 +1074,11 @@ bool LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight
 		return false;
 	}
 
-	raw_image->resize(getWidth(), getHeight(), getComponents());
+	if( !raw_image->resize(getWidth(), getHeight(), getComponents()) )
+	{
+		LL_ERRS() << "LLImageTGA: Failed to resize image" << LL_ENDL;
+		return false;
+	}
 
 	U8* dst = raw_image->getData();
 	U8* src = getData() + mDataOffset;
diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp
index eb70b78a362ff104e4e4e78e88bfafa2dfd2703a..f298764cc0743a8a5856c741a7645673e920961f 100644
--- a/indra/llimage/llpngwrapper.cpp
+++ b/indra/llimage/llpngwrapper.cpp
@@ -173,8 +173,11 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
 		// data space
 		if (rawImage != NULL)
 		{
-			rawImage->resize(static_cast<U16>(mWidth),
-				static_cast<U16>(mHeight), mChannels);
+			if (!rawImage->resize(static_cast<U16>(mWidth),
+				static_cast<U16>(mHeight), mChannels))
+			{
+				LLTHROW(PngError("Failed to resize image"));
+			}
 			U8 *dest = rawImage->getData();
 			int offset = mWidth * mChannels;
 
@@ -207,6 +210,12 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
 		releaseResources();
 		return (FALSE);
 	}
+	catch (std::bad_alloc)
+	{
+		mErrorMessage = "LLPngWrapper";
+		releaseResources();
+		return (FALSE);
+	}
 
 	// Clean up and return
 	releaseResources();
diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp
index 458adc9eddf9f01dd2331082ecb4a36db08132f1..853ed655f5264d0beb10edefdd5bff656d71b81c 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -190,7 +190,7 @@ LLInventoryType::EType LLInventoryType::defaultForAssetType(LLAssetType::EType a
 	}
 	else
 	{
-		return IT_NONE;
+		return IT_UNKNOWN;
 	}
 }
 
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index 8f2267307bb147f7bd7d73e65d6f1f6dce39ded0..72092b1d8b8a818378ab4334645075f1bb447271 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -67,6 +67,7 @@ class LLInventoryType
         IT_SETTINGS = 25,
 		IT_COUNT = 26,
 
+		IT_UNKNOWN = 255,
 		IT_NONE = -1
 	};
 
@@ -117,6 +118,7 @@ class LLInventoryType
         ICONNAME_SETTINGS_DAY,
 
 		ICONNAME_INVALID,
+		ICONNAME_UNKNOWN,
 		ICONNAME_COUNT,
 		ICONNAME_NONE = -1
 	};
diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp
index b7460df508caec0cdabfd22556c76c1786e35d39..b15b98db806b04ae7204cd2a6c4482a5d0f7b13a 100644
--- a/indra/llmessage/lliosocket.cpp
+++ b/indra/llmessage/lliosocket.cpp
@@ -101,7 +101,7 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)
 ///
 
 // static
-LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
+LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port, const char *hostname)
 {
 	LLSocket::ptr_t rv;
 	apr_socket_t* socket = NULL;
@@ -150,7 +150,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
 		apr_sockaddr_t* sa = NULL;
 		status = apr_sockaddr_info_get(
 			&sa,
-			APR_ANYADDR,
+			hostname,
 			APR_UNSPEC,
 			port,
 			0,
diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h
index f840f0275c12388e0eff23b8ff26c33b990f74bc..303d80eb142982c40daa1592d865fc06b52e19cd 100644
--- a/indra/llmessage/lliosocket.h
+++ b/indra/llmessage/lliosocket.h
@@ -96,12 +96,14 @@ class LLSocket
 	 * and associated with the socket.
 	 * @param type The type of socket to create
 	 * @param port The port for the socket
+	 * @param hostname e.g. APR_ANYADDR to listen openly, or "127.0.0.1"
 	 * @return A valid socket shared pointer if the call worked.
 	 */
 	static ptr_t create(
 		apr_pool_t* pool,
 		EType type,
-		U16 port = PORT_EPHEMERAL);
+		U16 port = PORT_EPHEMERAL,
+		const char *hostname = APR_ANYADDR);
 
 	/** 
 	 * @brief Create a LLSocket when you already have an apr socket.
diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp
index ec7b21d8b60b6f3dc20d4627e08b56ca4444d9f2..452b77fb6d1f6579b9b30b6f48447f3739552ec5 100644
--- a/indra/llmessage/lltransfermanager.cpp
+++ b/indra/llmessage/lltransfermanager.cpp
@@ -62,9 +62,11 @@ LLTransferManager::LLTransferManager() :
 
 LLTransferManager::~LLTransferManager()
 {
+	// LLTransferManager should have been cleaned up by message system shutdown process
+	llassert(!mValid);
 	if (mValid)
 	{
-		LL_WARNS() << "LLTransferManager::~LLTransferManager - Should have been cleaned up by message system shutdown process" << LL_ENDL;
+		// Usually happens if OS tries to kill viewer
 		cleanup();
 	}
 }
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 9b545bca0a5a8fe338b8377606283b16990c7a60..25ec493fa2cf12e2846c14c5e90b807f666adef2 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1285,7 +1285,8 @@ BOOL LLImageGL::createGLTexture()
 	stop_glerror();
 	if (!mTexName)
 	{
-		LL_ERRS() << "LLImageGL::createGLTexture failed to make an empty texture" << LL_ENDL;
+		LL_WARNS() << "LLImageGL::createGLTexture failed to make an empty texture" << LL_ENDL;
+		return FALSE;
 	}
 
 	return TRUE ;
@@ -1418,7 +1419,16 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	}
 	if (!mTexName)
 	{
-		LL_ERRS() << "LLImageGL::createGLTexture failed to make texture" << LL_ENDL;
+		if (old_name)
+		{
+			sGlobalTextureMemory -= mTextureMemory;
+			LLImageGL::deleteTextures(1, &old_name);
+			disclaimMem(mTextureMemory);
+			stop_glerror();
+		}
+
+		LL_WARNS() << "LLImageGL::createGLTexture failed to make texture" << LL_ENDL;
+		return FALSE;
 	}
 
 	if (mUseMipMaps)
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index ed65b1e45f1b6cb55a3fcb9be4d50ae7322800fd..f4028057e8565b66078f4b9abc706c30910923e4 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -199,7 +199,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
 	mHoveredColor(p.hovered_color()),
 	mSearchColumn(p.search_column),
 	mColumnPadding(p.column_padding),
-	mContextMenuType(MENU_NONE)
+	mContextMenuType(MENU_NONE),
+	mIsFriendSignal(NULL)
 {
 	mItemListRect.setOriginAndSize(
 		mBorderThickness,
@@ -323,6 +324,7 @@ LLScrollListCtrl::~LLScrollListCtrl()
 	mItemList.clear();
 	std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());
 	mColumns.clear();
+	delete mIsFriendSignal;
 }
 
 
@@ -1836,6 +1838,19 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
 				menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
 			if (mPopupMenu)
 			{
+				if (mIsFriendSignal)
+				{
+					bool isFriend = *(*mIsFriendSignal)(uuid);
+					LLView* addFriendButton = mPopupMenu->getChild<LLView>("add_friend");
+					LLView* removeFriendButton = mPopupMenu->getChild<LLView>("remove_friend");
+
+					if (addFriendButton && removeFriendButton)
+					{
+						addFriendButton->setEnabled(!isFriend);
+						removeFriendButton->setEnabled(isFriend);
+					}
+				}
+
 				mPopupMenu->show(x, y);
 				LLMenuGL::showPopup(this, mPopupMenu, x, y);
 				return TRUE;
@@ -3110,3 +3125,11 @@ void LLScrollListCtrl::onFocusLost()
 	LLUICtrl::onFocusLost();
 }
 
+boost::signals2::connection LLScrollListCtrl::setIsFriendCallback(const is_friend_signal_t::slot_type& cb)
+{
+	if (!mIsFriendSignal)
+	{
+		mIsFriendSignal = new is_friend_signal_t();
+	}
+	return mIsFriendSignal->connect(cb);
+}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 699a8744e194cf5f9de143004c1696d43ef8c228..b35a8608e70d82e2b9ec8f9ab7fb0d764ad329b2 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -90,6 +90,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 
 	
 	typedef boost::signals2::signal<S32 (S32,const LLScrollListItem*,const LLScrollListItem*),maximum<S32> > sort_signal_t;
+	typedef boost::signals2::signal<bool(const LLUUID& user_id)> is_friend_signal_t;
 	
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
@@ -393,6 +394,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 		return mSortCallback->connect(cb);
 	}
 
+	boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb);
+
 
 protected:
 	// "Full" interface: use this when you're creating a list that has one or more of the following:
@@ -515,6 +518,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	std::vector<sort_column_t>	mSortColumns;
 
 	sort_signal_t*	mSortCallback;
+
+	is_friend_signal_t*	mIsFriendSignal;
 }; // end class LLScrollListCtrl
 
 #endif  // LL_SCROLLLISTCTRL_H
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index f98c2423e5e8a2b20f2945fbb27a6fd5371e502b..4ee4a5357c53eda5dd69ae7e2c99315e265fedbc 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -752,9 +752,6 @@ void LLWindowWin32::close()
 
 	mDragDrop->reset();
 
-	// Make sure cursor is visible and we haven't mangled the clipping state.
-	setMouseClipping(FALSE);
-	showCursor();
 
 	// Go back to screen mode written in the registry.
 	if (mFullscreen)
@@ -762,9 +759,23 @@ void LLWindowWin32::close()
 		resetDisplayResolution();
 	}
 
+	// Don't process events in our mainWindowProc any longer.
+	SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, NULL);
+
+	// Make sure cursor is visible and we haven't mangled the clipping state.
+	showCursor();
+	setMouseClipping(FALSE);
+	if (gKeyboard)
+	{
+		gKeyboard->resetKeys();
+	}
+
 	// Clean up remaining GL state
-	LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL;
-	gGLManager.shutdownGL();
+	if (gGLManager.mInited)
+	{
+		LL_INFOS("Window") << "Cleaning up GL" << LL_ENDL;
+		gGLManager.shutdownGL();
+	}
 
 	LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL;
 	if (mhRC)
@@ -785,16 +796,16 @@ void LLWindowWin32::close()
 	// Restore gamma to the system values.
 	restoreGamma();
 
-	if (mhDC && !ReleaseDC(mWindowHandle, mhDC))
+	if (mhDC)
 	{
-		LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL;
+		if (!ReleaseDC(mWindowHandle, mhDC))
+		{
+			LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL;
+		}
 		mhDC = NULL;
 	}
 
 	LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
-	
-	// Don't process events in our mainWindowProc any longer.
-	SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, NULL);
 
 	// Make sure we don't leave a blank toolbar button.
 	ShowWindow(mWindowHandle, SW_HIDE);
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index fc3aa7739a76be177721ca4ff6cb1419f092d932..48ea19be078d9fc0bab6825684af472f85ec404f 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-5.1.9
+5.1.10
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index ecd7c4bc3648c599466b2d87e3b4c468033072be..8ced81fdb36fa7089a25b288c05eda931cc538ef 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -2,7 +2,6 @@
 	<map>
 		<!-- default-level can be ALL, DEBUG, INFO, WARN, ERROR, or NONE -->
 		<key>default-level</key>    <string>INFO</string>
-		<key>print-location</key>   <boolean>false</boolean>
 		<key>settings</key>
 			<array>
 				<!-- Suppress anything but ERROR for some very verbose components -->
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 4ce5e0925443b29b282d585eca821bac57a991fe..5135d5072ae2e444a11ed39c9b015f611426505f 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4163,6 +4163,7 @@ void LLAgent::setTeleportState(ETeleportState state)
             " for previously failed teleport.  Ignore!" << LL_ENDL;
         return;
     }
+    LL_DEBUGS("Teleport") << "Setting teleport state to " << state << " Previous state: " << mTeleportState << LL_ENDL;
 	mTeleportState = state;
 	if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime"))
 	{
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 477ec88be4197ecd2df11b2cf988661a780b3479..ad35c26dc63973d666f4150a1e39b232636b77ff 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -637,6 +637,7 @@ class LLAgent : public LLOldEvents::LLObservable
 	void			teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation
 	void 			teleportCancel();										// May or may not be allowed by server
     void            restoreCanceledTeleportRequest();
+    bool			canRestoreCanceledTeleport() { return mTeleportCanceled != NULL; }
 	bool			getTeleportKeepsLookAt() { return mbTeleportKeepsLookAt; } // Whether look-at reset after teleport
 protected:
 	bool 			teleportCore(bool is_local = false); 					// Stuff for all teleports; returns true if the teleport can proceed
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 62ff8cf4fb1cb33e4c29d0d15ae0712403e6b8d3..cb1a2e28fdd4b8439689bec6b3309374c1b35fef 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3121,7 +3121,7 @@ LLSD LLAppViewer::getViewerInfo() const
 	}
 	else
 	{
-		LL_WARNS("Driver version")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL;
+		LL_WARNS("DriverVersion")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL;
 		LLSD driver_info = gDXHardware.getDisplayInfo();
 		if (driver_info.has("DriverVersion"))
 		{
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 48b3a1c485a46635bc6e15f5ae13bd5e632c9c54..f0a4a54fbf4584c5000679da9c158d7fadbf985b 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -698,7 +698,7 @@ void LLAppViewerWin32::initCrashReporting(bool reportFreeze)
                      &processInfo) == FALSE)
       // Could not start application -> call 'GetLastError()'
 	{
-        LL_WARNS("CrashReport Launch") << "CreateProcess failed " << GetLastError() << LL_ENDL;
+        LL_WARNS("CrashReport") << "CreateProcess failed " << GetLastError() << LL_ENDL;
         return;
     }
 }
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
index c4f959bfa9c03f27d59ef26ec23b92dfab65d520..91b9d68fd25e9cf8bf44e485a3372421e4be93bb 100644
--- a/indra/newview/llchicletbar.cpp
+++ b/indra/newview/llchicletbar.cpp
@@ -70,7 +70,7 @@ void LLChicletBar::log(LLView* panel, const std::string& descr)
 {
 	if (NULL == panel) return;
 	LLView* layout = panel->getParent();
-	LL_DEBUGS("Chiclet Bar Rects") << descr << ": "
+	LL_DEBUGS("ChicletBarRects") << descr << ": "
 		<< "panel: " << panel->getName()
 		<< ", rect: " << panel->getRect()
 		<< " layout: " << layout->getName()
diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp
index 4ac9c974c1e84c58776fa46162407d4bd025e7e2..d5d8cda8cecc973208651708132d1fb359810bd1 100644
--- a/indra/newview/llestateinfomodel.cpp
+++ b/indra/newview/llestateinfomodel.cpp
@@ -95,7 +95,7 @@ void LLEstateInfoModel::update(const strings_t& strings)
 	mFlags		= strtoul(strings[3].c_str(), NULL, 10);
 	mSunHour	= ((F32)(strtod(strings[4].c_str(), NULL)))/1024.0f;
 
-	LL_DEBUGS("Windlight Sync") << "Received estate info: "
+	LL_DEBUGS("WindlightSync") << "Received estate info: "
 		<< "is_sun_fixed = " << getUseFixedSun()
 		<< ", sun_hour = " << getSunHour() << LL_ENDL;
 	LL_DEBUGS() << getInfoDump() << LL_ENDL;
@@ -154,7 +154,7 @@ void LLEstateInfoModel::commitEstateInfoCapsCoro(std::string url)
 
     body["invoice"] = LLFloaterRegionInfo::getLastInvoice();
 
-    LL_DEBUGS("Windlight Sync") << "Sending estate caps: "
+    LL_DEBUGS("WindlightSync") << "Sending estate caps: "
         << "is_sun_fixed = " << getUseFixedSun()
         << ", sun_hour = " << getSunHour() << LL_ENDL;
     LL_DEBUGS() << body << LL_ENDL;
@@ -184,7 +184,7 @@ void LLEstateInfoModel::commitEstateInfoCapsCoro(std::string url)
 // strings[3] = str((S32)(sun_hour * 1024.f))
 void LLEstateInfoModel::commitEstateInfoDataserver()
 {
-	LL_DEBUGS("Windlight Sync") << "Sending estate info: "
+	LL_DEBUGS("WindlightSync") << "Sending estate info: "
 		<< "is_sun_fixed = " << getUseFixedSun()
 		<< ", sun_hour = " << getSunHour() << LL_ENDL;
 	LL_DEBUGS() << getInfoDump() << LL_ENDL;
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 487496df9a3691a16d809525d721ccc2a2a555c4..8d07035b97d85dcc528472db0d2b2c42b04b0d8e 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -377,6 +377,43 @@ bool LLFeatureManager::parseFeatureTable(std::string filename)
 
 F32 gpu_benchmark();
 
+#if LL_WINDOWS
+
+static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
+
+U32 exception_benchmark_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
+{
+    if (code == STATUS_MSC_EXCEPTION)
+    {
+        // C++ exception, go on
+        return EXCEPTION_CONTINUE_SEARCH;
+    }
+    else
+    {
+        // handle it
+        return EXCEPTION_EXECUTE_HANDLER;
+    }
+}
+
+F32 logExceptionBenchmark()
+{
+    // Todo: make a wrapper/class for SEH exceptions
+    F32 gbps = -1;
+    __try
+    {
+        gbps = gpu_benchmark();
+    }
+    __except (exception_benchmark_filter(GetExceptionCode(), GetExceptionInformation()))
+    {
+        // convert to C++ styled exception
+        char integer_string[32];
+        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
+        throw std::exception(integer_string);
+    }
+    return gbps;
+}
+#endif
+
 bool LLFeatureManager::loadGPUClass()
 {
 	if (!gSavedSettings.getBOOL("SkipBenchmark"))
@@ -385,7 +422,11 @@ bool LLFeatureManager::loadGPUClass()
 		F32 gbps;
 		try
 		{
+#if LL_WINDOWS
+			gbps = logExceptionBenchmark();
+#else
 			gbps = gpu_benchmark();
+#endif
 		}
 		catch (const std::exception& e)
 		{
@@ -400,11 +441,11 @@ bool LLFeatureManager::loadGPUClass()
 		LL_WARNS("RenderInit") << "Unable to get an accurate benchmark; defaulting to class 3" << LL_ENDL;
 		mGPUClass = GPU_CLASS_3;
 	#else
-			if (gGLManager.mGLVersion < 2.f)
+			if (gGLManager.mGLVersion <= 2.f)
 			{
 				mGPUClass = GPU_CLASS_0;
 			}
-			else if (gGLManager.mGLVersion < 3.f)
+			else if (gGLManager.mGLVersion <= 3.f)
 			{
 				mGPUClass = GPU_CLASS_1;
 			}
@@ -420,6 +461,11 @@ bool LLFeatureManager::loadGPUClass()
 			{
 				mGPUClass = GPU_CLASS_4;
 			}
+			if (gGLManager.mIsIntel && mGPUClass > GPU_CLASS_1)
+			{
+				// Intels are generally weaker then other GPUs despite having advanced features
+				mGPUClass = (EGPUClass)(mGPUClass - 1);
+			}
 	#endif
 		}
 		else if (gGLManager.mGLVersion <= 2.f)
diff --git a/indra/newview/llfloaternotificationstabbed.cpp b/indra/newview/llfloaternotificationstabbed.cpp
index 4b5fe4989ac413b8fc7dc68dfbaf92c39af19a17..d1679fd936de4032183f028d3203b5aaba86c4b4 100644
--- a/indra/newview/llfloaternotificationstabbed.cpp
+++ b/indra/newview/llfloaternotificationstabbed.cpp
@@ -387,7 +387,8 @@ void LLFloaterNotificationsTabbed::onStoreToast(LLPanel* info_panel, LLUUID id)
     p.notification_name = notify->getName();
     p.transaction_id = payload["transaction_id"];
     p.group_id = payload["group_id"];
-    p.fee =  payload["fee"];
+    p.fee = payload["fee"];
+    p.use_offline_cap = payload["use_offline_cap"].asInteger();
     p.subject = payload["subject"].asString();
     p.message = payload["message"].asString();
     p.sender = payload["sender_name"].asString();
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 2a22dd461a698b8853eb60d9b1f17b9f62c5d30f..43b359e00368208a0af53cd5e3dc2d83961feb91 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2722,6 +2722,16 @@ void LLPanelPreferenceGraphics::cancel()
 void LLPanelPreferenceGraphics::saveSettings()
 {
 	resetDirtyChilds();
+	std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive");
+	if (preset_graphic_active.empty())
+	{
+		LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+		if (instance)
+		{
+			//don't restore previous preset after closing Preferences
+			instance->saveGraphicsPreset(preset_graphic_active);
+		}
+	}
 	LLPanelPreference::saveSettings();
 }
 void LLPanelPreferenceGraphics::setHardwareDefaults()
diff --git a/indra/newview/llfloatersaveprefpreset.cpp b/indra/newview/llfloatersaveprefpreset.cpp
index bdef718d0e94dc4689634cfbe23f0fbf9048905e..684778c93ac8c1f31389eeaf9478aea19e1c2fef 100644
--- a/indra/newview/llfloatersaveprefpreset.cpp
+++ b/indra/newview/llfloatersaveprefpreset.cpp
@@ -34,6 +34,7 @@
 #include "llfloaterreg.h"
 #include "llnotificationsutil.h"
 #include "llpresetsmanager.h"
+#include "lltrans.h"
 
 LLFloaterSavePrefPreset::LLFloaterSavePrefPreset(const LLSD &key)
 :	LLFloater(key)
@@ -76,7 +77,7 @@ void LLFloaterSavePrefPreset::onOpen(const LLSD& key)
 
 	setTitle(floater_title);
 
-	EDefaultOptions option = DEFAULT_TOP;
+	EDefaultOptions option = DEFAULT_HIDE;
 	LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, mPresetCombo, option);
 
 	onPresetNameEdited();
@@ -86,7 +87,11 @@ void LLFloaterSavePrefPreset::onBtnSave()
 {
 	std::string name = mPresetCombo->getSimple();
 
-	if (!LLPresetsManager::getInstance()->savePreset(mSubdirectory, name))
+	if ((name == LLTrans::getString(PRESETS_DEFAULT)) || (name == PRESETS_DEFAULT))
+	{
+		LLNotificationsUtil::add("DefaultPresetNotSaved");
+	}
+	else if (!LLPresetsManager::getInstance()->savePreset(mSubdirectory, name))
 	{
 		LLSD args;
 		args["NAME"] = name;
@@ -98,7 +103,7 @@ void LLFloaterSavePrefPreset::onBtnSave()
 
 void LLFloaterSavePrefPreset::onPresetsListChange()
 {
-	EDefaultOptions option = DEFAULT_TOP;
+	EDefaultOptions option = DEFAULT_HIDE;
 	LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, mPresetCombo, option);
 }
 
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 7fc60ddaacc3e742e1dd362105da5f05621c1c8f..ee4fdbe9a5ef3646a33fe33a1ec1b51803b36d35 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1225,7 +1225,7 @@ void LLFloaterTools::getMediaState()
 	if(!has_media_capability)
 	{
 		getChildView("add_media")->setEnabled(FALSE);
-		LL_WARNS("LLFloaterTools: media") << "Media not enabled (no capability) in this region!" << LL_ENDL;
+		LL_WARNS("LLFloaterToolsMedia") << "Media not enabled (no capability) in this region!" << LL_ENDL;
 		clearMediaSettings();
 		return;
 	}
@@ -1249,7 +1249,7 @@ void LLFloaterTools::getMediaState()
 			{
 				if (!object->permModify())
 				{
-					LL_INFOS("LLFloaterTools: media")
+					LL_INFOS("LLFloaterToolsMedia")
 						<< "Selection not editable due to lack of modify permissions on object id "
 						<< object->getID() << LL_ENDL;
 					
@@ -1262,7 +1262,7 @@ void LLFloaterTools::getMediaState()
 				// contention as to whether this is a sufficient solution.
 //				if (object->isMediaDataBeingFetched())
 //				{
-//					LL_INFOS("LLFloaterTools: media")
+//					LL_INFOS("LLFloaterToolsMedia")
 //						<< "Selection not editable due to media data being fetched for object id "
 //						<< object->getID() << LL_ENDL;
 //						
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index 491671c46f8f3c1f79fc7b6b6ae48d4651499806..e76b3d118e324d90363e783bdbce877a4a1cd54d 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -814,10 +814,11 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
 
                 LLSD payload;
                 payload["transaction_id"] = session_id;
-                payload["group_id"] = from_id;
+                payload["group_id"] = from_group ? from_id : aux_id;
                 payload["name"] = name;
                 payload["message"] = message;
                 payload["fee"] = membership_fee;
+                payload["use_offline_cap"] = session_id.isNull() && (offline == IM_OFFLINE);
 
                 LLSD args;
                 args["MESSAGE"] = message;
@@ -1459,8 +1460,12 @@ void LLIMProcessing::requestOfflineMessages()
         // Auto-accepted inventory items may require the avatar object
         // to build a correct name.  Likewise, inventory offers from
         // muted avatars require the mute list to properly mute.
-        if (cap_url.empty())
+        if (cap_url.empty()
+            || gAgent.getRegionCapability("AcceptFriendship").empty()
+            || gAgent.getRegionCapability("AcceptGroupInvite").empty())
         {
+            // Offline messages capability provides no session/transaction ids for message AcceptFriendship and IM_GROUP_INVITATION to work
+            // So make sure we have the caps before using it.
             requestOfflineMessagesLegacy();
         }
         else
@@ -1561,7 +1566,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
             message_data["to_agent_id"].asUUID(),
             IM_OFFLINE,
             (EInstantMessage)message_data["dialog"].asInteger(),
-            LLUUID::null, // session id, fix this for friendship offers to work
+            LLUUID::null, // session id, since there is none we can only use frienship/group invite caps
             message_data["timestamp"].asInteger(),
             message_data["from_agent_name"].asString(),
             message_data["message"].asString(),
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 3dc138af7ff3460db537e0c45e7e5e278e48ad4e..3b6778892f7dbfd457c9def9fc82cc747dab0760 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -1410,7 +1410,9 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
 			}
 			new_listener = new LLMeshBridge(inventory, root, uuid);
 			break;
-
+		case LLAssetType::AT_UNKNOWN:
+			new_listener = new LLUnknownItemBridge(inventory, root, uuid);
+			break;
 		case LLAssetType::AT_IMAGE_TGA:
 		case LLAssetType::AT_IMAGE_JPEG:
 			//LL_WARNS() << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << LL_ENDL;
@@ -7125,6 +7127,21 @@ const LLUUID &LLLinkFolderBridge::getFolderID() const
 	return LLUUID::null;
 }
 
+void LLUnknownItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+	menuentry_vec_t items;
+	menuentry_vec_t disabled_items;
+	items.push_back(std::string("Properties"));
+	items.push_back(std::string("Rename"));
+	hide_context_entries(menu, items, disabled_items);
+}
+
+LLUIImagePtr LLUnknownItemBridge::getIcon() const
+{
+	return LLInventoryIcon::getIcon(LLAssetType::AT_UNKNOWN, mInvType);
+}
+
+
 /********************************************************************************
  **
  **                    BRIDGE ACTIONS
@@ -7523,7 +7540,7 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ
 	menuentry_vec_t disabled_items;
     if (get_selection_item_uuids(selected_items, ids))
     {
-        if (!LLAppearanceMgr::instance().canAddWearables(ids))
+		if (!LLAppearanceMgr::instance().canAddWearables(ids) && canWearSelected(ids))
         {
 			disabled_items.push_back(std::string("Wearable Add"));
         }
@@ -7531,4 +7548,17 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ
 	disable_context_entries_if_present(menu, disabled_items);
 }
 
+bool LLFolderViewGroupedItemBridge::canWearSelected(uuid_vec_t item_ids)
+{
+	for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it)
+	{
+		LLViewerInventoryItem* item = gInventory.getItem(*it);
+		LLAssetType::EType asset_type = item->getType();
+		if (!item || (asset_type >= LLAssetType::AT_COUNT) || (asset_type <= LLAssetType::AT_NONE))
+		{
+			return false;
+		}
+	}
+	return true;
+}
 // EOF
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index ffe59b93e59f683425cae9c87c724449ae3e27b7..73f20d214616a29793b17cfb34357522d6e67c00 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -578,6 +578,17 @@ class LLLinkItemBridge : public LLItemBridge
 	static std::string sPrefix;
 };
 
+class LLUnknownItemBridge : public LLItemBridge
+{
+public:
+	LLUnknownItemBridge(LLInventoryPanel* inventory,
+		LLFolderView* root,
+		const LLUUID& uuid) :
+		LLItemBridge(inventory, root, uuid) {}
+	virtual LLUIImagePtr getIcon() const;
+	virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+};
+
 class LLLinkFolderBridge : public LLItemBridge
 {
 public:
@@ -774,6 +785,7 @@ class LLFolderViewGroupedItemBridge: public LLFolderViewGroupedItemModel
 public:
     LLFolderViewGroupedItemBridge();
     virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu);
+    bool canWearSelected(uuid_vec_t item_ids);
 };
 
 #endif // LL_LLINVENTORYBRIDGE_H
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index f33df439193f2f35d043c81a3ad9eee16946bacf..a9640a2264dd932b1c014568c3f9bae72a602cfa 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -154,7 +154,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
 	// we're showing all folders, overriding filter
 	if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)
 	{
-		return !gInventory.isCategoryHidden(folder_id);
+		return true;
 	}
 
 	// when applying a filter, matching folders get their contents downloaded first
diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
index 106e5fd41571984a5d3a5e47c6dab038ac9688a7..323d19b68a7101f30c0fa957bf9370ab9a082977 100644
--- a/indra/newview/llinventoryicon.cpp
+++ b/indra/newview/llinventoryicon.cpp
@@ -99,6 +99,7 @@ LLIconDictionary::LLIconDictionary()
     addEntry(LLInventoryType::ICONNAME_SETTINGS,                new IconEntry("Inv_Settings"));
 
 	addEntry(LLInventoryType::ICONNAME_INVALID, 				new IconEntry("Inv_Invalid"));
+	addEntry(LLInventoryType::ICONNAME_UNKNOWN, 				new IconEntry("Inv_Unknown"));
 
 	addEntry(LLInventoryType::ICONNAME_NONE, 					new IconEntry("NONE"));
 }
@@ -177,6 +178,9 @@ const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type,
             // TODO: distinguish between Sky and Water settings.
             idx = assignSettingsIcon(misc_flag);
             break;
+		case LLAssetType::AT_UNKNOWN:
+			idx = LLInventoryType::ICONNAME_UNKNOWN;
+			break;
 		default:
 			break;
 	}
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 9c50866dc103a876afa58f751fec5695bd598551..1c6d9fba9db22fb0e3256d8ac74ce5c733956657 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -342,27 +342,6 @@ LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const
 	return category;
 }
 
-bool LLInventoryModel::isCategoryHidden(const LLUUID& id) const
-{
-	bool res = false;
-	const LLViewerInventoryCategory* category = getCategory(id);
-	if (category)
-	{
-		LLFolderType::EType cat_type = category->getPreferredType();
-		switch (cat_type)
-		{
-			case LLFolderType::FT_INBOX:
-			case LLFolderType::FT_OUTBOX:
-			case LLFolderType::FT_MARKETPLACE_LISTINGS:
-				res = true;
-				break;
-			default:
-				break;
-		}
-	}
-	return res;
-}
-
 S32 LLInventoryModel::getItemCount() const
 {
 	return mItemMap.size();
@@ -1831,11 +1810,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)
 	llassert(item);
 	if(item)
 	{
-		// This can happen if assettype enums from llassettype.h ever change.
-		// For example, there is a known backwards compatibility issue in some viewer prototypes prior to when 
-		// the AT_LINK enum changed from 23 to 24.
-		if ((item->getType() == LLAssetType::AT_NONE)
-		    || LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP)
+		if (item->getType() <= LLAssetType::AT_NONE)
 		{
 			LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName()
 							  << " type: " << item->getType()
@@ -1843,6 +1818,13 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)
 			return;
 		}
 
+		if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP)
+		{
+			LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName()
+				<< " type: " << item->getType()
+				<< " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL;
+		}
+
 		// This condition means that we tried to add a link without the baseobj being in memory.
 		// The item will show up as a broken link.
 		if (item->getIsBrokenLink())
@@ -2051,6 +2033,7 @@ bool LLInventoryModel::loadSkeleton(
 		update_map_t child_counts;
 		cat_array_t categories;
 		item_array_t items;
+		changed_items_t categories_to_update;
 		item_array_t possible_broken_links;
 		cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded.
 		std::string inventory_filename = getInvCacheAddres(owner_id);
@@ -2076,7 +2059,7 @@ bool LLInventoryModel::loadSkeleton(
 			}
 		}
 		bool is_cache_obsolete = false;
-		if(loadFromFile(inventory_filename, categories, items, is_cache_obsolete))
+		if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete))
 		{
 			// We were able to find a cache of files. So, use what we
 			// found to generate a set of categories we should add. We
@@ -2094,6 +2077,12 @@ bool LLInventoryModel::loadSkeleton(
 					continue; // cache corruption?? not sure why this happens -SJB
 				}
 				LLViewerInventoryCategory* tcat = *cit;
+
+				if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end())
+				{
+					tcat->setVersion(NO_VERSION);
+					LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL;
+				}
 				
 				// we can safely ignore anything loaded from file, but
 				// not sent down in the skeleton. Must have been removed from inventory.
@@ -2643,6 +2632,7 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const
 bool LLInventoryModel::loadFromFile(const std::string& filename,
 									LLInventoryModel::cat_array_t& categories,
 									LLInventoryModel::item_array_t& items,
+									LLInventoryModel::changed_items_t& cats_to_update,
 									bool &is_cache_obsolete)
 {
 	if(filename.empty())
@@ -2717,7 +2707,14 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 				}
 				else
 				{
-					items.push_back(inv_item);
+					if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
+					{
+						cats_to_update.insert(inv_item->getParentUUID());
+					}
+					else
+					{
+						items.push_back(inv_item);
+					}
 				}
 			}
 			else
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 576c5e9e20c54ccbc8a73abcfbb141cf4f44f527..a4326aaeed9708a41e836f05f4f6798f96ed89d3 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -316,9 +316,7 @@ class LLInventoryModel
     // Copy content of all folders of type "type" into folder "id" and delete/purge the empty folders
     // Note : This method has been designed for FT_OUTBOX (aka Merchant Outbox) but can be used for other categories
     void consolidateForType(const LLUUID& id, LLFolderType::EType type);
-
-    bool isCategoryHidden(const LLUUID& id) const;
-
+    
 private:
 	mutable LLPointer<LLViewerInventoryItem> mLastItem; // cache recent lookups	
 
@@ -615,6 +613,7 @@ class LLInventoryModel
 	static bool loadFromFile(const std::string& filename,
 							 cat_array_t& categories,
 							 item_array_t& items,
+							 changed_items_t& cats_to_update,
 							 bool& is_cache_obsolete); 
 	static bool saveToFile(const std::string& filename,
 						   const cat_array_t& categories,
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 36fb98efe100ecadc882dca742b4581fbb1d9cbb..002c7a321567b7c0388a116898b76137ab5044ef 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -867,13 +867,37 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
 
  	if (!folder_view_item && parent_folder)
   		{
-  			if (objectp->getType() <= LLAssetType::AT_NONE ||
-  				objectp->getType() >= LLAssetType::AT_COUNT)
+			if (objectp->getType() <= LLAssetType::AT_NONE)
+			{
+				LL_WARNS() << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : "
+					<< ((S32)objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
+					<< LL_ENDL;
+				return NULL;
+			}
+			
+			if (objectp->getType() >= LLAssetType::AT_COUNT)
   			{
-  				LL_WARNS() << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : "
-                << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
-                << LL_ENDL;
-  				return NULL;
+  				LL_WARNS() << "LLInventoryPanel::buildNewViews called with unknown objectp->mType : "
+				<< ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
+				<< LL_ENDL;
+
+				LLInventoryItem* item = (LLInventoryItem*)objectp;
+				if (item)
+				{
+					LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_UNKNOWN,
+						LLAssetType::AT_UNKNOWN,
+						LLInventoryType::IT_UNKNOWN,
+						this,
+						&mInventoryViewModel,
+						mFolderRoot.get(),
+						item->getUUID(),
+						item->getFlags());
+
+					if (new_listener)
+					{
+						folder_view_item = createFolderViewItem(new_listener);
+					}
+				}
   			}
   		
   			if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp
index f2de8e54a0e5c2a3835110a064a6a543123035d8..a5bc75e6bd51dfb4608249f3a6bbcdcee54d6a06 100644
--- a/indra/newview/llnotificationlistitem.cpp
+++ b/indra/newview/llnotificationlistitem.cpp
@@ -312,38 +312,15 @@ void LLGroupInviteNotificationListItem::onClickJoinBtn()
 		return;
 	}
 
-	if(mParams.fee > 0)
-	{
-		LLSD args;
-		args["COST"] = llformat("%d", mParams.fee);
-		// Set the fee for next time to 0, so that we don't keep
-		// asking about a fee.
-		LLSD next_payload;
-		next_payload["group_id"]=  mParams.group_id;
-		next_payload["transaction_id"]= mParams.transaction_id;
-		next_payload["fee"] = 0;
-		LLNotificationsUtil::add("JoinGroupCanAfford", args, next_payload);
-	}
-	else
-	{
-		send_improved_im(mParams.group_id,
-						std::string("name"),
-						std::string("message"),
-						IM_ONLINE,
-						IM_GROUP_INVITATION_ACCEPT,
-						mParams.transaction_id);
-	}
+	send_join_group_response(mParams.group_id, mParams.transaction_id, true, mParams.fee, mParams.use_offline_cap);
+
 	LLNotificationListItem::onClickCloseBtn();
 }
 
 void LLGroupInviteNotificationListItem::onClickDeclineBtn()
 {
-	send_improved_im(mParams.group_id,
-					std::string("name"),
-					std::string("message"),
-					IM_ONLINE,
-					IM_GROUP_INVITATION_DECLINE,
-					mParams.transaction_id);
+	send_join_group_response(mParams.group_id, mParams.transaction_id, false, mParams.fee, mParams.use_offline_cap);
+
 	LLNotificationListItem::onClickCloseBtn();
 }
 
diff --git a/indra/newview/llnotificationlistitem.h b/indra/newview/llnotificationlistitem.h
index 3dd52986b07d18a44c0a8be75f0e04c771af9304..3d564fed0e6b75e542204d01fb45301998877ead 100644
--- a/indra/newview/llnotificationlistitem.h
+++ b/indra/newview/llnotificationlistitem.h
@@ -56,6 +56,7 @@ class LLNotificationListItem : public LLPanel
         std::string     message;
         std::string     sender;
         S32             fee;
+        U8              use_offline_cap;
         LLDate          time_stamp;
         LLDate          received_time;
         LLSD            inventory_offer;
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 0c129d11644958d5db63dd6a27103ae884a6a9b8..278d83bab7ad04ffb04ae43a46e8dbd7e82840a9 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -1090,11 +1090,6 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id)
                     updates["name"] = new_name;
                     update_inventory_item(inv_id, updates, NULL);
                     mOutfitRenamePending.setNull();
-                    LLFloater* inv_floater = LLFloaterReg::getInstance("inventory");
-                    if (inv_floater)
-                    {
-                        inv_floater->closeFloater();
-                    }
                     LLFloater* appearance_floater = LLFloaterReg::getInstance("appearance");
                     if (appearance_floater)
                     {
@@ -1227,7 +1222,7 @@ void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filename
             LLFloaterPerms::getNextOwnerPerms("Uploads"),
             LLFloaterPerms::getGroupPerms("Uploads"),
             LLFloaterPerms::getEveryonePerms("Uploads"),
-            upload_pending_name, LLAssetStorage::LLStoreAssetCallback(), expected_upload_cost, nruserdata);
+            upload_pending_name, LLAssetStorage::LLStoreAssetCallback(), expected_upload_cost, nruserdata, false);
         mOutfitLinkPending = outfit_id;
     }
     delete unit;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 01ce4470f08ff9f6f247e8a18b0144ada8efe447..13ee7bb003ff2e78ba38bc92d51dad85c60dbdb9 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1255,7 +1255,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 			if (material && editable)
 			{
-				LL_DEBUGS("Materials: OnMatererialsLoaded:") << material->asLLSD() << LL_ENDL;
+				LL_DEBUGS("Materials") << material->asLLSD() << LL_ENDL;
 
 				// Alpha
 				LLCtrlSelectionInterface* combobox_alphamode =
diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp
index 46603bf4d494a3c46becc93119242aa20929eee4..7373c7412ce977c3a5faec28b3e3cea22c3fc2fd 100644
--- a/indra/newview/llpanelgroupnotices.cpp
+++ b/indra/newview/llpanelgroupnotices.cpp
@@ -304,6 +304,8 @@ void LLPanelGroupNotices::activate()
 {
 	if(mNoticesList)
 		mNoticesList->deleteAllItems();
+
+	mPrevSelectedNotice = LLUUID();
 	
 	BOOL can_send = gAgent.hasPowerInGroup(mGroupID,GP_NOTICES_SEND);
 	BOOL can_receive = gAgent.hasPowerInGroup(mGroupID,GP_NOTICES_RECEIVE);
@@ -455,12 +457,18 @@ void LLPanelGroupNotices::refreshNotices()
 	
 }
 
+void LLPanelGroupNotices::clearNoticeList()
+{
+	mPrevSelectedNotice = mNoticesList->getStringUUIDSelectedItem();
+	mNoticesList->deleteAllItems();
+}
+
 void LLPanelGroupNotices::onClickRefreshNotices(void* data)
 {
 	LL_DEBUGS() << "LLPanelGroupNotices::onClickGetPastNotices" << LL_ENDL;
 	LLPanelGroupNotices* self = (LLPanelGroupNotices*)data;
 	
-	self->mNoticesList->deleteAllItems();
+	self->clearNoticeList();
 
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessage("GroupNoticesListRequest");
@@ -548,7 +556,6 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)
 
 		LLSD row;
 		row["id"] = id;
-		
 		row["columns"][0]["column"] = "icon";
 		if (has_attachment)
 		{
@@ -576,7 +583,13 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)
 
 	mNoticesList->setNeedsSort(save_sort);
 	mNoticesList->updateSort();
-	mNoticesList->selectFirstItem();
+	if (mPanelViewNotice->getVisible())
+	{
+		if (!mNoticesList->selectByID(mPrevSelectedNotice))
+		{
+			mNoticesList->selectFirstItem();
+		}
+	}
 }
 
 void LLPanelGroupNotices::onSelectNotice(LLUICtrl* ctrl, void* data)
diff --git a/indra/newview/llpanelgroupnotices.h b/indra/newview/llpanelgroupnotices.h
index 04629b5f6bfb7312ba810301c097305f66fabc05..46c8c241c657fcb61142abeaf5fd3098a2fb82b9 100644
--- a/indra/newview/llpanelgroupnotices.h
+++ b/indra/newview/llpanelgroupnotices.h
@@ -65,6 +65,8 @@ class LLPanelGroupNotices : public LLPanelGroupTab
 
 	void refreshNotices();
 
+	void clearNoticeList();
+
 	virtual void setGroupID(const LLUUID& id);
 
 private:
@@ -113,6 +115,8 @@ class LLPanelGroupNotices : public LLPanelGroupTab
 
 	LLOfferInfo* mInventoryOffer;
 
+	LLUUID mPrevSelectedNotice;
+
 	static std::map<LLUUID,LLPanelGroupNotices*>	sInstances;
 };
 
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 087e0a07593712c4135a85456f15d6189cec88c4..52a13304df3418adb06679039e2d23efc6960665 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -834,6 +834,7 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
 	// Show the member's profile on double click.
 	mMembersList->setDoubleClickCallback(onMemberDoubleClick, this);
 	mMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
+	mMembersList->setIsFriendCallback(LLAvatarActions::isFriend);
 	
 	LLSD row;
 	row["columns"][0]["column"] = "name";
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 25cfb598e79b4bc0b0bcee95fd81a74fa7187ee7..3665910c633effc7954561d97c5f1e04c3dda797 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -341,21 +341,17 @@ void LLPanelObject::getState( )
 		return;
 	}
 
-	// can move or rotate only linked group with move permissions, or sub-object with move and modify perms
-	BOOL enable_move	= objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts"));
-	BOOL enable_scale	= objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && objectp->permModify();
-	BOOL enable_rotate	= objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts"));
-
 	S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
 	BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ))
 						 && (selected_count == 1);
 
-	if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1)
-	{
-		enable_move = FALSE;
-		enable_scale = FALSE;
-		enable_rotate = FALSE;
-	}
+	bool enable_move;
+	bool enable_modify;
+
+	LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify);
+
+	BOOL enable_scale = enable_modify;
+	BOOL enable_rotate = enable_move; // already accounts for a case of children, which needs permModify() as well
 
 	LLVector3 vec;
 	if (enable_move)
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 30fef9f5f076d39de17ade995093ecce973ed6e2..1cbff372870d5fa7d2f65fd800b43c7db34a8595 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -213,10 +213,39 @@ class LLAvatarItemRecentSpeakerComparator : public  LLAvatarItemNameComparator
 	}
 };
 
+class LLAvatarItemRecentArrivalComparator : public  LLAvatarItemNameComparator
+{
+public:
+	LLAvatarItemRecentArrivalComparator() {};
+	virtual ~LLAvatarItemRecentArrivalComparator() {};
+
+protected:
+	virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const
+	{
+
+		F32 arr_time1 = LLRecentPeople::instance().getArrivalTimeByID(item1->getAvatarId());
+		F32 arr_time2 = LLRecentPeople::instance().getArrivalTimeByID(item2->getAvatarId());
+
+		if (arr_time1 == arr_time2)
+		{
+			std::string name1 = item1->getAvatarName();
+			std::string name2 = item2->getAvatarName();
+
+			LLStringUtil::toUpper(name1);
+			LLStringUtil::toUpper(name2);
+
+			return name1 < name2;
+		}
+
+		return arr_time1 > arr_time2;
+	}
+};
+
 static const LLAvatarItemRecentComparator RECENT_COMPARATOR;
 static const LLAvatarItemStatusComparator STATUS_COMPARATOR;
 static LLAvatarItemDistanceComparator DISTANCE_COMPARATOR;
 static const LLAvatarItemRecentSpeakerComparator RECENT_SPEAKER_COMPARATOR;
+static LLAvatarItemRecentArrivalComparator RECENT_ARRIVAL_COMPARATOR;
 
 static LLPanelInjector<LLPanelPeople> t_people("panel_people");
 
@@ -539,6 +568,8 @@ LLPanelPeople::LLPanelPeople()
 	mEnableCallbackRegistrar.add("People.Nearby.ViewSort.CheckItem",	boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck,	this, _2));
 
 	mEnableCallbackRegistrar.add("People.Group.Plus.Validate",	boost::bind(&LLPanelPeople::onGroupPlusButtonValidate,	this));
+
+	doPeriodically(boost::bind(&LLPanelPeople::updateNearbyArrivalTime, this), 2.0);
 }
 
 LLPanelPeople::~LLPanelPeople()
@@ -1049,6 +1080,10 @@ void LLPanelPeople::setSortOrder(LLAvatarList* list, ESortOrder order, bool save
 		list->setComparator(&DISTANCE_COMPARATOR);
 		list->sort();
 		break;
+	case E_SORT_BY_RECENT_ARRIVAL:
+		list->setComparator(&RECENT_ARRIVAL_COMPARATOR);
+		list->sort();
+		break;
 	default:
 		LL_WARNS() << "Unrecognized people sort order for " << list->getName() << LL_ENDL;
 		return;
@@ -1386,6 +1421,10 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)
 	{
 		setSortOrder(mNearbyList, E_SORT_BY_DISTANCE);
 	}
+	else if (chosen_item == "sort_arrival")
+	{
+		setSortOrder(mNearbyList, E_SORT_BY_RECENT_ARRIVAL);
+	}
 	else if (chosen_item == "view_usernames")
 	{
 	    bool hide_usernames = !gSavedSettings.getBOOL("NearbyListHideUsernames");
@@ -1407,6 +1446,8 @@ bool LLPanelPeople::onNearbyViewSortMenuItemCheck(const LLSD& userdata)
 		return sort_order == E_SORT_BY_NAME;
 	if (item == "sort_distance")
 		return sort_order == E_SORT_BY_DISTANCE;
+	if (item == "sort_arrival")
+		return sort_order == E_SORT_BY_RECENT_ARRIVAL;
 
 	return false;
 }
@@ -1594,5 +1635,15 @@ bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)
 	return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
 }
 
+bool LLPanelPeople::updateNearbyArrivalTime()
+{
+	std::vector<LLVector3d> positions;
+	std::vector<LLUUID> uuids;
+	static LLCachedControl<F32> range(gSavedSettings, "NearMeRange");
+	LLWorld::getInstance()->getAvatars(&uuids, &positions, gAgent.getPositionGlobal(), range);
+	LLRecentPeople::instance().updateAvatarsArrivalTime(uuids);
+	return LLApp::isExiting();
+}
+
 
 // EOF
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index eb7e76a77299f0c042d5f26f46da3551a17c27fb..c72c4fc08a2375fcc339e736509bad6f9d57b540 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -62,6 +62,8 @@ class LLPanelPeople
 	// internals
 	class Updater;
 
+	bool updateNearbyArrivalTime();
+
 private:
 
 	typedef enum e_sort_oder {
@@ -70,6 +72,7 @@ class LLPanelPeople
 		E_SORT_BY_MOST_RECENT = 2,
 		E_SORT_BY_DISTANCE = 3,
 		E_SORT_BY_RECENT_SPEAKERS = 4,
+		E_SORT_BY_RECENT_ARRIVAL = 5
 	} ESortOrder;
 
     void				    removePicker();
diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp
index 96818d5a21ab839d861a285f73cd707c883951ff..df93572508283b925c5caf22388adbd6a764dc7f 100644
--- a/indra/newview/llpresetsmanager.cpp
+++ b/indra/newview/llpresetsmanager.cpp
@@ -138,6 +138,11 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n
 	{
 		name = PRESETS_DEFAULT;
 	}
+	if (!createDefault && name == PRESETS_DEFAULT)
+	{
+		LL_WARNS() << "Should not overwrite default" << LL_ENDL;
+		return false;
+	}
 
 	bool saved = false;
 	std::vector<std::string> name_list;
diff --git a/indra/newview/llrecentpeople.cpp b/indra/newview/llrecentpeople.cpp
index 7689cd1a5251e8952a875fbc735e065d84779b11..83b0c4f1bf29b81484484906418170209341d30b 100644
--- a/indra/newview/llrecentpeople.cpp
+++ b/indra/newview/llrecentpeople.cpp
@@ -126,3 +126,33 @@ bool LLRecentPeople::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
 	add(event->getValue().asUUID());
 	return true;
 }
+
+void LLRecentPeople::updateAvatarsArrivalTime(uuid_vec_t& uuids)
+{
+	id_to_time_map_t buf = mAvatarsArrivalTime;
+	mAvatarsArrivalTime.clear();
+
+	for (uuid_vec_t::const_iterator id_it = uuids.begin(); id_it != uuids.end(); ++id_it)
+	{
+		if (buf.find(*id_it) != buf.end())
+		{
+			mAvatarsArrivalTime[*id_it] = buf[*id_it];
+		}
+		else
+		{
+			mAvatarsArrivalTime[*id_it] = LLDate::now().secondsSinceEpoch();
+		}
+	}
+}
+
+F32 LLRecentPeople::getArrivalTimeByID(const LLUUID& id)
+{
+	id_to_time_map_t::const_iterator it = mAvatarsArrivalTime.find(id);
+
+	if (it != mAvatarsArrivalTime.end())
+	{
+		return it->second;
+	}
+	return LLDate::now().secondsSinceEpoch();
+}
+
diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h
index c7aaf604f5dd554ce64d4d60f47f2cf5c80cbf70..1b4295ddad9509bec5e03f0e332981db889bd8ad 100644
--- a/indra/newview/llrecentpeople.h
+++ b/indra/newview/llrecentpeople.h
@@ -53,6 +53,7 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL
 	LLSINGLETON_EMPTY_CTOR(LLRecentPeople);
 	LOG_CLASS(LLRecentPeople);
 public:
+	typedef std::map <LLUUID, F32> id_to_time_map_t;
 	typedef boost::signals2::signal<void ()> signal_t;
 	
 	/**
@@ -116,6 +117,9 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL
 	 */
 	/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
 
+	void updateAvatarsArrivalTime(uuid_vec_t& uuids);
+	F32 getArrivalTimeByID(const LLUUID& id);
+
 private:
 
 	const LLUUID& getIDByPhoneNumber(const LLSD& userdata);
@@ -123,6 +127,7 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL
 	typedef std::map<LLUUID, LLSD> recent_people_t;
 	recent_people_t		mPeople;
 	signal_t			mChangedSignal;
+	id_to_time_map_t	mAvatarsArrivalTime;
 };
 
 #endif // LL_LLRECENTPEOPLE_H
diff --git a/indra/newview/llregioninfomodel.cpp b/indra/newview/llregioninfomodel.cpp
index 25d7be831f6de31599f3c6a9ea525a0349dff981..7daaa7ef8e80dfe4f42bccd7e5fa26eead47ba40 100644
--- a/indra/newview/llregioninfomodel.cpp
+++ b/indra/newview/llregioninfomodel.cpp
@@ -158,7 +158,7 @@ void LLRegionInfoModel::update(LLMessageSystem* msg)
 
 	// actually the "last set" sun hour, not the current sun hour. JC
 	msg->getF32(_PREHASH_RegionInfo, _PREHASH_SunHour, mSunHour);
-	LL_DEBUGS("Windlight Sync") << "Got region sun hour: " << mSunHour << LL_ENDL;
+	LL_DEBUGS("WindlightSync") << "Got region sun hour: " << mSunHour << LL_ENDL;
 
 	msg->getS32Fast(_PREHASH_RegionInfo2, _PREHASH_HardMaxAgents, mHardAgentLimit);
 
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index ddae109030c53d4218b72ae17b6993e205becc0d..fce21fa30af67a48fd131e7bf0ab458c7fee7146 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -3676,6 +3676,39 @@ void LLSelectMgr::selectForceDelete()
 		SEND_ONLY_ROOTS);
 }
 
+BOOL LLSelectMgr::selectGetEditMoveLinksetPermissions(bool &move, bool &modify)
+{
+    move = true;
+    modify = true;
+    bool selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
+
+    for (LLObjectSelection::iterator iter = getSelection()->begin();
+        iter != getSelection()->end(); iter++)
+    {
+        LLSelectNode* nodep = *iter;
+        LLViewerObject* object = nodep->getObject();
+        if (!object || !nodep->mValid)
+        {
+            move = false;
+            modify = false;
+            return FALSE;
+        }
+
+        LLViewerObject *root_object = object->getRootEdit();
+        bool this_object_movable = false;
+        if (object->permMove() && !object->isPermanentEnforced() &&
+            ((root_object == NULL) || !root_object->isPermanentEnforced()) &&
+            (object->permModify() || selecting_linked_set))
+        {
+            this_object_movable = true;
+        }
+        move = move && this_object_movable;
+        modify = modify && object->permModify();
+    }
+
+    return TRUE;
+}
+
 void LLSelectMgr::selectGetAggregateSaleInfo(U32 &num_for_sale,
 											 BOOL &is_for_sale_mixed, 
 											 BOOL &is_sale_price_mixed,
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index e965dd80d5859135ed09f96d5601ae68e995e700..87ac8993251787f3513c913b995453505a81f2bd 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -675,6 +675,11 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	// returns TRUE if all the nodes are valid. Accumulates
 	// permissions in the parameter.
 	BOOL selectGetPermissions(LLPermissions& perm);
+
+	// returns TRUE if all the nodes are valid. Depends onto "edit linked" state
+	// Children in linksets are a bit special - they require not only move permission
+	// but also modify if "edit linked" is set, since you move them relative to parent
+	BOOL selectGetEditMoveLinksetPermissions(bool &move, bool &modify);
 	
 	// Get a bunch of useful sale information for the object(s) selected.
 	// "_mixed" is true if not all objects have the same setting.
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index e6ea5c3784464d60e73e82d3cb6b4b5caa16991c..d7c2ecb758b84f5aa38720536d9ab56c12c5ba20 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -614,7 +614,7 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 		LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
 		if(ctl)
 		{
-			ctl->setTentative(TRUE);
+			ctl->setTentative(!ctl->getEnabled());
 			ctl->set(TRUE);
 		}
 	}
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index d0cff1464b5eaed7bcf58295f644c3f4892f751a..5a40af14a3c8239485915626280fa58aef838361 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -1050,7 +1050,7 @@ void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name)
             tid, LLAssetType::AT_TEXTURE, res_name, res_desc, 0,
             folder_type, inv_type,
             PERM_ALL, LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"),
-            expected_upload_cost));
+            expected_upload_cost, !outfit_snapshot));
 
         upload_new_resource(assetUploadInfo);
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 4666a1e053f1a322686c1f10c25a901e0d13f6f0..831b9e2d2a874696c28e69201fe28c64ba68f35c 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -246,6 +246,7 @@ static bool mLoginStatePastUI = false;
 
 const S32 DEFAULT_MAX_AGENT_GROUPS = 42;
 const S32 ALLOWED_MAX_AGENT_GROUPS = 500;
+const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds
 
 boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
 boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
@@ -1614,6 +1615,13 @@ bool idle_startup()
 			LLStartUp::setStartupState( STATE_INVENTORY_SEND );
 		}
 		display_startup();
+
+		if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT)
+		{
+			LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL;
+			LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
+			reset_login();
+		}
 		return FALSE;
 	}
 
diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index a20d69dd41c392e39589016e24d21e1dded23662..3c3c1c96ef99a7c285101803a77820cb66280ad8 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -116,6 +116,8 @@ void LLTeleportHistory::handleLoginComplete()
 
 void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 {
+	if (!gAgent.getRegion()) return;
+
 	if (!mTeleportHistoryStorage)
 	{
 		mTeleportHistoryStorage = LLTeleportHistoryStorage::getInstance();
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 6a8843cb4470ca38c41dfc973b1f326752bb0930..5082e166857b33187351cac15bf6c8c7d9f2d888 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -609,8 +609,8 @@ 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->flagHandleTouch()) 
-				  || (parent && parent->flagHandleTouch()))
+		else if ((!object || !object->isAttachment() || object->getClickAction() != CLICK_ACTION_DISABLED)
+				 && ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())))
 		{
 			show_highlight = true;
 			gViewerWindow->setCursor(UI_CURSOR_HAND);
diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp
index 70c6e97e0e3a3626c5b914d6a6b2c946e4b6af01..4804ef6ddcb4f19583a0de80acd9a9e410d02f09 100644
--- a/indra/newview/llviewerassettype.cpp
+++ b/indra/newview/llviewerassettype.cpp
@@ -84,6 +84,8 @@ LLViewerAssetDictionary::LLViewerAssetDictionary()
 	
 	addEntry(LLViewerAssetType::AT_PERSON, 				new ViewerAssetEntry(DAD_PERSON));
 
+	addEntry(LLViewerAssetType::AT_UNKNOWN,				new ViewerAssetEntry(DAD_NONE));
+
 	addEntry(LLViewerAssetType::AT_NONE, 				new ViewerAssetEntry(DAD_NONE));
     addEntry(LLViewerAssetType::AT_SETTINGS,            new ViewerAssetEntry(DAD_SETTINGS));
 };
diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp
index 6a81c312d36a46b1c5e635b1057d3743c5703187..2544f75926823bd088491e24be56564337bb451a 100644
--- a/indra/newview/llviewerassetupload.cpp
+++ b/indra/newview/llviewerassetupload.cpp
@@ -60,7 +60,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
         LLAssetType::EType assetType, std::string name, std::string description,
         S32 compressionInfo, LLFolderType::EType destinationType,
         LLInventoryType::EType inventoryType, U32 nextOWnerPerms,
-        U32 groupPerms, U32 everyonePerms, S32 expectedCost) :
+        U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) :
     mTransactionId(transactId),
     mAssetType(assetType),
     mName(name),
@@ -72,6 +72,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
     mGroupPerms(groupPerms),
     mEveryonePerms(everyonePerms),
     mExpectedUploadCost(expectedCost),
+    mShowInventory(showInventory),
     mFolderId(LLUUID::null),
     mItemId(LLUUID::null),
     mAssetId(LLAssetID::null)
@@ -81,7 +82,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
 LLResourceUploadInfo::LLResourceUploadInfo(std::string name, 
         std::string description, S32 compressionInfo, 
         LLFolderType::EType destinationType, LLInventoryType::EType inventoryType, 
-        U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost):
+        U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) :
     mName(name),
     mDescription(description),
     mCompressionInfo(compressionInfo),
@@ -91,6 +92,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(std::string name,
     mGroupPerms(groupPerms),
     mEveryonePerms(everyonePerms),
     mExpectedUploadCost(expectedCost),
+    mShowInventory(showInventory),
     mTransactionId(),
     mAssetType(LLAssetType::AT_NONE),
     mFolderId(LLUUID::null),
@@ -112,6 +114,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLAssetID assetId, LLAssetType::EType
     mGroupPerms(0),
     mEveryonePerms(0),
     mExpectedUploadCost(0),
+    mShowInventory(true),
     mTransactionId(),
     mFolderId(LLUUID::null),
     mItemId(LLUUID::null)
@@ -331,10 +334,11 @@ LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo(
     U32 nextOWnerPerms,
     U32 groupPerms,
     U32 everyonePerms,
-    S32 expectedCost) :
+    S32 expectedCost,
+    bool show_inventory) :
     LLResourceUploadInfo(name, description, compressionInfo,
     destinationType, inventoryType,
-    nextOWnerPerms, groupPerms, everyonePerms, expectedCost),
+    nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory),
     mFileName(fileName)
 {
 }
diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h
index e18b75489afed47e3b6baff7a67cb578be50b451..4241c22c3e851e50010b220adac96c4107d63972 100644
--- a/indra/newview/llviewerassetupload.h
+++ b/indra/newview/llviewerassetupload.h
@@ -53,7 +53,8 @@ class LLResourceUploadInfo
         U32 nextOWnerPerms,
         U32 groupPerms,
         U32 everyonePerms,
-        S32 expectedCost);
+        S32 expectedCost,
+        bool showInventory = true);
 
     virtual ~LLResourceUploadInfo()
     { }
@@ -79,7 +80,7 @@ class LLResourceUploadInfo
     S32                 getExpectedUploadCost() const { return mExpectedUploadCost; };
 
     virtual bool        showUploadDialog() const { return true; }
-    virtual bool        showInventoryPanel() const { return true; }
+    virtual bool        showInventoryPanel() const { return mShowInventory; }
 
     virtual std::string getDisplayName() const;
 
@@ -97,7 +98,8 @@ class LLResourceUploadInfo
         U32 nextOWnerPerms,
         U32 groupPerms,
         U32 everyonePerms,
-        S32 expectedCost);
+        S32 expectedCost,
+        bool showInventory = true);
 
     LLResourceUploadInfo(
         LLAssetID assetId,
@@ -130,6 +132,7 @@ class LLResourceUploadInfo
     LLUUID              mFolderId;
     LLUUID              mItemId;
     LLAssetID           mAssetId;
+    bool                mShowInventory;
 };
 
 //-------------------------------------------------------------------------
@@ -146,7 +149,8 @@ class LLNewFileResourceUploadInfo : public LLResourceUploadInfo
         U32 nextOWnerPerms,
         U32 groupPerms,
         U32 everyonePerms,
-        S32 expectedCost);
+        S32 expectedCost,
+        bool show_inventory = true);
 
     virtual LLSD        prepareUpload();
 
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index fd4315a319d25f2a9ed6aceb93856c0cb6903374..b89e1497a188d1b5435e377275090c1faf340f5d 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -716,7 +716,7 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL
 	if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) 
 	{
 		mKeyHandledByUI[translated_key] = FALSE;
-		LL_INFOS("Keyboard Handling") << "Key wasn't handled by UI!" << LL_ENDL;
+		LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL;
 	}
 	else
 	{
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index b33da233f54c7f39b5838cb5a28d62d4e812bd31..26f0ec7905886d5bd59edb0fffd6973933fc59ad 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -130,6 +130,7 @@
 #include "llpathfindingmanager.h"
 #include "llstartup.h"
 #include "boost/unordered_map.hpp"
+#include <boost/regex.hpp>
 #include "llcleanup.h"
 #include "llviewershadermgr.h"
 
@@ -8022,7 +8023,12 @@ void handle_report_bug(const LLSD& param)
 	LLUIString url(param.asString());
 	
 	LLStringUtil::format_map_t replace;
-	replace["[ENVIRONMENT]"] = LLURI::escape(LLAppViewer::instance()->getViewerInfoString(true));
+	std::string environment = LLAppViewer::instance()->getViewerInfoString(true);
+	boost::regex regex;
+	regex.assign("</?nolink>");
+	std::string stripped_env = boost::regex_replace(environment, regex, "");
+
+	replace["[ENVIRONMENT]"] = LLURI::escape(stripped_env);
 	LLSLURL location_url;
 	LLAgentUI::buildSLURL(location_url);
 	replace["[LOCATION]"] = LLURI::escape(location_url.getSLURLString());
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 78e564588122524fc3755cf5adcc69b08049f1c3..bb557fbdaa8766d4765a0f5b554acb1d962649e8 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -689,7 +689,8 @@ LLUUID upload_new_resource(
 	const std::string& display_name,
 	LLAssetStorage::LLStoreAssetCallback callback,
 	S32 expected_upload_cost,
-	void *userdata)
+	void *userdata,
+	bool show_inventory)
 {	
 
     LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewFileResourceUploadInfo>(
@@ -697,7 +698,7 @@ LLUUID upload_new_resource(
         name, desc, compression_info,
         destination_folder_type, inv_type,
         next_owner_perms, group_perms, everyone_perms,
-        expected_upload_cost));
+        expected_upload_cost, show_inventory));
     upload_new_resource(uploadInfo, callback, userdata);
 
     return LLUUID::null;
diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h
index 2647b367a02ec2f578ed5758529091b058fa0f54..4e6250d9b40f77192f7770e58997cf42364ff8a1 100644
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -55,7 +55,8 @@ LLUUID upload_new_resource(
     const std::string& display_name,
     LLAssetStorage::LLStoreAssetCallback callback,
     S32 expected_upload_cost,
-    void *userdata);
+    void *userdata,
+    bool show_inventory = true);
 
 void upload_new_resource(
     LLResourceUploadInfo::ptr_t &uploadInfo,
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 9d9738fa600d7727be66a64b7a82e802a1e16213..04cfe270fe0d9ef4bdb379778069167c4e464059 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -169,7 +169,8 @@ void accept_friendship_coro(std::string url, LLSD notification)
     url += "?from=" + payload["from_id"].asString();
     url += "&agent_name=\"" + LLURI::escape(gAgentAvatarp->getFullname()) + "\"";
 
-    LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+    LLSD data;
+    LLSD result = httpAdapter->postAndSuspend(httpRequest, url, data);
 
     LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
     LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -199,20 +200,20 @@ void accept_friendship_coro(std::string url, LLSD notification)
 
 void decline_friendship_coro(std::string url, LLSD notification, S32 option)
 {
-    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
-    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
-        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("friendshipResponceErrorProcessing", httpPolicy));
-    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
     if (url.empty())
     {
         LL_WARNS("Friendship") << "Empty capability!" << LL_ENDL;
         return;
     }
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("friendshipResponceErrorProcessing", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
 
     LLSD payload = notification["payload"];
     url += "?from=" + payload["from_id"].asString();
 
-    LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+    LLSD result = httpAdapter->deleteAndSuspend(httpRequest, url);
 
     LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
     LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
@@ -732,6 +733,122 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain)
 static LLSD sSavedGroupInvite;
 static LLSD sSavedResponse;
 
+void response_group_invitation_coro(std::string url, LLUUID group_id, bool notify_and_update)
+{
+    if (url.empty())
+    {
+        LL_WARNS("GroupInvite") << "Empty capability!" << LL_ENDL;
+        return;
+    }
+
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("responseGroupInvitation", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+    LLSD payload;
+    payload["group"] = group_id;
+
+    LLSD result = httpAdapter->postAndSuspend(httpRequest, url, payload);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+    if (!status)
+    {
+        LL_WARNS("GroupInvite") << "HTTP status, " << status.toTerseString() <<
+            ". Group " << group_id << " invitation response processing failed." << LL_ENDL;
+    }
+    else
+    {
+        if (!result.has("success") || result["success"].asBoolean() == false)
+        {
+            LL_WARNS("GroupInvite") << "Server failed to process group " << group_id << " invitation response. " << httpResults << LL_ENDL;
+        }
+        else
+        {
+            LL_DEBUGS("GroupInvite") << "Successfully sent response to group " << group_id << " invitation" << LL_ENDL;
+            if (notify_and_update)
+            {
+                LLNotificationsUtil::add("JoinGroupSuccess");
+                gAgent.sendAgentDataUpdateRequest();
+
+                LLGroupMgr::getInstance()->clearGroupData(group_id);
+                // refresh the floater for this group, if any.
+                LLGroupActions::refresh(group_id);
+            }
+        }
+    }
+}
+
+void send_join_group_response(LLUUID group_id, LLUUID transaction_id, bool accept_invite, S32 fee, bool use_offline_cap, LLSD &payload)
+{
+    if (accept_invite && fee > 0)
+    {
+        // If there is a fee to join this group, make
+        // sure the user is sure they want to join.
+            LLSD args;
+            args["COST"] = llformat("%d", fee);
+            // Set the fee for next time to 0, so that we don't keep
+            // asking about a fee.
+            LLSD next_payload = payload;
+            next_payload["fee"] = 0;
+            LLNotificationsUtil::add("JoinGroupCanAfford",
+                args,
+                next_payload);
+    }
+    else if (use_offline_cap)
+    {
+        std::string url;
+        if (accept_invite)
+        {
+            url = gAgent.getRegionCapability("AcceptGroupInvite");
+        }
+        else
+        {
+            url = gAgent.getRegionCapability("DeclineGroupInvite");
+        }
+
+        if (!url.empty())
+        {
+            LL_DEBUGS("GroupInvite") << "Capability url: " << url << LL_ENDL;
+            LLCoros::instance().launch("LLMessageSystem::acceptGroupInvitation",
+                boost::bind(response_group_invitation_coro, url, group_id, accept_invite));
+        }
+        else
+        {
+            // if sim has no this cap, we can do nothing - regular request will fail
+            LL_WARNS("GroupInvite") << "No capability, can't reply to offline invitation!" << LL_ENDL;
+        }
+    }
+    else
+    {
+        LL_DEBUGS("GroupInvite") << "Replying to group invite via IM message" << LL_ENDL;
+
+        EInstantMessage type = accept_invite ? IM_GROUP_INVITATION_ACCEPT : IM_GROUP_INVITATION_DECLINE;
+
+        send_improved_im(group_id,
+            std::string("name"),
+            std::string("message"),
+            IM_ONLINE,
+            type,
+            transaction_id);
+    }
+}
+
+void send_join_group_response(LLUUID group_id, LLUUID transaction_id, bool accept_invite, S32 fee, bool use_offline_cap)
+{
+    LLSD payload;
+    if (accept_invite)
+    {
+        payload["group_id"] = group_id;
+        payload["transaction_id"] =  transaction_id;
+        payload["fee"] =  fee;
+        payload["use_offline_cap"] = use_offline_cap;
+    }
+    send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, payload);
+}
+
 bool join_group_response(const LLSD& notification, const LLSD& response)
 {
 //	A bit of variable saving and restoring is used to deal with the case where your group list is full and you
@@ -770,6 +887,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response)
 	std::string name = notification_adjusted["payload"]["name"].asString();
 	std::string message = notification_adjusted["payload"]["message"].asString();
 	S32 fee = notification_adjusted["payload"]["fee"].asInteger();
+	U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger();
 
 	if (option == 2 && !group_id.isNull())
 	{
@@ -798,42 +916,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response)
 			return false;
 		}
 	}
-
-	if (accept_invite)
-	{
-		// If there is a fee to join this group, make
-		// sure the user is sure they want to join.
-		if (fee > 0)
-		{
-			LLSD args;
-			args["COST"] = llformat("%d", fee);
-			// Set the fee for next time to 0, so that we don't keep
-			// asking about a fee.
-			LLSD next_payload = notification_adjusted["payload"];
-			next_payload["fee"] = 0;
-			LLNotificationsUtil::add("JoinGroupCanAfford",
-									args,
-									next_payload);
-		}
-		else
-		{
-			send_improved_im(group_id,
-							 std::string("name"),
-							 std::string("message"),
-							IM_ONLINE,
-							IM_GROUP_INVITATION_ACCEPT,
-							transaction_id);
-		}
-	}
-	else
-	{
-		send_improved_im(group_id,
-						 std::string("name"),
-						 std::string("message"),
-						IM_ONLINE,
-						IM_GROUP_INVITATION_DECLINE,
-						transaction_id);
-	}
+	send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]);
 
 	sSavedGroupInvite[id] = LLSD::emptyMap();
 	sSavedResponse[id] = LLSD::emptyMap();
@@ -1740,7 +1823,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 		//don't spam them if they are getting flooded
 		if (check_offer_throttle(mFromName, true))
 		{
-			log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
+			log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString(".");
 			LLSD args;
 			args["MESSAGE"] = log_message;
 			LLNotificationsUtil::add("SystemMessageTip", args);
@@ -1925,7 +2008,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 			//don't spam them if they are getting flooded
 			if (check_offer_throttle(mFromName, true))
 			{
-				log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
+				log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString(".");
 				LLSD args;
 				args["MESSAGE"] = log_message;
 				LLNotificationsUtil::add("SystemMessageTip", args);
@@ -1998,6 +2081,23 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 	return false;
 }
 
+std::string LLOfferInfo::getSanitizedDescription()
+{
+	// currently we get description from server as: 'Object' ( Location )
+	// object name shouldn't be shown as a hyperlink
+	std::string description = mDesc;
+
+	std::size_t start = mDesc.find_first_of("'");
+	std::size_t end = mDesc.find_last_of("'");
+	if ((start != std::string::npos) && (end != std::string::npos))
+	{
+		description.insert(start, "<nolink>");
+		description.insert(end + 8, "</nolink>");
+	}
+	return description;
+}
+
+
 void LLOfferInfo::initRespondFunctionMap()
 {
 	if(mRespondFunctions.empty())
@@ -2609,6 +2709,12 @@ void process_teleport_start(LLMessageSystem *msg, void**)
 	U32 teleport_flags = 0x0;
 	msg->getU32("Info", "TeleportFlags", teleport_flags);
 
+	if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING)
+	{
+		// Race condition?
+		LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL;
+	}
+
 	LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL;
 
 	// *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM
@@ -2666,7 +2772,7 @@ void process_teleport_progress(LLMessageSystem* msg, void**)
 	}
 	std::string buffer;
 	msg->getString("Info", "Message", buffer);
-	LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL;
+	LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL;
 
 	//Sorta hacky...default to using simulator raw messages
 	//if we don't find the coresponding mapping in our progress mappings
@@ -2789,9 +2895,25 @@ void process_teleport_finish(LLMessageSystem* msg, void**)
 
     if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)
     {
-        // Server either ignored teleport cancel message or did not receive it in time.
-        // This message can't be ignored since teleport is complete at server side
-        gAgent.restoreCanceledTeleportRequest();
+        if (gAgent.canRestoreCanceledTeleport())
+        {
+            // Server either ignored teleport cancel message or did not receive it in time.
+            // This message can't be ignored since teleport is complete at server side
+            gAgent.restoreCanceledTeleportRequest();
+        }
+        else
+        {
+            // Race condition? Make sure all variables are set correctly for teleport to work
+            LL_WARNS("Messaging") << "Teleport 'finish' message without 'start'" << LL_ENDL;
+            gTeleportDisplay = TRUE;
+            LLViewerMessage::getInstance()->mTeleportStartedSignal();
+            gAgent.setTeleportState(LLAgent::TELEPORT_REQUESTED);
+            make_ui_sound("UISndTeleportOut");
+        }
+    }
+    else if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING)
+    {
+        LL_WARNS("Messaging") << "Teleport message in the middle of other teleport" << LL_ENDL;
     }
 	
 	// Teleport is finished; it can't be cancelled now.
@@ -3656,7 +3778,7 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data)
 
 	LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec);
 
-	LL_DEBUGS("Windlight Sync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL;
+	LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL;
 
     
 	/* LAPRAS
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index b0eaa37541db4af72b8eb4c7ccda1bf30e0de7a3..913abef2be5dc1ab5f8bc22a0ea52a2d17da5721 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -66,6 +66,11 @@ enum InventoryOfferResponse
 BOOL can_afford_transaction(S32 cost);
 void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group = FALSE,
 				S32 trx_type = TRANS_GIFT, const std::string& desc = LLStringUtil::null);
+void send_join_group_response(LLUUID group_id,
+							  LLUUID transaction_id,
+							  bool accept_invite,
+							  S32 fee,
+							  bool use_offline_cap);
 
 void process_logout_reply(LLMessageSystem* msg, void**);
 void process_layer_data(LLMessageSystem *mesgsys, void **user_data);
@@ -257,6 +262,7 @@ class LLOfferInfo : public LLNotificationResponderInterface
 private:
 
 	void initRespondFunctionMap();
+	std::string getSanitizedDescription();
 
 	typedef boost::function<bool (const LLSD&, const LLSD&)> respond_function_t;
 	typedef std::map<std::string, respond_function_t> respond_function_map_t;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index e3c6b371908d8884ece2046c6373c14319f11faa..263750dee4446ee566b0033f04612cdf64c958e5 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2818,7 +2818,8 @@ void LLViewerRegion::unpackRegionHandshake()
 void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 {
 	capabilityNames.append("AbuseCategories");
-	//capabilityNames.append("AcceptFriendship");
+	capabilityNames.append("AcceptFriendship");
+	capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!!
 	capabilityNames.append("AgentPreferences");
 	capabilityNames.append("AgentState");
 	capabilityNames.append("AttachmentResources");
@@ -2828,7 +2829,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("ChatSessionRequest");
 	capabilityNames.append("CopyInventoryFromNotecard");
 	capabilityNames.append("CreateInventoryCategory");
-	//capabilityNames.append("DeclineFriendship");
+	capabilityNames.append("DeclineFriendship");
+	capabilityNames.append("DeclineGroupInvite"); // ReadOfflineMsgs recieved messages only!!!
 	capabilityNames.append("DispatchRegionInfo");
 	capabilityNames.append("DirectDelivery");
 	capabilityNames.append("EnvironmentSettings");
@@ -2880,7 +2882,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("ParcelVoiceInfoRequest");
 	capabilityNames.append("ProductInfoRequest");
 	capabilityNames.append("ProvisionVoiceAccountRequest");
-	//capabilityNames.append("ReadOfflineMsgs");
+	capabilityNames.append("ReadOfflineMsgs"); // Requires to respond reliably: AcceptFriendship, AcceptGroupInvite, DeclineFriendship, DeclineGroupInvite
 	capabilityNames.append("RemoteParcelRequest");
 	capabilityNames.append("RenderMaterials");
 	capabilityNames.append("RequestTextureDownload");
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index c38f19f5790d24d01af23dc0b4d1aaf6783183e6..82932ef6ae0ac7edb19a0171afebe130828f1c41 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -110,6 +110,12 @@ const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve
 const F32 desired_discard_bias_max = (F32)MAX_DISCARD_LEVEL; // max number of levels to reduce image quality by
 const F64 log_2 = log(2.0);
 
+#if ADDRESS_SIZE == 32
+const U32 DESIRED_NORMAL_FETCHED_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT / 2;
+#else
+const U32 DESIRED_NORMAL_FETCHED_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT;
+#endif
+
 //----------------------------------------------------------------------------------------------
 //namespace: LLViewerTextureAccess
 //----------------------------------------------------------------------------------------------
@@ -1578,12 +1584,17 @@ void LLViewerFetchedTexture::processTextureStats()
 			mDesiredDiscardLevel = 	llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel);
 		}
 		else
-		{	
+		{
+			U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
+			if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED)
+			{
+				desired_size = DESIRED_NORMAL_FETCHED_TEXTURE_SIZE;
+			}
 			if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight)
 			{
-				if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
+				if (mFullWidth > desired_size || mFullHeight > desired_size)
 				{
-					mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
+					mDesiredDiscardLevel = 1;
 				}
 				else
 				{
@@ -3197,8 +3208,13 @@ void LLViewerLODTexture::processTextureStats()
 		discard_level = floorf(discard_level);
 
 		F32 min_discard = 0.f;
-		if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
-			min_discard = 1.f; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
+		U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
+		if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED)
+		{
+			desired_size = DESIRED_NORMAL_FETCHED_TEXTURE_SIZE;
+		}
+		if (mFullWidth > desired_size || mFullHeight > desired_size)
+			min_discard = 1.f;
 
 		discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL);
 		
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 893e7620d2944be6964fe35a31da7d8c3ad88702..58f26d6a2b10ec1ec8318261c4a6a9dc3bedb2fc 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3826,37 +3826,22 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls,
 			{
 				if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() )
 				{
-					BOOL moveable_object_selected = FALSE;
-					BOOL all_selected_objects_move = TRUE;
-					BOOL all_selected_objects_modify = TRUE;
-					BOOL selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
-
-					for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
-						 iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
-					{
-						LLSelectNode* nodep = *iter;
-						LLViewerObject* object = nodep->getObject();
-						LLViewerObject *root_object = (object == NULL) ? NULL : object->getRootEdit();
-						BOOL this_object_movable = FALSE;
-						if (object->permMove() && !object->isPermanentEnforced() &&
-							((root_object == NULL) || !root_object->isPermanentEnforced()) &&
-							(object->permModify() || selecting_linked_set))
-						{
-							moveable_object_selected = TRUE;
-							this_object_movable = TRUE;
-						}
-						all_selected_objects_move = all_selected_objects_move && this_object_movable;
-						all_selected_objects_modify = all_selected_objects_modify && object->permModify();
-					}
+					bool all_selected_objects_move;
+					bool all_selected_objects_modify;
+					// Note: This might be costly to do on each frame and when a lot of objects are selected
+					// we might be better off with some kind of memory for selection and/or states, consider
+					// optimizing, perhaps even some kind of selection generation at level of LLSelectMgr to
+					// make whole viewer benefit.
+					LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(all_selected_objects_move, all_selected_objects_modify);
 
 					BOOL draw_handles = TRUE;
 
-					if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
+					if (tool == LLToolCompTranslate::getInstance() && !all_selected_objects_move)
 					{
 						draw_handles = FALSE;
 					}
 
-					if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
+					if (tool == LLToolCompRotate::getInstance() && !all_selected_objects_move)
 					{
 						draw_handles = FALSE;
 					}
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index c58e98b3fb4f97b66eccd436a4b8c499acf99694..f971554c9dec325563225c1c4d109fb27769d245 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -74,10 +74,18 @@ LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& sess
 
 LLVoiceChannel::~LLVoiceChannel()
 {
-	// Must check instance exists here, the singleton MAY have already been destroyed.
-	if(LLVoiceClient::instanceExists())
+	if (sSuspendedVoiceChannel == this)
 	{
-		LLVoiceClient::getInstance()->removeObserver(this);
+		sSuspendedVoiceChannel = NULL;
+	}
+	if (sCurrentVoiceChannel == this)
+	{
+		sCurrentVoiceChannel = NULL;
+		// Must check instance exists here, the singleton MAY have already been destroyed.
+		if(LLVoiceClient::instanceExists())
+		{
+			LLVoiceClient::getInstance()->removeObserver(this);
+		}
 	}
 	
 	sVoiceChannelMap.erase(mSessionID);
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index b90e09b739da99256e3f62e42ace4816e4eebcb6..b039afa73418b118a8fed76aa87afc7c1e283df1 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -456,7 +456,7 @@ void LLVivoxVoiceClient::updateSettings()
 bool LLVivoxVoiceClient::writeString(const std::string &str)
 {
 	bool result = false;
-    LL_DEBUGS("LOW Voice") << "sending:\n" << str << LL_ENDL;
+    LL_DEBUGS("LowVoice") << "sending:\n" << str << LL_ENDL;
 
 	if(mConnected)
 	{
@@ -7270,12 +7270,12 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
 	if (isEvent)
 	{
 		const char *eventTypeCstr = eventTypeString.c_str();
-        LL_DEBUGS("LOW Voice") << eventTypeCstr << LL_ENDL;
+        LL_DEBUGS("LowVoice") << eventTypeCstr << LL_ENDL;
 
 		if (!stricmp(eventTypeCstr, "ParticipantUpdatedEvent"))
 		{
 			// These happen so often that logging them is pretty useless.
-            LL_DEBUGS("LOW Voice") << "Updated Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << isModeratorMuted << ", " << isSpeaking << ", " << volume << ", " << energy << LL_ENDL;
+            LL_DEBUGS("LowVoice") << "Updated Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << isModeratorMuted << ", " << isSpeaking << ", " << volume << ", " << energy << LL_ENDL;
             LLVivoxVoiceClient::getInstance()->participantUpdatedEvent(sessionHandle, sessionGroupHandle, uriString, alias, isModeratorMuted, isSpeaking, volume, energy);
 		}
 		else if (!stricmp(eventTypeCstr, "AccountLoginStateChangeEvent"))
@@ -7344,7 +7344,7 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
 			 <ParticipantType>0</ParticipantType>
 			 </Event>
 			 */
-            LL_DEBUGS("LOW Voice") << "Added Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << ", " << displayNameString << ", " << participantType << LL_ENDL;
+            LL_DEBUGS("LowVoice") << "Added Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << ", " << displayNameString << ", " << participantType << LL_ENDL;
 			LLVivoxVoiceClient::getInstance()->participantAddedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString, displayNameString, participantType);
 		}
 		else if (!stricmp(eventTypeCstr, "ParticipantRemovedEvent"))
@@ -7357,7 +7357,7 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
 			 <AccountName>xtx7YNV-3SGiG7rA1fo5Ndw==</AccountName>
 			 </Event>
 			 */
-            LL_DEBUGS("LOW Voice") << "Removed params:" << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << LL_ENDL;
+            LL_DEBUGS("LowVoice") << "Removed params:" << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << LL_ENDL;
 
 			LLVivoxVoiceClient::getInstance()->participantRemovedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString);
 		}
@@ -7424,7 +7424,7 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
 	else
 	{
 		const char *actionCstr = actionString.c_str();
-        LL_DEBUGS("LOW Voice") << actionCstr << LL_ENDL;
+        LL_DEBUGS("LowVoice") << actionCstr << LL_ENDL;
 
 		if (!stricmp(actionCstr, "Session.Set3DPosition.1"))
 		{
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index b816225b072517bc51de2ba1392be260be4575e5..768db047a421bb7cb76276038b8dffcf415c3342 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -268,6 +268,12 @@ bool LLWeb::useExternalBrowser(const std::string &url)
 		boost::match_results<std::string::const_iterator> matches;
 		return !(boost::regex_search(uri_string, matches, pattern));
 	}
+	else
+	{
+		boost::regex pattern = boost::regex("^mailto:", boost::regex::perl | boost::regex::icase);
+		boost::match_results<std::string::const_iterator> matches;
+		return boost::regex_search(url, matches, pattern);
+	}
 	return false;
 #endif
 }
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index 837b30586b7b1800dd4d5c72e7299f7032911e3b..cbb6e85b96af1138fc4a06f2f46119aa244e147a 100644
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -172,7 +172,7 @@ void LLSimInfo::dump() const
 	U32 x_pos, y_pos;
 	from_region_handle(mHandle, &x_pos, &y_pos);
 
-	LL_INFOS("World Map") << x_pos << "," << y_pos
+	LL_INFOS("WorldMap") << x_pos << "," << y_pos
 		<< " " << mName 
 		<< " " << (S32)mAccess
 		<< " " << std::hex << mRegionFlags << std::dec
@@ -229,7 +229,7 @@ LLWorldMap::LLWorldMap() :
 	mTrackingLocation( 0, 0, 0 ),
 	mFirstRequest(true)
 {
-	//LL_INFOS("World Map") << "Creating the World Map -> LLWorldMap::LLWorldMap()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << "Creating the World Map -> LLWorldMap::LLWorldMap()" << LL_ENDL;
 	mMapBlockLoaded = new bool[MAP_BLOCK_RES*MAP_BLOCK_RES];
 	clearSimFlags();
 }
@@ -237,7 +237,7 @@ LLWorldMap::LLWorldMap() :
 
 LLWorldMap::~LLWorldMap()
 {
-	//LL_INFOS("World Map") << "Destroying the World Map -> LLWorldMap::~LLWorldMap()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << "Destroying the World Map -> LLWorldMap::~LLWorldMap()" << LL_ENDL;
 	reset();
 	delete[] mMapBlockLoaded;
 }
@@ -375,7 +375,7 @@ bool LLWorldMap::simNameFromPosGlobal(const LLVector3d& pos_global, std::string
 
 void LLWorldMap::reloadItems(bool force)
 {
-	//LL_INFOS("World Map") << "LLWorldMap::reloadItems()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << "LLWorldMap::reloadItems()" << LL_ENDL;
 	if (clearItems(force))
 	{
 		LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_TELEHUB);
@@ -407,7 +407,7 @@ bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUI
 	else
 	{
 		U64 handle = to_region_handle(x_world, y_world);
- 		//LL_INFOS("World Map") << "Map sim : " << name << ", ID : " << image_id.getString() << LL_ENDL;
+ 		//LL_INFOS("WorldMap") << "Map sim : " << name << ", ID : " << image_id.getString() << LL_ENDL;
 		// Insert the region in the region map of the world map
 		// Loading the LLSimInfo object with what we got and insert it in the map
 		LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
@@ -459,7 +459,7 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID&
 		siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle);
 	}
 
-	//LL_INFOS("World Map") << "Process item : type = " << type << LL_ENDL;
+	//LL_INFOS("WorldMap") << "Process item : type = " << type << LL_ENDL;
 	switch (type)
 	{
 		case MAP_ITEM_TELEHUB: // telehubs
@@ -553,7 +553,7 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID&
 		}
 		case MAP_ITEM_AGENT_LOCATIONS: // agent locations
 		{
-// 				LL_INFOS("World Map") << "New Location " << new_item.mName << LL_ENDL;
+// 				LL_INFOS("WorldMap") << "New Location " << new_item.mName << LL_ENDL;
 			if (extra > 0)
 			{
 				new_item.setCount(extra);
@@ -604,7 +604,7 @@ void LLWorldMap::updateRegions(S32 x0, S32 y0, S32 x1, S32 y1)
 			S32 offset = block_x | (block_y * MAP_BLOCK_RES);
 			if (!mMapBlockLoaded[offset])
 			{
- 				//LL_INFOS("World Map") << "Loading Block (" << block_x << "," << block_y << ")" << LL_ENDL;
+ 				//LL_INFOS("WorldMap") << "Loading Block (" << block_x << "," << block_y << ")" << LL_ENDL;
 				LLWorldMapMessage::getInstance()->sendMapBlockRequest(block_x * MAP_BLOCK_SIZE, block_y * MAP_BLOCK_SIZE, (block_x * MAP_BLOCK_SIZE) + MAP_BLOCK_SIZE - 1, (block_y * MAP_BLOCK_SIZE) + MAP_BLOCK_SIZE - 1);
 				mMapBlockLoaded[offset] = true;
 			}
@@ -614,7 +614,7 @@ void LLWorldMap::updateRegions(S32 x0, S32 y0, S32 x1, S32 y1)
 
 void LLWorldMap::dump()
 {
-	LL_INFOS("World Map") << "LLWorldMap::dump()" << LL_ENDL;
+	LL_INFOS("WorldMap") << "LLWorldMap::dump()" << LL_ENDL;
 	for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
 	{
 		LLSimInfo* info = it->second;
diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp
index 865292fa90f38eeec1e09c054329577a0cefd710..8be340de4c42ec8d95073e2b8e7ae8616502d80e 100644
--- a/indra/newview/llworldmapmessage.cpp
+++ b/indra/newview/llworldmapmessage.cpp
@@ -54,7 +54,7 @@ LLWorldMapMessage::~LLWorldMapMessage()
 
 void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle)
 {
-	//LL_INFOS("World Map") << "Send item request : type = " << type << LL_ENDL;
+	//LL_INFOS("WorldMap") << "Send item request : type = " << type << LL_ENDL;
 	LLMessageSystem* msg = gMessageSystem;
 
 	msg->newMessageFast(_PREHASH_MapItemRequest);
@@ -74,7 +74,7 @@ void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle)
 
 void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name)
 {
-	//LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << LL_ENDL;
 	LLMessageSystem* msg = gMessageSystem;
 
 	// Request for region data
@@ -95,7 +95,7 @@ void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name,
 		const std::string& callback_url,
 		bool teleport)	// immediately teleport when result returned
 {
-	//LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << LL_ENDL;
 	mSLURLRegionName = region_name;
 	mSLURLRegionHandle = 0;
 	mSLURL = callback_url;
@@ -110,7 +110,7 @@ void LLWorldMapMessage::sendHandleRegionRequest(U64 region_handle,
 		const std::string& callback_url,
 		bool teleport)	// immediately teleport when result returned
 {
-	//LL_INFOS("World Map") << "LLWorldMap::sendHandleRegionRequest()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << LL_ENDL;
 	mSLURLRegionName.clear();
 	mSLURLRegionHandle = region_handle;
 	mSLURL = callback_url;
@@ -128,7 +128,7 @@ void LLWorldMapMessage::sendHandleRegionRequest(U64 region_handle,
 
 void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent)
 {
-	//LL_INFOS("World Map") << "LLWorldMap::sendMapBlockRequest()" << ", min = (" << min_x << ", " << min_y << "), max = (" << max_x << ", " << max_y << "), nonexistent = " << return_nonexistent << LL_ENDL;
+	//LL_INFOS("WorldMap" << " min = (" << min_x << ", " << min_y << "), max = (" << max_x << ", " << max_y << ", nonexistent = " << return_nonexistent << LL_ENDL;
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_MapBlockRequest);
 	msg->nextBlockFast(_PREHASH_AgentData);
@@ -161,7 +161,7 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**)
 	}
 
 	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data);
-	//LL_INFOS("World Map") << "LLWorldMap::processMapBlockReply(), num_blocks = " << num_blocks << LL_ENDL;
+	//LL_INFOS("WorldMap") << "num_blocks = " << num_blocks << LL_ENDL;
 
 	bool found_null_sim = false;
 
@@ -233,7 +233,7 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**)
 // public static
 void LLWorldMapMessage::processMapItemReply(LLMessageSystem* msg, void**)
 {
-	//LL_INFOS("World Map") << "LLWorldMap::processMapItemReply()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << LL_ENDL;
 	U32 type;
 	msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type);
 
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 9ae788a40910a4b6c002ee2ba61462f3221565e0..707fe76cef19d12d62f2a18833a27f1c4082391d 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -177,7 +177,7 @@ LLWorldMapView::LLWorldMapView()
 	mMouseDownY( 0 ),
 	mSelectIDStart(0)
 {
-	//LL_INFOS("World Map") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL;
 
 	clearLastClick();
 }
@@ -217,7 +217,7 @@ BOOL LLWorldMapView::postBuild()
 
 LLWorldMapView::~LLWorldMapView()
 {
-	//LL_INFOS("World Map") << "Destroying the map -> LLWorldMapView::~LLWorldMapView()" << LL_ENDL;
+	//LL_INFOS("WorldMap") << "Destroying the map -> LLWorldMapView::~LLWorldMapView()" << LL_ENDL;
 	cleanupTextures();
 }
 
@@ -616,7 +616,7 @@ void LLWorldMapView::drawMipmap(S32 width, S32 height)
 	}
 	else
 	{
-		//LL_INFOS("World Map") << "Render complete, don't draw background..." << LL_ENDL;
+		//LL_INFOS("WorldMap") << "Render complete, don't draw background..." << LL_ENDL;
 	}
 
 	// Render the current level
@@ -705,7 +705,7 @@ bool LLWorldMapView::drawMipmapLevel(S32 width, S32 height, S32 level, bool load
 				//else
 				//{
 				//	Waiting for a tile -> the level is not complete
-				//	LL_INFOS("World Map") << "Unfetched tile. level = " << level << LL_ENDL;
+				//	LL_INFOS("WorldMap") << "Unfetched tile. level = " << level << LL_ENDL;
 				//}
 			}
 			else
@@ -1668,7 +1668,7 @@ void LLWorldMapView::updateVisibleBlocks()
 	S32 world_bottom = world_center_y - S32(half_height / sMapScale) - 1;
 	S32 world_top    = world_center_y + S32(half_height / sMapScale) + 1;
 
-	//LL_INFOS("World Map") << "LLWorldMapView::updateVisibleBlocks() : sMapScale = " << sMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom  = " << world_bottom << ", top = " << world_top << LL_ENDL;
+	//LL_INFOS("WorldMap") << "LLWorldMapView::updateVisibleBlocks() : sMapScale = " << sMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom  = " << world_bottom << ", top = " << world_top << LL_ENDL;
 	LLWorldMap::getInstance()->updateRegions(world_left, world_bottom, world_right, world_top);
 }
 
diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp
index 895ccaef5a1fafe98d02b6bf21af16b8fc3e4ed3..a2e519a61aa14057f5f29c24df900fc5e5fc76bb 100644
--- a/indra/newview/llworldmipmap.cpp
+++ b/indra/newview/llworldmipmap.cpp
@@ -100,7 +100,7 @@ void LLWorldMipmap::equalizeBoostLevels()
 		}
 	}
 #if DEBUG_TILES_STAT
-	LL_INFOS("World Map") << "LLWorldMipmap tile stats : total requested = " << nb_tiles << ", visible = " << nb_visible << ", missing = " << nb_missing << LL_ENDL;
+	LL_INFOS("WorldMap") << "LLWorldMipmap tile stats : total requested = " << nb_tiles << ", visible = " << nb_visible << ", missing = " << nb_missing << LL_ENDL;
 #endif // DEBUG_TILES_STAT
 }
 
@@ -187,7 +187,7 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32
 	// Use a local jpeg for every tile to test map speed without S3 access
 	//imageurl = "file://C:\\Develop\\mapserver-distribute-3\\indra\\build-vc80\\mapserver\\relwithdebinfo\\regions\\00995\\01001\\region-995-1001-prims.jpg";
 	// END DEBUG
-	//LL_INFOS("World Map") << "LLWorldMipmap::loadObjectsTile(), URL = " << imageurl << LL_ENDL;
+	//LL_INFOS("WorldMap") << "LLWorldMipmap::loadObjectsTile(), URL = " << imageurl << LL_ENDL;
 
 	LLPointer<LLViewerFetchedTexture> img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, FTT_MAP_TILE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
 	img->setBoostLevel(LLGLTexture::BOOST_MAP);
diff --git a/indra/newview/skins/default/textures/icons/Inv_UnknownObject.png b/indra/newview/skins/default/textures/icons/Inv_UnknownObject.png
new file mode 100644
index 0000000000000000000000000000000000000000..10f2b31cb570e74ef1f445d9ddf2c43fadf05bed
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Inv_UnknownObject.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 176fbd49e9903f189fe9fc5d93c5d7067e0b18b6..beffe718635ec7a7062f5fe9fd9b18fea9daed66 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -330,6 +330,7 @@ with the same filename but different name
   <texture name="Inv_SettingsDay" file_name="icons/Inv_SettingsDay.png" preload="false" />
 
   <texture name="Inv_Invalid" file_name="icons/Inv_Invalid.png" preload="false" />
+  <texture name="Inv_Unknown" file_name="icons/Inv_UnknownObject.png" preload="false" />
   <texture name="Inv_VersionFolderClosed" file_name="icons/Inv_VersionFolderClosed.png" preload="false" />
   <texture name="Inv_VersionFolderOpen" file_name="icons/Inv_VersionFolderOpen.png" preload="false" />
   
diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml
index fbb96b3ca06ea350aadc2cef019004b2f938c52c..e5f7338181079f5ea9e280773dba857538814da3 100644
--- a/indra/newview/skins/default/xui/de/strings.xml
+++ b/indra/newview/skins/default/xui/de/strings.xml
@@ -70,7 +70,7 @@ UI-Skalierung: [UI_SCALE]
 Sichtweite: [DRAW_DISTANCE] m
 Bandbreite: [NET_BANDWITH] kbit/s
 LOD-Faktor: [LOD_FACTOR]
-Darstellungsqualität: [RENDER_QUALITY] / 7
+Darstellungsqualität: [RENDER_QUALITY]
 Erweitertes Beleuchtungsmodell: [GPU_SHADERS]
 Texturspeicher: [TEXTURE_MEMORY] MB
 Erstellungszeit VFS (Cache): [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml
index d714cc613ef444f4157a3f65b0fb3807cd3607b2..ae1fb4cccd24261f286b6f211880cb130027630a 100644
--- a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml
@@ -57,7 +57,8 @@
      top="27"
      visible="false"
      width="315"
-     word_wrap="true">
+     word_wrap="true"
+     parse_urls="false">
 Connecting to [CALLEE_NAME]
     </text>
     <text
@@ -68,7 +69,8 @@ Connecting to [CALLEE_NAME]
      name="calling"
      top="27"
      width="315"
-     word_wrap="true">
+     word_wrap="true"
+     parse_urls="false">
 Calling [CALLEE_NAME]
     </text>
     <text
@@ -90,7 +92,8 @@ No Answer.  Please try again later.
    name="nearby"
    top="27"
    width="315"
-   word_wrap="true">
+   word_wrap="true"
+   parse_urls="false">
     You have been disconnected from [VOICE_CHANNEL_NAME].  [RECONNECT_NEARBY]
   </text>
   <text
@@ -101,7 +104,8 @@ No Answer.  Please try again later.
    name="nearby_P2P_by_other"
    top="27"
    width="315"
-   word_wrap="true">
+   word_wrap="true"
+   parse_urls="false">
     Your call has ended.  [RECONNECT_NEARBY]
   </text>
   <text
@@ -112,7 +116,8 @@ No Answer.  Please try again later.
    name="nearby_P2P_by_agent"
    top="27"
    width="315"
-   word_wrap="true">
+   word_wrap="true"
+   parse_urls="false">
     You have ended the call.  [RECONNECT_NEARBY]
   </text>
   <text
@@ -123,7 +128,8 @@ No Answer.  Please try again later.
      name="leaving"
      top="62"
      width="315"
-     word_wrap="true">
+     word_wrap="true"
+     parse_urls="false">
 Leaving [CURRENT_CHAT].
     </text>
   <button
diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml
index a9f6b8045dd4552b6ccb65cbd1ccc3227dea0e1b..0f7c6a2aa53db54a4e6f0126ea222bf74774a26a 100644
--- a/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml
@@ -33,6 +33,16 @@
          function="People.Nearby.ViewSort.CheckItem"
          parameter="sort_distance"/>
     </menu_item_check>
+    <menu_item_check
+       label="Sort by Recent arrival"
+       name="sort_arrival">
+      <menu_item_check.on_click
+         function="People.Nearby.ViewSort.Action"
+         parameter="sort_arrival"/>
+      <menu_item_check.on_check
+         function="People.Nearby.ViewSort.CheckItem"
+         parameter="sort_arrival"/>
+  </menu_item_check>
     <menu_item_separator layout="topleft" />
     <menu_item_check name="view_icons" label="View People Icons">
         <menu_item_check.on_click
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d0dafdbc8d2e0384239daefcf4806fd7d8dc51b7..69503cdbf2d9b88ec916feba3a19418fcf07ae0b 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -8289,6 +8289,13 @@ Failed to save snapshot to [PATH]: Directory does not exist.
     type="notifytip">
 Error saving preset [NAME].
   </notification>
+    
+  <notification
+    icon="notifytip.tga"
+    name="DefaultPresetNotSaved"
+    type="notifytip">
+Can not overwrite default preset.
+  </notification>
 
   <notification
     icon="notifytip.tga"
diff --git a/indra/newview/skins/default/xui/en/panel_group_notify.xml b/indra/newview/skins/default/xui/en/panel_group_notify.xml
index 4121acdfb01cee98572f4ffd2ace08749065416f..60e5a03d5183ca711b53db37c0af727d5e5a6fb2 100644
--- a/indra/newview/skins/default/xui/en/panel_group_notify.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_notify.xml
@@ -43,6 +43,7 @@
          layout="topleft"
          left_pad="10"
          name="title"
+         parse_urls="false"
          text_color="GroupNotifyTextColor"
          top="5"
          use_ellipses="true"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 76d040150d578927d9b9c069267047cfef7fc224..8681c867bdca06eb66859e49f6f8ecd0616439b9 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -53,7 +53,7 @@ UI Scaling: [UI_SCALE]
 Draw distance: [DRAW_DISTANCE]m
 Bandwidth: [NET_BANDWITH]kbit/s
 LOD factor: [LOD_FACTOR]
-Render quality: [RENDER_QUALITY] / 7
+Render quality: [RENDER_QUALITY]
 Advanced Lighting Model: [GPU_SHADERS]
 Texture memory: [TEXTURE_MEMORY]MB
 VFS (cache) creation time: [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml
index 87c123125ca513d500f5810e07e846545119aace..41766d56975e4f61dd3772e8728cea850558171b 100644
--- a/indra/newview/skins/default/xui/es/strings.xml
+++ b/indra/newview/skins/default/xui/es/strings.xml
@@ -62,7 +62,7 @@ Ajuste de escala de IU: [UI_SCALE]
 Distancia de dibujo: [DRAW_DISTANCE]m
 Ancho de banda: [NET_BANDWITH]kbit/s
 Factor de LOD: [LOD_FACTOR]
-Calidad de renderizado: [RENDER_QUALITY] / 7
+Calidad de renderizado: [RENDER_QUALITY]
 Modelo de iluminación avanzado: [GPU_SHADERS]
 Memoria de textura: [TEXTURE_MEMORY]MB
 Tiempo de creación de VFS (caché): [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml
index 8b7269b915e759bd5da42a6daaeeabbf6cf31990..e3a379d4f9b99538a4fbdd7aaa152c5a25de81f2 100644
--- a/indra/newview/skins/default/xui/fr/strings.xml
+++ b/indra/newview/skins/default/xui/fr/strings.xml
@@ -71,7 +71,7 @@ Ajustement de la taille de la police : [FONT_SIZE_ADJUSTMENT] pts
 Limite d’affichage : [DRAW_DISTANCE] m
 Bande passante : [NET_BANDWITH] kbit/s
 Facteur LOD (niveau de détail) : [LOD_FACTOR]
-Qualité de rendu : [RENDER_QUALITY] / 7
+Qualité de rendu : [RENDER_QUALITY]
 Modèle d’éclairage avancé : [GPU_SHADERS]
 Mémoire textures : [TEXTURE_MEMORY] Mo
 Durée de création VFS (cache) : [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml
index a51b8ebf75e00c0b89e366e209ed429cf09196e9..933f624525dfe360cd79b6d850a4254edfd14068 100644
--- a/indra/newview/skins/default/xui/it/strings.xml
+++ b/indra/newview/skins/default/xui/it/strings.xml
@@ -68,7 +68,7 @@ Scala UI: [UI_SCALE]
 Distanza visualizzazione: [DRAW_DISTANCE] m
 Larghezza banda: [NET_BANDWITH] kbit/s
 Fattore livello di dettaglio: [LOD_FACTOR]
-Qualità di rendering: [RENDER_QUALITY] / 7
+Qualità di rendering: [RENDER_QUALITY]
 Modello illuminazione avanzato: [GPU_SHADERS]
 Memoria texture: [TEXTURE_MEMORY] MB
 Data/ora creazione VFS (cache): [VFS_TIME]
@@ -1508,7 +1508,7 @@ Se continui a ricevere questo messaggio, contatta l&apos;assistenza Second Life
 		Trascina le cartelle in questa area per metterle in vendita su [[MARKETPLACE_DASHBOARD_URL] Marketplace].
 	</string>
 	<string name="InventoryItemsCount">
-		( [ITEM_COUNT] oggetti )
+		( [ITEMS_COUNT] oggetti )
 	</string>
 	<string name="Marketplace Validation Warning Stock">
 		la cartella di magazzino deve essere inclusa in una cartella di versione
diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml
index d901e0ba63cd1582dd9ac227d017c2fc0efa20ef..abb697c6362fa83fa9c0e5026fce9758aeda9f3d 100644
--- a/indra/newview/skins/default/xui/ja/strings.xml
+++ b/indra/newview/skins/default/xui/ja/strings.xml
@@ -71,7 +71,7 @@ UI スケーリング: [UI_SCALE]
 描画距離:[DRAW_DISTANCE]m
 帯域幅:[NET_BANDWITH]kbit/s
 LOD 係数: [LOD_FACTOR]
-表示品質: [RENDER_QUALITY] / 7
+表示品質: [RENDER_QUALITY]
 高度なライティングモデル: [GPU_SHADERS]
 テクスチャメモリ: [TEXTURE_MEMORY]MB
 VFS(キャッシュ)作成時間: [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index ee048e28e3c600c5ffb60faef94519bedbf40600..046e7db47c8249d66b9df78b020a097a5a5aeff0 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -62,7 +62,7 @@ Escala de interface: [UI_SCALE]
 Dist. máxima: [DRAW_DISTANCE]m
 Largura de banda: [NET_BANDWITH]kbit/s
 Fator LOD: [LOD_FACTOR]
-Qualidade de renderização: [RENDER_QUALITY] / 7
+Qualidade de renderização: [RENDER_QUALITY]
 Modelo de iluminação avançado: [GPU_SHADERS]
 Memória de textura: [TEXTURE_MEMORY]MB
 Tempo de criação de VFS (cache): [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/ru/floater_tos.xml b/indra/newview/skins/default/xui/ru/floater_tos.xml
index 3f2b5747d58eb1e2713b2de663a50382b5c0966e..7196a04de1a4da4f3a724b0606c50173bb550e70 100644
--- a/indra/newview/skins/default/xui/ru/floater_tos.xml
+++ b/indra/newview/skins/default/xui/ru/floater_tos.xml
@@ -16,6 +16,6 @@
 	<text name="agree_list">
 		Я прочитал и согласен с Условиями и положениями по конфиденциальности Пользовательского соглашения, включая требования по разрешению разногласий Second Life.
 	</text>
-	<button label="Продолжить" label_selected="Продолжить" name="Continue"/>
+	<button label="Продолжить" label_selected="Продолжить" name="Continue" top_delta="45"/>
 	<button label="Отмена" label_selected="Отмена" name="Cancel"/>
 </floater>
diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml
index ac6209b1f2714988301aeca8674505b57b5c873c..206d5c2081496be88a2bbe47cca25b1f24dfeb80 100644
--- a/indra/newview/skins/default/xui/ru/strings.xml
+++ b/indra/newview/skins/default/xui/ru/strings.xml
@@ -71,7 +71,7 @@ SLURL: &lt;nolink&gt;[SLURL]&lt;/nolink&gt;
 Дальность отрисовки: [DRAW_DISTANCE] м
 Ширина канала: [NET_BANDWITH] кбит/с
 Коэффициент детализации: [LOD_FACTOR]
-Качество визуализации: [RENDER_QUALITY] / 7
+Качество визуализации: [RENDER_QUALITY]
 Расширенная модель освещения: [GPU_SHADERS]
 Память текстур: [TEXTURE_MEMORY] МБ
 Время создания VFS (кэш): [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml
index 3bbff7bfde16f9cdc396de56afdd53b58ba7fc79..8d901cf0f1a7588964e197f253cbf49bf1e432fd 100644
--- a/indra/newview/skins/default/xui/tr/strings.xml
+++ b/indra/newview/skins/default/xui/tr/strings.xml
@@ -71,7 +71,7 @@ Kullanıcı Arayüzü Ölçekleme: [UI_SCALE]
 Çizme mesafesi: [DRAW_DISTANCE] m
 Bant geniÅŸliÄŸi: [NET_BANDWITH] kbit/sn
 Ayrıntı seviyesi faktörü: [LOD_FACTOR]
-Ä°ÅŸleme kalitesi: [RENDER_QUALITY] / 7
+Ä°ÅŸleme kalitesi: [RENDER_QUALITY]
 Gelişmiş Aydınlatma Modeli: [GPU_SHADERS]
 Doku belleÄŸi: [TEXTURE_MEMORY]MB
 VFS (önbellek) oluşturma zamanı: [VFS_TIME]
diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml
index bc63c5af74c3948e8aac71fabceef84201673681..34096f0d60d568d179c107aaece1a182e1e76b9f 100644
--- a/indra/newview/skins/default/xui/zh/strings.xml
+++ b/indra/newview/skins/default/xui/zh/strings.xml
@@ -71,7 +71,7 @@
 描繪距離:[DRAW_DISTANCE]公尺
 頻寬:[NET_BANDWITH]千位元/秒
 細節層次率:[LOD_FACTOR]
-呈像品質:[RENDER_QUALITY] / 7
+呈像品質:[RENDER_QUALITY]
 進階照明模型:[GPU_SHADERS]
 材質記憶體:[TEXTURE_MEMORY]MB
 VFS(快取)建立時間:[VFS_TIME]
diff --git a/indra/test/io.cpp b/indra/test/io.cpp
index ff900ab96bea3840cf497417a7a4114007920597..40243a8ad6ef6505f9f2988db9b2c8dea9d3c6bc 100644
--- a/indra/test/io.cpp
+++ b/indra/test/io.cpp
@@ -914,7 +914,8 @@ namespace tut
 			mSocket = LLSocket::create(
 				mPool,
 				LLSocket::STREAM_TCP,
-				SERVER_LISTEN_PORT);
+				SERVER_LISTEN_PORT,
+				"127.0.0.1");
 		}
 
 		~pipe_and_pump_fitness()
diff --git a/scripts/content_tools/anim_tool.py b/scripts/content_tools/anim_tool.py
index 77bf731ae60e8be463565eba3bbcc5bcb463304d..3496617b21404b7a06dff73dbe546e5b42582abe 100644
--- a/scripts/content_tools/anim_tool.py
+++ b/scripts/content_tools/anim_tool.py
@@ -1,14 +1,22 @@
-#!runpy.sh
-
+#!/usr/bin/python
 """\
-
-This module contains tools for manipulating the .anim files supported
-for Second Life animation upload. Note that this format is unrelated
-to any non-Second Life formats of the same name.
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
+@file   anim_tool.py
+@author Brad Payne, Nat Goodspeed
+@date   2015-09-15
+@brief  This module contains tools for manipulating the .anim files supported
+        for Second Life animation upload. Note that this format is unrelated
+        to any non-Second Life formats of the same name.
+
+        This code is a Python translation of the logic in
+        LLKeyframeMotion::serialize() and deserialize():
+        https://bitbucket.org/lindenlab/viewer-release/src/827a910542a9af0a39b0ca03663c02e5c83869ea/indra/llcharacter/llkeyframemotion.cpp?at=default&fileviewer=file-view-default#llkeyframemotion.cpp-1864
+        https://bitbucket.org/lindenlab/viewer-release/src/827a910542a9af0a39b0ca03663c02e5c83869ea/indra/llcharacter/llkeyframemotion.cpp?at=default&fileviewer=file-view-default#llkeyframemotion.cpp-1220
+        save that there is no support for old-style .anim files, permitting
+        simpler code.
+
+$LicenseInfo:firstyear=2015&license=viewerlgpl$
 Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
+Copyright (C) 2015, 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
@@ -28,63 +36,85 @@
 $/LicenseInfo$
 """
 
-import sys
-import os
-import struct
-import StringIO
 import math
-import argparse
+import os
 import random
-from lxml import etree
+from cStringIO import StringIO
+import struct
+import sys
+from xml.etree import ElementTree
+
+class Error(Exception):
+    pass
+
+class BadFormat(Error):
+    """
+    Something went wrong trying to read the specified .anim file.
+    """
+    pass
+
+class ExtraneousData(BadFormat):
+    """
+    Specifically, the .anim file in question contains more data than needed.
+    This could happen if the file isn't a .anim at all, and it 'just happens'
+    to read properly otherwise -- e.g. a block of all zero bytes could look
+    like empty name strings, empty arrays etc. That could be a legitimate
+    error -- or it could be due to a sloppy tool. Break this exception out
+    separately so caller can distinguish if desired.
+    """
+    pass
 
 U16MAX = 65535
-OOU16MAX = 1.0/(float)(U16MAX)
+# One Over U16MAX, for scaling
+OOU16MAX = 1.0/float(U16MAX)
 
 LL_MAX_PELVIS_OFFSET = 5.0
 
 class FilePacker(object):
     def __init__(self):
-        self.data = StringIO.StringIO()
-        self.offset = 0
+        self.buffer = StringIO()
 
     def write(self,filename):
-        f = open(filename,"wb")
-        f.write(self.data.getvalue())
-        f.close()
+        with open(filename,"wb") as f:
+            f.write(self.buffer.getvalue())
 
     def pack(self,fmt,*args):
         buf = struct.pack(fmt, *args)
-        self.offset += struct.calcsize(fmt)
-        self.data.write(buf)
+        self.buffer.write(buf)
 
     def pack_string(self,str,size=0):
-        buf = str + "\000"
-        if size and (len(buf) < size):
-            buf += "\000" * (size-len(buf))
-        self.data.write(buf)
+        # If size == 0, caller doesn't care, just wants a terminating nul byte
+        size = size or (len(str) + 1)
+        # Nonzero size means a fixed-length field. If the passed string (plus
+        # its terminating nul) exceeds that fixed length, we'll have to
+        # truncate. But make sure we still leave room for the final nul byte!
+        str = str[:size-1]
+        # Now pad what's left of str out to 'size' with nul bytes.
+        buf = str + ("\000" * (size-len(str)))
+        self.buffer.write(buf)
         
 class FileUnpacker(object):
     def __init__(self, filename):
-        f = open(filename,"rb")
-        self.data = f.read()
+        with open(filename,"rb") as f:
+            self.buffer = f.read()
         self.offset = 0
 
     def unpack(self,fmt):
-        result = struct.unpack_from(fmt, self.data, self.offset)
+        result = struct.unpack_from(fmt, self.buffer, self.offset)
         self.offset += struct.calcsize(fmt)
         return result
     
     def unpack_string(self, size=0):
-        result = ""
-        i = 0
-        while (self.data[self.offset+i] != "\000"):
-            result += self.data[self.offset+i]
-            i += 1
-        i += 1
+        # Nonzero size means we must consider exactly the next 'size'
+        # characters in self.buffer.
         if size:
-            # fixed-size field for the string
-            i = size
-        self.offset += i
+            self.offset += size
+            # but stop at the first nul byte
+            return self.buffer[self.offset-size:self.offset].split("\000", 1)[0]
+        # Zero size means consider everything until the next nul character.
+        result = self.buffer[self.offset:].split("\000", 1)[0]
+        # don't forget to skip the nul byte too
+        self.offset += len(result) + 1
         return result
 
 # translated from the C++ version in lldefs.h
@@ -108,7 +138,7 @@ def F32_to_U16(val, lower, upper):
 # translated from the C++ version in llquantize.h
 def U16_to_F32(ival, lower, upper):
     if ival < 0 or ival > U16MAX:
-        raise Exception("U16 out of range: "+ival)
+        raise ValueError("U16 out of range: %s" % ival)
     val = ival*OOU16MAX
     delta = (upper - lower)
     val *= delta
@@ -121,71 +151,100 @@ def U16_to_F32(ival, lower, upper):
         val = 0.0
     return val; 
 
-class BadFormat(Exception):
-    pass
-
 class RotKey(object):
-    def __init__(self):
-        pass
-
-    def unpack(self, anim, fup):
-        (self.time_short, ) = fup.unpack("<H")
-        self.time = U16_to_F32(self.time_short, 0.0, anim.duration)
+    def __init__(self, time, duration, rot):
+        """
+        This constructor instantiates a RotKey object from scratch, as it
+        were, converting from float time to time_short.
+        """
+        self.time = time
+        self.time_short = F32_to_U16(time, 0.0, duration) \
+                          if time is not None else None
+        self.rotation = rot
+
+    @staticmethod
+    def unpack(duration, fup):
+        """
+        This staticmethod constructs a RotKey by loadingfrom a FileUnpacker.
+        """
+        # cheat the other constructor
+        this = RotKey(None, None, None)
+        # load time_short directly from the file
+        (this.time_short, ) = fup.unpack("<H")
+        # then convert to float time
+        this.time = U16_to_F32(this.time_short, 0.0, duration)
+        # convert each coordinate of the rotation from short to float
         (x,y,z) = fup.unpack("<HHH")
-        self.rotation = [U16_to_F32(i, -1.0, 1.0) for i in (x,y,z)]
+        this.rotation = [U16_to_F32(i, -1.0, 1.0) for i in (x,y,z)]
+        return this
 
     def dump(self, f):
-        print >>f, "    rot_key: t",self.time,"st",self.time_short,"rot",",".join([str(f) for f in self.rotation])
+        print >>f, "    rot_key: t %.3f" % self.time,"st",self.time_short,"rot",",".join("%.3f" % f for f in self.rotation)
 
-    def pack(self, anim, fp):
-        if not hasattr(self,"time_short"):
-            self.time_short = F32_to_U16(self.time, 0.0, anim.duration)
+    def pack(self, fp):
         fp.pack("<H",self.time_short)
         (x,y,z) = [F32_to_U16(v, -1.0, 1.0) for v in self.rotation]
         fp.pack("<HHH",x,y,z)
         
 class PosKey(object):
-    def __init__(self):
-        pass
-
-    def unpack(self, anim, fup):
-        (self.time_short, ) = fup.unpack("<H")
-        self.time = U16_to_F32(self.time_short, 0.0, anim.duration)
+    def __init__(self, time, duration, pos):
+        """
+        This constructor instantiates a PosKey object from scratch, as it
+        were, converting from float time to time_short.
+        """
+        self.time = time
+        self.time_short = F32_to_U16(time, 0.0, duration) \
+                          if time is not None else None
+        self.position = pos
+
+    @staticmethod
+    def unpack(duration, fup):
+        """
+        This staticmethod constructs a PosKey by loadingfrom a FileUnpacker.
+        """
+        # cheat the other constructor
+        this = PosKey(None, None, None)
+        # load time_short directly from the file
+        (this.time_short, ) = fup.unpack("<H")
+        # then convert to float time
+        this.time = U16_to_F32(this.time_short, 0.0, duration)
+        # convert each coordinate of the rotation from short to float
         (x,y,z) = fup.unpack("<HHH")
-        self.position = [U16_to_F32(i, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET) for i in (x,y,z)]
+        this.position = [U16_to_F32(i, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET)
+                         for i in (x,y,z)]
+        return this
 
     def dump(self, f):
-        print >>f, "    pos_key: t",self.time,"pos ",",".join([str(f) for f in self.position])
+        print >>f, "    pos_key: t %.3f" % self.time,"pos ",",".join("%.3f" % f for f in self.position)
         
-    def pack(self, anim, fp):
-        if not hasattr(self,"time_short"):
-            self.time_short = F32_to_U16(self.time, 0.0, anim.duration)
+    def pack(self, fp):
         fp.pack("<H",self.time_short)
         (x,y,z) = [F32_to_U16(v, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET) for v in self.position]
         fp.pack("<HHH",x,y,z)
 
 class Constraint(object):
-    def __init__(self):
-        pass
-
-    def unpack(self, anim, fup):
-        (self.chain_length, self.constraint_type) = fup.unpack("<BB")
-        self.source_volume = fup.unpack_string(16)
-        self.source_offset = fup.unpack("<fff")
-        self.target_volume = fup.unpack_string(16)
-        self.target_offset = fup.unpack("<fff")
-        self.target_dir = fup.unpack("<fff")
-        fmt = "<ffff"
-        (self.ease_in_start, self.ease_in_stop, self.ease_out_start, self.ease_out_stop) = fup.unpack("<ffff")
-
-    def pack(self, anim, fp):
+    @staticmethod
+    def unpack(duration, fup):
+        this = Constraint()
+        (this.chain_length, this.constraint_type) = fup.unpack("<BB")
+        this.source_volume = fup.unpack_string(16)
+        this.source_offset = fup.unpack("<fff")
+        this.target_volume = fup.unpack_string(16)
+        this.target_offset = fup.unpack("<fff")
+        this.target_dir = fup.unpack("<fff")
+        (this.ease_in_start, this.ease_in_stop, this.ease_out_start, this.ease_out_stop) = \
+                             fup.unpack("<ffff")
+        return this
+
+    def pack(self, fp):
         fp.pack("<BB", self.chain_length, self.constraint_type)
         fp.pack_string(self.source_volume, 16)
         fp.pack("<fff", *self.source_offset)
         fp.pack_string(self.target_volume, 16)
         fp.pack("<fff", *self.target_offset)
         fp.pack("<fff", *self.target_dir)
-        fp.pack("<ffff", self.ease_in_start, self.ease_in_stop, self.ease_out_start, self.ease_out_stop)
+        fp.pack("<ffff", self.ease_in_start, self.ease_in_stop,
+                self.ease_out_start, self.ease_out_stop)
 
     def dump(self, f):
         print >>f, "  constraint:"
@@ -202,30 +261,26 @@ def dump(self, f):
         print >>f, "    ease_out_stop",self.ease_out_stop
         
 class Constraints(object):
-    def __init__(self):
-        pass
-
-    def unpack(self, anim, fup):
-        (self.num_constraints, ) = fup.unpack("<i")
-        self.constraints = []
-        for i in xrange(self.num_constraints):
-            constraint = Constraint()
-            constraint.unpack(anim, fup)
-            self.constraints.append(constraint)
-
-    def pack(self, anim, fp):
-        fp.pack("<i",self.num_constraints)
+    @staticmethod
+    def unpack(duration, fup):
+        this = Constraints()
+        (num_constraints, ) = fup.unpack("<i")
+        this.constraints = [Constraint.unpack(duration, fup)
+                            for i in xrange(num_constraints)]
+        return this
+
+    def pack(self, fp):
+        fp.pack("<i",len(self.constraints))
         for c in self.constraints:
-            c.pack(anim,fp)
+            c.pack(fp)
 
     def dump(self, f):
-        print >>f, "constraints:",self.num_constraints
+        print >>f, "constraints:",len(self.constraints)
         for c in self.constraints:
             c.dump(f)
 
 class PositionCurve(object):
     def __init__(self):
-        self.num_pos_keys = 0
         self.keys = []
 
     def is_static(self):
@@ -236,28 +291,27 @@ def is_static(self):
                     return False
         return True
 
-    def unpack(self, anim, fup):
-        (self.num_pos_keys, ) = fup.unpack("<i")
-        self.keys = []
-        for k in xrange(0,self.num_pos_keys):
-            pos_key = PosKey()
-            pos_key.unpack(anim, fup)
-            self.keys.append(pos_key)
+    @staticmethod
+    def unpack(duration, fup):
+        this = PositionCurve()
+        (num_pos_keys, ) = fup.unpack("<i")
+        this.keys = [PosKey.unpack(duration, fup)
+                     for k in xrange(num_pos_keys)]
+        return this
 
-    def pack(self, anim, fp):
-        fp.pack("<i",self.num_pos_keys)
+    def pack(self, fp):
+        fp.pack("<i",len(self.keys))
         for k in self.keys:
-            k.pack(anim, fp)
+            k.pack(fp)
 
     def dump(self, f):
         print >>f, "  position_curve:"
-        print >>f, "    num_pos_keys", self.num_pos_keys
-        for k in xrange(0,self.num_pos_keys):
-            self.keys[k].dump(f)
+        print >>f, "    num_pos_keys", len(self.keys)
+        for k in self.keys:
+            k.dump(f)
 
 class RotationCurve(object):
     def __init__(self):
-        self.num_rot_keys = 0
         self.keys = []
 
     def is_static(self):
@@ -268,42 +322,46 @@ def is_static(self):
                     return False
         return True
 
-    def unpack(self, anim, fup):
-        (self.num_rot_keys, ) = fup.unpack("<i")
-        self.keys = []
-        for k in xrange(0,self.num_rot_keys):
-            rot_key = RotKey()
-            rot_key.unpack(anim, fup)
-            self.keys.append(rot_key)
+    @staticmethod
+    def unpack(duration, fup):
+        this = RotationCurve()
+        (num_rot_keys, ) = fup.unpack("<i")
+        this.keys = [RotKey.unpack(duration, fup)
+                     for k in xrange(num_rot_keys)]
+        return this
 
-    def pack(self, anim, fp):
-        fp.pack("<i",self.num_rot_keys)
+    def pack(self, fp):
+        fp.pack("<i",len(self.keys))
         for k in self.keys:
-            k.pack(anim, fp)
+            k.pack(fp)
 
     def dump(self, f):
         print >>f, "  rotation_curve:"
-        print >>f, "    num_rot_keys", self.num_rot_keys
-        for k in xrange(0,self.num_rot_keys):
-            self.keys[k].dump(f)
+        print >>f, "    num_rot_keys", len(self.keys)
+        for k in self.keys:
+            k.dump(f)
             
 class JointInfo(object):
-    def __init__(self):
-        pass
-
-    def unpack(self, anim, fup):
-        self.joint_name = fup.unpack_string()
-        (self.joint_priority, ) = fup.unpack("<i")
+    def __init__(self, name, priority):
+        self.joint_name = name
+        self.joint_priority = priority
         self.rotation_curve = RotationCurve()
-        self.rotation_curve.unpack(anim, fup)
         self.position_curve = PositionCurve()
-        self.position_curve.unpack(anim, fup)
 
-    def pack(self, anim, fp):
+    @staticmethod
+    def unpack(duration, fup):
+        this = JointInfo(None, None)
+        this.joint_name = fup.unpack_string()
+        (this.joint_priority, ) = fup.unpack("<i")
+        this.rotation_curve = RotationCurve.unpack(duration, fup)
+        this.position_curve = PositionCurve.unpack(duration, fup)
+        return this
+
+    def pack(self, fp):
         fp.pack_string(self.joint_name)
         fp.pack("<i", self.joint_priority)
-        self.rotation_curve.pack(anim, fp)
-        self.position_curve.pack(anim, fp)
+        self.rotation_curve.pack(fp)
+        self.position_curve.pack(fp)
 
     def dump(self, f):
         print >>f, "joint:"
@@ -313,13 +371,26 @@ def dump(self, f):
         self.position_curve.dump(f)
 
 class Anim(object):
-    def __init__(self, filename=None):
+    def __init__(self, filename=None, verbose=False):
+        # set this FIRST as it's consulted by read() and unpack()
+        self.verbose = verbose
         if filename:
             self.read(filename)
 
     def read(self, filename):
         fup = FileUnpacker(filename)
-        self.unpack(fup)
+        try:
+            self.unpack(fup)
+        except struct.error as err:
+            raise BadFormat("error reading %s: %s" % (filename, err))
+        # By the end of streaming data in from our FileUnpacker, we should
+        # have consumed the entire thing. If there's excess data, it's
+        # entirely possible that this is a garbage file that happens to
+        # resemble a valid degenerate .anim file, e.g. with zero counts of
+        # things.
+        if fup.offset != len(fup.buffer):
+            raise ExtraneousData("extraneous data in %s; is it really a Linden .anim file?" %
+                                 filename)
 
     # various validity checks could be added - see LLKeyframeMotion::deserialize()
     def unpack(self,fup):
@@ -333,27 +404,57 @@ def unpack(self,fup):
         else:
             raise BadFormat("Bad combination of version, sub_version: %d %d" % (self.version, self.sub_version))
 
+        # Also consult BVH conversion code for stricter checks
+
+        # C++ deserialize() checks self.base_priority against
+        # LLJoint::ADDITIVE_PRIORITY and LLJoint::USE_MOTION_PRIORITY,
+        # possibly sets self.max_priority
+        # checks self.duration against MAX_ANIM_DURATION !!
+        # checks self.emote_name != str(self.ID)
+        # checks self.hand_pose against LLHandMotion::NUM_HAND_POSES !!
+        # checks 0 < num_joints <= LL_CHARACTER_MAX_JOINTS (no need --
+        # validate names)
+        # checks each joint_name neither "mScreen" nor "mRoot" ("attempted to
+        # animate special joint") !!
+        # checks each joint_name can be found in mCharacter
+        # checks each joint_priority >= LLJoint::USE_MOTION_PRIORITY
+        # tracks max observed joint_priority, excluding USE_MOTION_PRIORITY
+        # checks each 0 <= RotKey.time <= self.duration !!
+        # checks each RotKey.rotation.isFinite() !!
+        # checks each PosKey.position.isFinite() !!
+        # checks 0 <= num_constraints <= MAX_CONSTRAINTS  !!
+        # checks each Constraint.chain_length <= num_joints
+        # checks each Constraint.constraint_type < NUM_CONSTRAINT_TYPES !!
+        # checks each Constraint.source_offset.isFinite() !!
+        # checks each Constraint.target_offset.isFinite() !!
+        # checks each Constraint.target_dir.isFinite() !!
+        # from https://bitbucket.org/lindenlab/viewer-release/src/827a910542a9af0a39b0ca03663c02e5c83869ea/indra/llcharacter/llkeyframemotion.cpp?at=default&fileviewer=file-view-default#llkeyframemotion.cpp-1812 :
+        # find joint to which each Constraint's collision volume is attached;
+        # for each link in Constraint.chain_length, walk to joint's parent,
+        # find that parent in list of joints, set its index in index list
+
         self.emote_name = fup.unpack_string()
         
-        (self.loop_in_point, self.loop_out_point, self.loop, self.ease_in_duration, self.ease_out_duration, self.hand_pose, self.num_joints) = fup.unpack("@ffiffII")
+        (self.loop_in_point, self.loop_out_point, self.loop,
+         self.ease_in_duration, self.ease_out_duration, self.hand_pose, num_joints) = \
+            fup.unpack("@ffiffII")
         
-        self.joints = []
-        for j in xrange(0,self.num_joints):
-            joint_info = JointInfo()
-            joint_info.unpack(self, fup)
-            self.joints.append(joint_info)
-            print "unpacked joint",joint_info.joint_name
-        self.constraints = Constraints()
-        self.constraints.unpack(self, fup)
-        self.data = fup.data
+        self.joints = [JointInfo.unpack(self.duration, fup)
+                       for j in xrange(num_joints)]
+        if self.verbose:
+            for joint_info in self.joints:
+                print "unpacked joint",joint_info.joint_name
+        self.constraints = Constraints.unpack(self.duration, fup)
+        self.buffer = fup.buffer
         
     def pack(self, fp):
         fp.pack("@HHhf", self.version, self.sub_version, self.base_priority, self.duration)
         fp.pack_string(self.emote_name, 0)
-        fp.pack("@ffiffII", self.loop_in_point, self.loop_out_point, self.loop, self.ease_in_duration, self.ease_out_duration, self.hand_pose, self.num_joints)
+        fp.pack("@ffiffII", self.loop_in_point, self.loop_out_point, self.loop,
+                self.ease_in_duration, self.ease_out_duration, self.hand_pose, len(self.joints))
         for j in self.joints:
-            j.pack(anim, fp)
-        self.constraints.pack(anim, fp)
+            j.pack(fp)
+        self.constraints.pack(fp)
 
     def dump(self, filename="-"):
         if filename=="-":
@@ -370,7 +471,7 @@ def dump(self, filename="-"):
         print >>f, "ease_in_duration: ", self.ease_in_duration
         print >>f, "ease_out_duration: ", self.ease_out_duration
         print >>f, "hand_pose", self.hand_pose
-        print >>f, "num_joints", self.num_joints
+        print >>f, "num_joints", len(self.joints)
         for j in self.joints:
             j.dump(f)
         self.constraints.dump(f)
@@ -382,10 +483,9 @@ def write(self, filename):
 
     def write_src_data(self, filename):
         print "write file",filename
-        f = open(filename,"wb")
-        f.write(self.data)
-        f.close()
-        
+        with open(filename,"wb") as f:
+            f.write(self.buffer)
+
     def find_joint(self, name):
         joints = [j for j in self.joints if j.joint_name == name]
         if joints:
@@ -395,91 +495,71 @@ def find_joint(self, name):
 
     def add_joint(self, name, priority):
         if not self.find_joint(name):
-            j = JointInfo()
-            j.joint_name = name
-            j.joint_priority = priority
-            j.rotation_curve = RotationCurve()
-            j.position_curve = PositionCurve()
-            self.joints.append(j)
-            self.num_joints = len(self.joints)
+            self.joints.append(JointInfo(name, priority))
 
     def delete_joint(self, name):
         j = self.find_joint(name)
         if j:
-            if args.verbose:
+            if self.verbose:
                 print "removing joint", name
-            anim.joints.remove(j)
-            anim.num_joints = len(self.joints)
+            self.joints.remove(j)
         else:
-            if args.verbose:
+            if self.verbose:
                 print "joint not found to remove", name
 
     def summary(self):
         nj = len(self.joints)
         nz = len([j for j in self.joints if j.joint_priority > 0])
-        nstatic = len([j for j in self.joints if j.rotation_curve.is_static() and j.position_curve.is_static()])
+        nstatic = len([j for j in self.joints
+                       if j.rotation_curve.is_static()
+                       and j.position_curve.is_static()])
         print "summary: %d joints, non-zero priority %d, static %d" % (nj, nz, nstatic)
 
     def add_pos(self, joint_names, positions):
         js = [joint for joint in self.joints if joint.joint_name in joint_names]
         for j in js:
-            if args.verbose:
+            if self.verbose:
                 print "adding positions",j.joint_name,positions
             j.joint_priority = 4
-            j.position_curve.num_pos_keys = len(positions)
-            j.position_curve.keys = []
-            for i,pos in enumerate(positions):
-                key = PosKey()
-                key.time = self.duration * i / (len(positions) - 1)
-                key.time_short = F32_to_U16(key.time, 0.0, self.duration)
-                key.position = pos
-                j.position_curve.keys.append(key)
+            j.position_curve.keys = [PosKey(self.duration * i / (len(positions) - 1),
+                                            self.duration,
+                                            pos)
+                                     for i,pos in enumerate(positions)]
 
     def add_rot(self, joint_names, rotations):
         js = [joint for joint in self.joints if joint.joint_name in joint_names]
         for j in js:
             print "adding rotations",j.joint_name
             j.joint_priority = 4
-            j.rotation_curve.num_rot_keys = len(rotations)
-            j.rotation_curve.keys = []
-            for i,pos in enumerate(rotations):
-                key = RotKey()
-                key.time = self.duration * i / (len(rotations) - 1)
-                key.time_short = F32_to_U16(key.time, 0.0, self.duration)
-                key.rotation = pos
-                j.rotation_curve.keys.append(key)
+            j.rotation_curve.keys = [RotKey(self.duration * i / (len(rotations) - 1),
+                                            self.duration,
+                                            rot)
+                                     for i,rot in enumerate(rotations)]
 
 def twistify(anim, joint_names, rot1, rot2):
     js = [joint for joint in anim.joints if joint.joint_name in joint_names]
     for j in js:
         print "twisting",j.joint_name
-        print j.rotation_curve.num_rot_keys
+        print len(j.rotation_curve.keys)
         j.joint_priority = 4
-        j.rotation_curve.num_rot_keys = 2
-        j.rotation_curve.keys = []
-        key1 = RotKey()
-        key1.time_short = 0
-        key1.time = U16_to_F32(key1.time_short, 0.0, anim.duration)
-        key1.rotation = rot1
-        key2 = RotKey()
-        key2.time_short = U16MAX
-        key2.time = U16_to_F32(key2.time_short, 0.0, anim.duration)
-        key2.rotation = rot2
-        j.rotation_curve.keys.append(key1)
-        j.rotation_curve.keys.append(key2)
+        # Set the joint(s) to rot1 at time 0, rot2 at the full duration.
+        j.rotation_curve.keys = [
+            RotKey(0.0, anim.duration, rot1),
+            RotKey(anim.duration, anim.duration, rot2)]
 
 def float_triple(arg):
     vals = arg.split()
     if len(vals)==3:
         return [float(x) for x in vals]
     else:
-        raise Exception("arg %s does not resolve to a float triple" % arg)
+        raise ValueError("arg %s does not resolve to a float triple" % arg)
 
 def get_joint_by_name(tree,name):
     if tree is None:
         return None
-    matches = [elt for elt in tree.getroot().iter() if \
-                   elt.get("name")==name and elt.tag in ["bone", "collision_volume", "attachment_point"]]
+    matches = [elt for elt in tree.getroot().iter()
+               if elt.get("name")==name
+               and elt.tag in ["bone", "collision_volume", "attachment_point"]]
     if len(matches)==1:
         return matches[0]
     elif len(matches)>1:
@@ -496,121 +576,135 @@ def get_elt_pos(elt):
     else:
         return (0.0, 0.0, 0.0)
 
-def resolve_joints(names, skel_tree, lad_tree):
-    print "resolve joints, no_hud is",args.no_hud
+def resolve_joints(names, skel_tree, lad_tree, no_hud=False):
+    print "resolve joints, no_hud is",no_hud
     if skel_tree and lad_tree:
         all_elts = [elt for elt in skel_tree.getroot().iter()]
         all_elts.extend([elt for elt in lad_tree.getroot().iter()])
-        matches = []
+        matches = set()
         for elt in all_elts:
             if elt.get("name") is None:
                 continue
             #print elt.get("name"),"hud",elt.get("hud")
-            if args.no_hud and elt.get("hud"):
+            if no_hud and elt.get("hud"):
                 #print "skipping hud joint", elt.get("name")
                 continue
             if elt.get("name") in names or elt.tag in names:
-                matches.append(elt.get("name"))
-        return list(set(matches))
+                matches.add(elt.get("name"))
+        return list(matches)
     else:
         return names
 
-if __name__ == "__main__":
+def main(*argv):
+    import argparse
 
     # default search location for config files is defined relative to
     # the script location; assuming they live in the same viewer repo
+    # Use sys.argv[0] because (a) this script lives where it lives regardless
+    # of what our caller passes and (b) we don't expect our caller to pass the
+    # script name anyway.
     pathname = os.path.dirname(sys.argv[0])        
-    path_to_skel = os.path.join(os.path.abspath(pathname),"..","..","indra","newview","character")
+    # we're in scripts/content_tools; hop back to base of repository clone
+    path_to_skel = os.path.join(os.path.abspath(pathname),os.pardir,os.pardir,
+                                "indra","newview","character")
 
     parser = argparse.ArgumentParser(description="process SL animations")
     parser.add_argument("--verbose", help="verbose flag", action="store_true")
-    parser.add_argument("--dump", help="dump to specified file")
+    parser.add_argument("--dump", metavar="FILEPATH", help="dump to specified file")
     parser.add_argument("--rot", help="specify sequence of rotations", type=float_triple, nargs="+")
-    parser.add_argument("--rand_pos", help="request random positions", action="store_true")
+    parser.add_argument("--rand_pos", help="request NUM random positions (default %(default)s)",
+                        metavar="NUM", type=int, default=2)
     parser.add_argument("--reset_pos", help="request original positions", action="store_true")
     parser.add_argument("--pos", help="specify sequence of positions", type=float_triple, nargs="+")
-    parser.add_argument("--num_pos", help="number of positions to create", type=int, default=2)
-    parser.add_argument("--delete_joints", help="specify joints to be deleted", nargs="+")
-    parser.add_argument("--joints", help="specify joints to be added or modified", nargs="+")
+    parser.add_argument("--delete_joints", help="specify joints to be deleted", nargs="+",
+                        metavar="JOINT")
+    parser.add_argument("--joints", help="specify joints to be added or modified", nargs="+",
+                        metavar="JOINT")
     parser.add_argument("--summary", help="print summary of the output animation", action="store_true")
-    parser.add_argument("--skel", help="name of the avatar_skeleton file", default= os.path.join(path_to_skel,"avatar_skeleton.xml"))
-    parser.add_argument("--lad", help="name of the avatar_lad file", default= os.path.join(path_to_skel,"avatar_lad.xml"))
-    parser.add_argument("--set_version", nargs=2, type=int, help="set version and sub-version to specified values")
+    parser.add_argument("--skel", help="name of the avatar_skeleton file (default %(default)s)",
+                        default=os.path.join(path_to_skel,"avatar_skeleton.xml"),
+                        metavar="FILEPATH")
+    parser.add_argument("--lad", help="name of the avatar_lad file (default %(default)s)",
+                        default=os.path.join(path_to_skel,"avatar_lad.xml"),
+                        metavar="FILEPATH")
+    parser.add_argument("--set_version", nargs=2, type=int,
+                        help="set version and sub-version to specified values",
+                        metavar=("VERSION", "SUB-VERSION"))
     parser.add_argument("--no_hud", help="omit hud joints from list of attachments", action="store_true")
     parser.add_argument("--base_priority", help="set base priority", type=int)
     parser.add_argument("--joint_priority", help="set joint priority for all joints", type=int)
     parser.add_argument("infilename", help="name of a .anim file to input")
     parser.add_argument("outfilename", nargs="?", help="name of a .anim file to output")
-    args = parser.parse_args()
+    args = parser.parse_args(argv)
 
-    print "anim_tool.py: " + " ".join(sys.argv)
+    print "anim_tool.py: " + " ".join(argv)
     print "dump is", args.dump
     print "infilename",args.infilename,"outfilename",args.outfilename
     print "rot",args.rot
     print "pos",args.pos
     print "joints",args.joints
 
-    try:
-        anim = Anim(args.infilename)
-        skel_tree = None
-        lad_tree = None
-        joints = []
-        if args.skel:
-            skel_tree = etree.parse(args.skel)
-            if skel_tree is None:
-                print "failed to parse",args.skel
-                exit(1)
-        if args.lad:
-            lad_tree = etree.parse(args.lad)
-            if lad_tree is None:
-                print "failed to parse",args.lad
-                exit(1)
-        if args.joints:
-            joints = resolve_joints(args.joints, skel_tree, lad_tree)
-            if args.verbose:
-                print "joints resolved to",joints
-            for name in joints:
-                anim.add_joint(name,0)
-        if args.delete_joints:
-            for name in args.delete_joints:
-                anim.delete_joint(name)
-        if joints and args.rot:
-            anim.add_rot(joints, args.rot)
-        if joints and args.pos:
-            anim.add_pos(joints, args.pos)
-        if joints and args.rand_pos:
-            for joint in joints:
-                pos_array = list(tuple(random.uniform(-1,1) for i in xrange(3)) for j in xrange(args.num_pos))
-                pos_array.append(pos_array[0])
-                anim.add_pos([joint], pos_array)
-        if joints and args.reset_pos:
-            for joint in joints:
-                elt = get_joint_by_name(skel_tree,joint)
-                if elt is None:
-                    elt = get_joint_by_name(lad_tree,joint)
-                if elt is not None:
-                    pos_array = []
-                    pos_array.append(get_elt_pos(elt))
-                    pos_array.append(pos_array[0])
-                    anim.add_pos([joint], pos_array)
-                else:
-                    print "no elt or no pos data for",joint
-        if args.set_version:
-            anim.version = args.set_version[0]
-            anim.sub_version = args.set_version[1]
-        if args.base_priority is not None:
-            print "set base priority",args.base_priority
-            anim.base_priority = args.base_priority
-        if args.joint_priority is not None:
-            print "set joint priority",args.joint_priority
-            for joint in anim.joints:
-                joint.joint_priority = args.joint_priority
-        if args.dump:
-            anim.dump(args.dump)
-        if args.summary:
-            anim.summary()
-        if args.outfilename:
-            anim.write(args.outfilename)
-    except:
-        raise
+    anim = Anim(args.infilename, args.verbose)
+    skel_tree = None
+    lad_tree = None
+    joints = []
+    if args.skel:
+        skel_tree = ElementTree.parse(args.skel)
+        if skel_tree is None:
+            raise Error("failed to parse " + args.skel)
+    if args.lad:
+        lad_tree = ElementTree.parse(args.lad)
+        if lad_tree is None:
+            raise Error("failed to parse " + args.lad)
+    if args.joints:
+        joints = resolve_joints(args.joints, skel_tree, lad_tree, args.no_hud)
+        if args.verbose:
+            print "joints resolved to",joints
+        for name in joints:
+            anim.add_joint(name,0)
+    if args.delete_joints:
+        for name in args.delete_joints:
+            anim.delete_joint(name)
+    if joints and args.rot:
+        anim.add_rot(joints, args.rot)
+    if joints and args.pos:
+        anim.add_pos(joints, args.pos)
+    if joints and args.rand_pos:
+        # pick a random sequence of positions for each joint specified
+        for joint in joints:
+            # generate a list of rand_pos triples
+            pos_array = [tuple(random.uniform(-1,1) for i in xrange(3))
+                         for j in xrange(args.rand_pos)]
+            # close the loop by cycling back to the first entry
+            pos_array.append(pos_array[0])
+            anim.add_pos([joint], pos_array)
+    if joints and args.reset_pos:
+        for joint in joints:
+            elt = get_joint_by_name(skel_tree,joint) or get_joint_by_name(lad_tree,joint)
+            if elt is not None:
+                anim.add_pos([joint], 2*[get_elt_pos(elt)])
+            else:
+                print "no elt or no pos data for",joint
+    if args.set_version:
+        anim.version, anim.sub_version = args.set_version
+    if args.base_priority is not None:
+        print "set base priority",args.base_priority
+        anim.base_priority = args.base_priority
+    # --joint_priority sets priority for ALL joints, not just the explicitly-
+    # specified ones
+    if args.joint_priority is not None:
+        print "set joint priority",args.joint_priority
+        for joint in anim.joints:
+            joint.joint_priority = args.joint_priority
+    if args.dump:
+        anim.dump(args.dump)
+    if args.summary:
+        anim.summary()
+    if args.outfilename:
+        anim.write(args.outfilename)
 
+if __name__ == "__main__":
+    try:
+        sys.exit(main(*sys.argv[1:]))
+    except Error as err:
+        sys.exit("%s: %s" % (err.__class__.__name__, err))