diff --git a/.hgtags b/.hgtags
index 9f1e925c8d3ddd77791347f083cdbc9c027036ad..c1635c9adb8bc68ed234f73f107d77b3d191c8ad 100644
--- a/.hgtags
+++ b/.hgtags
@@ -153,4 +153,10 @@ e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-start
 6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release
 e1ed60913230dd64269a7f7fc52cbc6004f6d52c DRTVWR-71_2.8.0-beta1
 e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-beta1
+493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release
+493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release
+2c7e459e0c883f8e406b932e41e60097e9ee077e DRTVWR-73_2.8.1-beta1
+2c7e459e0c883f8e406b932e41e60097e9ee077e 2.8.1-beta1
 54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start
+493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release
+ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start
diff --git a/BuildParams b/BuildParams
index ad2f71e336c8ceea5504c4daa79d95a616bf6559..58852110ef05e6439946effc885d091b39bff09f 100644
--- a/BuildParams
+++ b/BuildParams
@@ -82,6 +82,26 @@ mesh-development.build_debug_release_separately = true
 mesh-development.build_CYGWIN_Debug = false
 mesh-development.build_viewer_update_version_manager = false
 
+# ========================================
+# mesh-development-release-1-candidate
+# ========================================
+mesh-development-release-1-candidate.viewer_channel = "Project Viewer - Mesh"
+mesh-development-release-1-candidate.login_channel = "Project Viewer - Mesh"
+mesh-development-release-1-candidate.viewer_grid = agni
+mesh-development-release-1-candidate.build_debug_release_separately = true
+mesh-development-release-1-candidate.build_CYGWIN_Debug = false
+mesh-development-release-1-candidate.build_viewer_update_version_manager = false
+
+# ========================================
+# mesh-development-rc
+# ========================================
+mesh-development-rc.viewer_channel = "Project Viewer - Mesh"
+mesh-development-rc.login_channel = "Project Viewer - Mesh"
+mesh-development-rc.viewer_grid = agni
+mesh-development-rc.build_debug_release_separately = true
+mesh-development-rc.build_CYGWIN_Debug = false
+mesh-development-rc.build_viewer_update_version_manager = false
+
 # ========================================
 # mesh-asset-deprecation
 # ========================================
diff --git a/autobuild.xml b/autobuild.xml
index d38103524856d1196cf519c3b660ba423f7d9d29..6872af0661e80bb0f297a25de5d54c612de01867 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -246,9 +246,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d05be8fc196e9ce7b6636b931cf13dff</string>
+              <string>be7321370b69b6d66938b82a9230a067</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-colladadom/rev/226716/arch/Linux/installer/colladadom-2.2-linux-20110415.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-colladadom/rev/233450/arch/Linux/installer/colladadom-2.2-linux-20110621.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -1110,9 +1110,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6e45ad68506cd1ba49fd35a3201f0478</string>
+              <string>0db10480362168f075c2af0ae302cb74</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/228821/arch/Darwin/installer/llconvexdecomposition-0.1-darwin-20110504.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/234943/arch/Darwin/installer/llconvexdecomposition-0.1-darwin-20110707.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -1122,9 +1122,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>00ff5144612c2e261a0811a4503ce3ba</string>
+              <string>f3c667dc159c0537a9122ce6e72e16db</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/228821/arch/Linux/installer/llconvexdecomposition-0.1-linux-20110504.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/234943/arch/Linux/installer/llconvexdecomposition-0.1-linux-20110707.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -1134,9 +1134,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a4635dcbbe0915ce023dd41d3b848d4c</string>
+              <string>46cac4d667446bbbc9b5023f2848a5ac</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/228821/arch/CYGWIN/installer/llconvexdecomposition-0.1-windows-20110504.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/234943/arch/CYGWIN/installer/llconvexdecomposition-0.1-windows-20110707.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -1148,7 +1148,7 @@
         <key>license</key>
         <string>lgpl</string>
         <key>license_file</key>
-        <string>LICENSES/lgpl.txt</string>
+        <string>LICENSES/LLConvexDecompositionStubLicense.txt</string>
         <key>name</key>
         <string>llconvexdecompositionstub</string>
         <key>platforms</key>
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index f98a5398c3ba8ec41f7d0b0ddcd57618b922c871..99c5412ae5ea8dbc20bfd98f79da252e8ab29dcb 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -29,7 +29,7 @@
 
 const S32 LL_VERSION_MAJOR = 2;
 const S32 LL_VERSION_MINOR = 8;
-const S32 LL_VERSION_PATCH = 3;
+const S32 LL_VERSION_PATCH = 4;
 const S32 LL_VERSION_BUILD = 0;
 
 const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index 93f3c910bd70f8fce1af0a7c9564605ad405bc17..331a1692ee8abff68e12d4d02173634011f1741d 100644
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -380,7 +380,7 @@ void LLCrashLogger::updateApplication(const std::string& message)
 
 bool LLCrashLogger::init()
 {
-	LLCurl::initClass();
+	LLCurl::initClass(false);
 
 	// We assume that all the logs we're looking for reside on the current drive
 	gDirUtilp->initAppDirs("SecondLife");
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 21cc9b22f2a9d9ab66ade1f562b727ef2f109f5b..2893e746e91079e93115c792380d4a5eae8a0141 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -32,6 +32,7 @@
 #if !LL_WINDOWS
 #include <stdint.h>
 #endif
+#include <cmath>
 
 #include "llerror.h"
 #include "llmemtype.h"
@@ -2379,11 +2380,16 @@ bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)co
 bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
 {
 	bool retval = false;
-	if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord)
+
+	const F32 epsilon = 0.00001f;
+
+	if (rhs.mData[POSITION].equals3(mData[POSITION], epsilon) && 
+		fabs(rhs.mTexCoord[0]-mTexCoord[0]) < epsilon &&
+		fabs(rhs.mTexCoord[1]-mTexCoord[1]) < epsilon)
 	{
 		if (angle_cutoff > 1.f)
 		{
-			retval = (mData[NORMAL].equals3(rhs.mData[NORMAL]));
+			retval = (mData[NORMAL].equals3(rhs.mData[NORMAL], epsilon));
 		}
 		else
 		{
@@ -2499,9 +2505,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 			}
 
 			{
-				U16* n = (U16*) &(norm[0]);
-				if(n)
+				if (!norm.empty())
 				{
+					U16* n = (U16*) &(norm[0]);
 					for (U32 j = 0; j < num_verts; ++j)
 					{
 						norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
@@ -2512,12 +2518,16 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 						n += 3;
 					}
 				}
+				else
+				{
+					memset(norm_out, 0, sizeof(LLVector4a)*num_verts);
+				}
 			}
 
 			{
-				U16* t = (U16*) &(tc[0]);
-				if(t)
+				if (!tc.empty())
 				{
+					U16* t = (U16*) &(tc[0]);
 					for (U32 j = 0; j < num_verts; j+=2)
 					{
 						if (j < num_verts-1)
@@ -2538,6 +2548,10 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 						tc_out++;
 					}
 				}
+				else
+				{
+					memset(tc_out, 0, sizeof(LLVector2)*num_verts);
+				}
 			}
 
 			if (mdl[i].has("Weights"))
@@ -2662,6 +2676,25 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 					min.setMin(min, face.mPositions[i]);
 					max.setMax(max, face.mPositions[i]);
 				}
+
+				if (face.mTexCoords)
+				{
+					LLVector2& min_tc = face.mTexCoordExtents[0];
+					LLVector2& max_tc = face.mTexCoordExtents[1];
+
+					min_tc = face.mTexCoords[0];
+					max_tc = face.mTexCoords[0];
+
+					for (U32 j = 1; j < face.mNumVertices; ++j)
+					{
+						update_min_max(min_tc, max_tc, face.mTexCoords[j]);
+					}
+				}
+				else
+				{
+					face.mTexCoordExtents[0].set(0,0);
+					face.mTexCoordExtents[1].set(1,1);
+				}
 			}
 		}
 	}
@@ -2741,11 +2774,13 @@ void LLVolume::makeTetrahedron()
 	n[2] = cv[2].getNormal();
 	n += 3;
 
-	tc[0] = cv[0].mTexCoord;
-	tc[1] = cv[1].mTexCoord;
-	tc[2] = cv[2].mTexCoord;
-	tc += 3;
-
+	if(tc)
+	{
+		tc[0] = cv[0].mTexCoord;
+		tc[1] = cv[1].mTexCoord;
+		tc[2] = cv[2].mTexCoord;
+		tc += 3;
+	}
 	
 	//side 2
 	cv[0].setPosition(p[3]);
@@ -2764,11 +2799,14 @@ void LLVolume::makeTetrahedron()
 	n[2] = cv[2].getNormal();
 	n += 3;
 
-	tc[0] = cv[0].mTexCoord;
-	tc[1] = cv[1].mTexCoord;
-	tc[2] = cv[2].mTexCoord;
-	tc += 3;
-	
+	if(tc)
+	{
+		tc[0] = cv[0].mTexCoord;
+		tc[1] = cv[1].mTexCoord;
+		tc[2] = cv[2].mTexCoord;
+		tc += 3;
+	}
+
 	//side 3
 	cv[0].setPosition(p[3]);
 	cv[1].setPosition(p[1]);
@@ -2786,10 +2824,13 @@ void LLVolume::makeTetrahedron()
 	n[2] = cv[2].getNormal();
 	n += 3;
 
-	tc[0] = cv[0].mTexCoord;
-	tc[1] = cv[1].mTexCoord;
-	tc[2] = cv[2].mTexCoord;
-	tc += 3;
+	if(tc)
+	{
+		tc[0] = cv[0].mTexCoord;
+		tc[1] = cv[1].mTexCoord;
+		tc[2] = cv[2].mTexCoord;
+		tc += 3;
+	}
 	
 	//side 4
 	cv[0].setPosition(p[2]);
@@ -2808,10 +2849,13 @@ void LLVolume::makeTetrahedron()
 	n[2] = cv[2].getNormal();
 	n += 3;
 
-	tc[0] = cv[0].mTexCoord;
-	tc[1] = cv[1].mTexCoord;
-	tc[2] = cv[2].mTexCoord;
-	tc += 3;
+	if(tc)
+	{
+		tc[0] = cv[0].mTexCoord;
+		tc[1] = cv[1].mTexCoord;
+		tc[2] = cv[2].mTexCoord;
+		tc += 3;
+	}
 	
 	//set index buffer
 	for (U16 i = 0; i < 12; i++)
@@ -5580,7 +5624,16 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 			
 		LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
 		LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
-		LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+
+		if(src.mTexCoords)
+		{
+			LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+		}
+		else
+		{
+			ll_aligned_free_16(mTexCoords) ;
+			mTexCoords = NULL ;
+		}
 
 
 		if (src.mBinormals)
@@ -5702,8 +5755,23 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
 {
 	cv.setPosition(mPositions[index]);
-	cv.setNormal(mNormals[index]);
-	cv.mTexCoord = mTexCoords[index];
+	if (mNormals)
+	{
+		cv.setNormal(mNormals[index]);
+	}
+	else
+	{
+		cv.getNormal().clear();
+	}
+
+	if (mTexCoords)
+	{
+		cv.mTexCoord = mTexCoords[index];
+	}
+	else
+	{
+		cv.mTexCoord.clear();
+	}
 }
 
 bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
@@ -5733,7 +5801,10 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
 	LLVolumeFace new_face;
 
 	//map of points to vector of vertices at that point
-	VertexMapData::PointMap point_map;
+	std::map<U64, std::vector<VertexMapData> > point_map;
+
+	LLVector4a range;
+	range.setSub(mExtents[1],mExtents[0]);
 
 	//remove redundant vertices
 	for (U32 i = 0; i < mNumIndices; ++i)
@@ -5744,7 +5815,19 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
 		getVertexData(index, cv);
 		
 		BOOL found = FALSE;
-		VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
+
+		LLVector4a pos;
+		pos.setSub(mPositions[index], mExtents[0]);
+		pos.div(range);
+
+		U64 pos64 = 0;
+
+		pos64 = (U16) (pos[0]*65535);
+		pos64 = pos64 | (((U64) (pos[1]*65535)) << 16);
+		pos64 = pos64 | (((U64) (pos[2]*65535)) << 32);
+
+		std::map<U64, std::vector<VertexMapData> >::iterator point_iter = point_map.find(pos64);
+		
 		if (point_iter != point_map.end())
 		{ //duplicate point might exist
 			for (U32 j = 0; j < point_iter->second.size(); ++j)
@@ -5776,11 +5859,26 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
 			}
 			else
 			{
-				point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
+				point_map[pos64].push_back(d);
 			}
 		}
 	}
 
+	llassert(new_face.mNumIndices == mNumIndices);
+	llassert(new_face.mNumVertices <= mNumVertices);
+
+	if (angle_cutoff > 1.f && !mNormals)
+	{
+		ll_aligned_free_16(new_face.mNormals);
+		new_face.mNormals = NULL;
+	}
+
+	if (!mTexCoords)
+	{
+		ll_aligned_free_16(new_face.mTexCoords);
+		new_face.mTexCoords = NULL;
+	}
+
 	swapData(new_face);
 }
 
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 0735842dcd2e625eef829b73e580d70cec4d2128..1a86a69a045f685ce5a1bb1000df7042c75c0eea 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -26,6 +26,7 @@
  * $/LicenseInfo$
  */
 
+
 #if LL_WINDOWS
 #define SAFE_SSL 1
 #elif LL_DARWIN
@@ -74,6 +75,7 @@ static const S32 MULTI_PERFORM_CALL_REPEAT	= 5;
 static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds
 static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
 
+static 
 // DEBUG //
 S32 gCurlEasyCount = 0;
 S32 gCurlMultiCount = 0;
@@ -85,6 +87,9 @@ std::vector<LLMutex*> LLCurl::sSSLMutex;
 std::string LLCurl::sCAPath;
 std::string LLCurl::sCAFile;
 
+bool LLCurl::sMultiThreaded = false;
+static U32 sMainThreadID = 0;
+
 void check_curl_code(CURLcode code)
 {
 	if (code != CURLE_OK)
@@ -244,7 +249,7 @@ class LLCurl::Easy
 	U32 report(CURLcode);
 	void getTransferInfo(LLCurl::TransferInfo* info);
 
-	void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, bool post = false);
+	void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false);
 	
 	const char* getErrorBuffer();
 
@@ -525,7 +530,7 @@ size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data
 
 void LLCurl::Easy::prepRequest(const std::string& url,
 							   const std::vector<std::string>& headers,
-							   ResponderPtr responder, bool post)
+							   ResponderPtr responder, S32 time_out, bool post)
 {
 	resetState();
 	
@@ -558,7 +563,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
 	
 	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)
 	setopt(CURLOPT_SSL_VERIFYHOST, 0);
-	setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
+	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));
 
 	setoptString(CURLOPT_URL, url);
 
@@ -601,6 +606,7 @@ class LLCurl::Multi : public LLThread
 
 	S32 process();
 	void perform();
+	void doPerform();
 	
 	virtual void run();
 
@@ -613,6 +619,7 @@ class LLCurl::Multi : public LLThread
 
 	LLCondition* mSignal;
 	bool mQuitting;
+	bool mThreaded;
 
 private:
 	void easyFree(Easy*);
@@ -634,7 +641,16 @@ LLCurl::Multi::Multi()
 	  mPerformState(PERFORM_STATE_READY)
 {
 	mQuitting = false;
-	mSignal = new LLCondition(NULL);
+
+	mThreaded = LLCurl::sMultiThreaded && LLThread::currentID() == sMainThreadID;
+	if (mThreaded)
+	{
+		mSignal = new LLCondition(NULL);
+	}
+	else
+	{
+		mSignal = NULL;
+	}
 
 	mCurlMultiHandle = curl_multi_init();
 	if (!mCurlMultiHandle)
@@ -681,39 +697,53 @@ CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
 
 void LLCurl::Multi::perform()
 {
-	if (mPerformState == PERFORM_STATE_READY)
+	if (mThreaded)
+	{
+		if (mPerformState == PERFORM_STATE_READY)
+		{
+			mSignal->signal();
+		}
+	}
+	else
 	{
-		mSignal->signal();
+		doPerform();
 	}
 }
 
 void LLCurl::Multi::run()
 {
+	llassert(mThreaded);
+
 	while (!mQuitting)
 	{
 		mSignal->wait();
 		mPerformState = PERFORM_STATE_PERFORMING;
 		if (!mQuitting)
 		{
-			S32 q = 0;
-			for (S32 call_count = 0;
-				 call_count < MULTI_PERFORM_CALL_REPEAT;
-				 call_count += 1)
-			{
-				CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
-				if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
-				{
-					check_curl_multi_code(code);
-					break;
-				}
-	
-			}
-			mQueued = q;
-			mPerformState = PERFORM_STATE_COMPLETED;
+			doPerform();
 		}
 	}
 }
 
+void LLCurl::Multi::doPerform()
+{
+	S32 q = 0;
+	for (S32 call_count = 0;
+			call_count < MULTI_PERFORM_CALL_REPEAT;
+			call_count += 1)
+	{
+		CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
+		if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
+		{
+			check_curl_multi_code(code);
+			break;
+		}
+	
+	}
+	mQueued = q;
+	mPerformState = PERFORM_STATE_COMPLETED;
+}
+
 S32 LLCurl::Multi::process()
 {
 	perform();
@@ -839,10 +869,13 @@ LLCurlRequest::~LLCurlRequest()
 	{
 		LLCurl::Multi* multi = *iter;
 		multi->mQuitting = true;
-		while (!multi->isStopped())
+		if (multi->mThreaded)
 		{
-			multi->mSignal->signal();
-			apr_sleep(1000);
+			while (!multi->isStopped())
+			{
+				multi->mSignal->signal();
+				apr_sleep(1000);
+			}
 		}
 	}
 	for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer());
@@ -852,7 +885,10 @@ void LLCurlRequest::addMulti()
 {
 	llassert_always(mThreadID == LLThread::currentID());
 	LLCurl::Multi* multi = new LLCurl::Multi();
-	multi->start();
+	if (multi->mThreaded)
+	{
+		multi->start();
+	}
 	mMultiSet.insert(multi);
 	mActiveMulti = multi;
 	mActiveRequestCount = 0;
@@ -914,14 +950,14 @@ bool LLCurlRequest::getByteRange(const std::string& url,
 bool LLCurlRequest::post(const std::string& url,
 						 const headers_t& headers,
 						 const LLSD& data,
-						 LLCurl::ResponderPtr responder)
+						 LLCurl::ResponderPtr responder, S32 time_out)
 {
 	LLCurl::Easy* easy = allocEasy();
 	if (!easy)
 	{
 		return false;
 	}
-	easy->prepRequest(url, headers, responder);
+	easy->prepRequest(url, headers, responder, time_out);
 
 	LLSDSerialize::toXML(data, easy->getInput());
 	S32 bytes = easy->getInput().str().length();
@@ -941,14 +977,14 @@ bool LLCurlRequest::post(const std::string& url,
 bool LLCurlRequest::post(const std::string& url,
 						 const headers_t& headers,
 						 const std::string& data,
-						 LLCurl::ResponderPtr responder)
+						 LLCurl::ResponderPtr responder, S32 time_out)
 {
 	LLCurl::Easy* easy = allocEasy();
 	if (!easy)
 	{
 		return false;
 	}
-	easy->prepRequest(url, headers, responder);
+	easy->prepRequest(url, headers, responder, time_out);
 
 	easy->getInput().write(data.data(), data.size());
 	S32 bytes = easy->getInput().str().length();
@@ -983,10 +1019,13 @@ S32 LLCurlRequest::process()
 		{
 			mMultiSet.erase(curiter);
 			multi->mQuitting = true;
-			while (!multi->isStopped())
+			if (multi->mThreaded)
 			{
-				multi->mSignal->signal();
-				apr_sleep(1000);
+				while (!multi->isStopped())
+				{
+					multi->mSignal->signal();
+					apr_sleep(1000);
+				}
 			}
 
 			delete multi;
@@ -1006,6 +1045,10 @@ S32 LLCurlRequest::getQueued()
 		curlmulti_set_t::iterator curiter = iter++;
 		LLCurl::Multi* multi = *curiter;
 		queued += multi->mQueued;
+		if (multi->mPerformState != LLCurl::Multi::PERFORM_STATE_READY)
+		{
+			++queued;
+		}
 	}
 	return queued;
 }
@@ -1019,7 +1062,10 @@ LLCurlEasyRequest::LLCurlEasyRequest()
 	  mResultReturned(false)
 {
 	mMulti = new LLCurl::Multi();
-	mMulti->start();
+	if (mMulti->mThreaded)
+	{
+		mMulti->start();
+	}
 	mEasy = mMulti->allocEasy();
 	if (mEasy)
 	{
@@ -1031,10 +1077,13 @@ LLCurlEasyRequest::LLCurlEasyRequest()
 LLCurlEasyRequest::~LLCurlEasyRequest()
 {
 	mMulti->mQuitting = true;
-	while (!mMulti->isStopped())
+	if (mMulti->mThreaded)
 	{
-		mMulti->mSignal->signal();
-		apr_sleep(1000);
+		while (!mMulti->isStopped())
+		{
+			mMulti->mSignal->signal();
+			apr_sleep(1000);
+		}
 	}
 	delete mMulti;
 }
@@ -1230,8 +1279,10 @@ unsigned long LLCurl::ssl_thread_id(void)
 }
 #endif
 
-void LLCurl::initClass()
+void LLCurl::initClass(bool multi_threaded)
 {
+	sMainThreadID = LLThread::currentID();
+	sMultiThreaded = multi_threaded;
 	// Do not change this "unless you are familiar with and mean to control 
 	// internal operations of libcurl"
 	// - http://curl.haxx.se/libcurl/c/curl_global_init.html
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 2f951d6ab8eb0ebd905ac8438e13805c899cd348..f7518c8e5c2f9c42116d0d5e44fdd24bf88de7d8 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -41,6 +41,7 @@
 #include "llbuffer.h"
 #include "lliopipe.h"
 #include "llsd.h"
+#include "llthread.h"
 
 class LLMutex;
 
@@ -55,6 +56,8 @@ class LLCurl
 	class Easy;
 	class Multi;
 
+	static bool sMultiThreaded;
+
 	struct TransferInfo
 	{
 		TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
@@ -159,7 +162,7 @@ class LLCurl
 	/**
 	 * @ brief Initialize LLCurl class
 	 */
-	static void initClass();
+	static void initClass(bool multi_threaded = false);
 
 	/**
 	 * @ brief Cleanup LLCurl class
@@ -201,8 +204,8 @@ class LLCurlRequest
 
 	void get(const std::string& url, LLCurl::ResponderPtr responder);
 	bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
-	bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder);
-	bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder);
+	bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
+	bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
 	
 	S32  process();
 	S32  getQueued();
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index d3d0403bbbe6347f8ed93ccc85822d583a3a7664..d081109acc57e3298b1a2940e1f58962e7f56064 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1,1424 +1,1424 @@
-/** 
- * @file llpluginclassmedia.cpp
- * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
- *
- * @cond
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#include "linden_common.h"
-#include "indra_constants.h"
-
-#include "llpluginclassmedia.h"
-#include "llpluginmessageclasses.h"
-
-#include "llqtwebkit.h"
-
-static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
-
-static int nextPowerOf2( int value )
-{
-	int next_power_of_2 = 1;
-	while ( next_power_of_2 < value )
-	{
-		next_power_of_2 <<= 1;
-	}
-	
-	return next_power_of_2;
-}
-
-LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
-{
-	mOwner = owner;
-	mPlugin = NULL;
-	reset();
-
-	//debug use
-	mDeleteOK = true ;
-}
-
-
-LLPluginClassMedia::~LLPluginClassMedia()
-{
-	llassert_always(mDeleteOK) ;
-	reset();
-}
-
-bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
-{	
-	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
-	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
-	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
-	
-	mPlugin = new LLPluginProcessParent(this);
-	mPlugin->setSleepTime(mSleepTime);
-	
-	// Queue up the media init message -- it will be sent after all the currently queued messages.
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
-	message.setValue("target", mTarget);
-	sendMessage(message);
-	
-	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
-
-	return true;
-}
-
-
-void LLPluginClassMedia::reset()
-{
-	if(mPlugin != NULL)
-	{
-		delete mPlugin;
-		mPlugin = NULL;
-	}
-
-	mTextureParamsReceived = false;
-	mRequestedTextureDepth = 0;
-	mRequestedTextureInternalFormat = 0;
-	mRequestedTextureFormat = 0;
-	mRequestedTextureType = 0;
-	mRequestedTextureSwapBytes = false;
-	mRequestedTextureCoordsOpenGL = false;
-	mTextureSharedMemorySize = 0;
-	mTextureSharedMemoryName.clear();
-	mDefaultMediaWidth = 0;
-	mDefaultMediaHeight = 0;
-	mNaturalMediaWidth = 0;
-	mNaturalMediaHeight = 0;
-	mSetMediaWidth = -1;
-	mSetMediaHeight = -1;
-	mRequestedMediaWidth = 0;
-	mRequestedMediaHeight = 0;
-	mRequestedTextureWidth = 0;
-	mRequestedTextureHeight = 0;
-	mFullMediaWidth = 0;
-	mFullMediaHeight = 0;
-	mTextureWidth = 0;
-	mTextureHeight = 0;
-	mMediaWidth = 0;
-	mMediaHeight = 0;
-	mDirtyRect = LLRect::null;	
-	mAutoScaleMedia = false;
-	mRequestedVolume = 1.0f;
-	mPriority = PRIORITY_NORMAL;
-	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
-	mAllowDownsample = false;
-	mPadding = 0;
-	mLastMouseX = 0;
-	mLastMouseY = 0;
-	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
-	mSleepTime = 1.0f / 100.0f;
-	mCanCut = false;
-	mCanCopy = false;
-	mCanPaste = false;
-	mMediaName.clear();
-	mMediaDescription.clear();
-	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
-	
-	// media_browser class
-	mNavigateURI.clear();
-	mNavigateResultCode = -1;
-	mNavigateResultString.clear();
-	mHistoryBackAvailable = false;
-	mHistoryForwardAvailable = false;
-	mStatusText.clear();
-	mProgressPercent = 0;	
-	mClickURL.clear();
-	mClickNavType.clear();
-	mClickTarget.clear();
-	mClickUUID.clear();
-	mStatusCode = 0;
-	
-	// media_time class
-	mCurrentTime = 0.0f;
-	mDuration = 0.0f;
-	mCurrentRate = 0.0f;
-	mLoadedDuration = 0.0f;
-}
-
-void LLPluginClassMedia::idle(void)
-{
-	if(mPlugin)
-	{
-		mPlugin->idle();
-	}
-	
-	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
-	{
-		// Can't process a size change at this time
-	}
-	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
-	{
-		// Calculate the correct size for the media texture
-		mRequestedTextureHeight = mRequestedMediaHeight;
-		if(mPadding < 0)
-		{
-			// negative values indicate the plugin wants a power of 2
-			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
-		}
-		else
-		{
-			mRequestedTextureWidth = mRequestedMediaWidth;
-			
-			if(mPadding > 1)
-			{
-				// Pad up to a multiple of the specified number of bytes per row
-				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
-				int pad = rowbytes % mPadding;
-				if(pad != 0)
-				{
-					rowbytes += mPadding - pad;
-				}
-				
-				if(rowbytes % mRequestedTextureDepth == 0)
-				{
-					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
-				}
-				else
-				{
-					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
-				}
-			}
-		}
-
-		
-		// Size change has been requested but not initiated yet.
-		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
-
-		// Add an extra line for padding, just in case.
-		newsize += mRequestedTextureWidth * mRequestedTextureDepth;
-
-		if(newsize != mTextureSharedMemorySize)
-		{
-			if(!mTextureSharedMemoryName.empty())
-			{
-				// Tell the plugin to remove the old memory segment
-				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
-				mTextureSharedMemoryName.clear();
-			}
-			
-			mTextureSharedMemorySize = newsize;
-			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
-			if(!mTextureSharedMemoryName.empty())
-			{
-				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
-				
-				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
-				memset( addr, 0x00, newsize );
-				
-				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
-				// so it may not be worthwhile.
-				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
-			}
-		}
-		
-		// This is our local indicator that a change is in progress.
-		mTextureWidth = -1;
-		mTextureHeight = -1;
-		mMediaWidth = -1;
-		mMediaHeight = -1;
-
-		// This invalidates any existing dirty rect.
-		resetDirty();
-		
-		// Send a size change message to the plugin
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
-			message.setValue("name", mTextureSharedMemoryName);
-			message.setValueS32("width", mRequestedMediaWidth);
-			message.setValueS32("height", mRequestedMediaHeight);
-			message.setValueS32("texture_width", mRequestedTextureWidth);
-			message.setValueS32("texture_height", mRequestedTextureHeight);
-			message.setValueReal("background_r", mBackgroundColor.mV[VX]);
-			message.setValueReal("background_g", mBackgroundColor.mV[VY]);
-			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
-			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
-			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
-			
-			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
-		}
-	}
-	
-	if(mPlugin && mPlugin->isRunning())
-	{
-		// Send queued messages
-		while(!mSendQueue.empty())
-		{
-			LLPluginMessage message = mSendQueue.front();
-			mSendQueue.pop();
-			mPlugin->sendMessage(message);
-		}
-	}
-}
-
-int LLPluginClassMedia::getTextureWidth() const
-{
-	return nextPowerOf2(mTextureWidth);
-}
-
-int LLPluginClassMedia::getTextureHeight() const
-{
-	return nextPowerOf2(mTextureHeight);
-}
-
-unsigned char* LLPluginClassMedia::getBitsData()
-{
-	unsigned char *result = NULL;
-	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
-	{
-		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
-	}
-	return result;
-}
-
-void LLPluginClassMedia::setSize(int width, int height)
-{
-	if((width > 0) && (height > 0))
-	{
-		mSetMediaWidth = width;
-		mSetMediaHeight = height;
-	}
-	else
-	{
-		mSetMediaWidth = -1;
-		mSetMediaHeight = -1;
-	}
-
-	setSizeInternal();
-}
-
-void LLPluginClassMedia::setSizeInternal(void)
-{
-	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
-	{
-		mRequestedMediaWidth = mSetMediaWidth;
-		mRequestedMediaHeight = mSetMediaHeight;
-	}
-	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
-	{
-		mRequestedMediaWidth = mNaturalMediaWidth;
-		mRequestedMediaHeight = mNaturalMediaHeight;
-	}
-	else
-	{
-		mRequestedMediaWidth = mDefaultMediaWidth;
-		mRequestedMediaHeight = mDefaultMediaHeight;
-	}
-	
-	// Save these for size/interest calculations
-	mFullMediaWidth = mRequestedMediaWidth;
-	mFullMediaHeight = mRequestedMediaHeight;
-	
-	if(mAllowDownsample)
-	{
-		switch(mPriority)
-		{
-			case PRIORITY_SLIDESHOW:
-			case PRIORITY_LOW:
-				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
-				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
-				{
-					mRequestedMediaWidth /= 2;
-					mRequestedMediaHeight /= 2;
-				}
-			break;
-			
-			default:
-				// Don't adjust texture size
-			break;
-		}
-	}
-	
-	if(mAutoScaleMedia)
-	{
-		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
-		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
-	}
-	
-	if(mRequestedMediaWidth > 2048)
-		mRequestedMediaWidth = 2048;
-
-	if(mRequestedMediaHeight > 2048)
-		mRequestedMediaHeight = 2048;
-}
-
-void LLPluginClassMedia::setAutoScale(bool auto_scale)
-{
-	if(auto_scale != mAutoScaleMedia)
-	{
-		mAutoScaleMedia = auto_scale;
-		setSizeInternal();
-	}
-}
-
-bool LLPluginClassMedia::textureValid(void)
-{
-	if(
-		!mTextureParamsReceived ||
-		mTextureWidth <= 0 ||
-		mTextureHeight <= 0 ||
-		mMediaWidth <= 0 ||
-		mMediaHeight <= 0 ||
-		mRequestedMediaWidth != mMediaWidth ||
-		mRequestedMediaHeight != mMediaHeight ||
-		getBitsData() == NULL
-	)	
-		return false;
-	
-	return true;
-}
-
-bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
-{
-	bool result = !mDirtyRect.isEmpty();
-
-	if(dirty_rect != NULL)
-	{
-		*dirty_rect = mDirtyRect;
-	}
-
-	return result;
-}
-
-void LLPluginClassMedia::resetDirty(void)
-{
-	mDirtyRect = LLRect::null;
-}
-
-std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
-{
-	std::string result;
-	
-	
-	if(modifiers & MASK_CONTROL)
-	{
-		result += "control|";
-	}
-
-	if(modifiers & MASK_ALT)
-	{
-		result += "alt|";
-	}
-
-	if(modifiers & MASK_SHIFT)
-	{
-		result += "shift|";
-	}
-
-	// TODO: should I deal with platform differences here or in callers?
-	// TODO: how do we deal with the Mac "command" key?
-/*
-	if(modifiers & MASK_SOMETHING)
-	{
-		result += "meta|";
-	}
-*/	
-	return result;
-}
-
-void LLPluginClassMedia::jsEnableObject( bool enable )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
-	message.setValueBoolean( "enable", enable );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location");
-	message.setValueReal( "x", x );
-	message.setValueReal( "y", y );
-	message.setValueReal( "z", z );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location");
-	message.setValueReal( "x", x );
-	message.setValueReal( "y", y );
-	message.setValueReal( "z", z );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentOrientationEvent( double angle )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation");
-	message.setValueReal( "angle", angle );
-
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language");
-	message.setValue( "language", language );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region");
-	message.setValue( "region", region );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity");
-	message.setValue( "maturity", maturity );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
-{
-	if(type == MOUSE_EVENT_MOVE)
-	{
-		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
-		{
-			// Don't queue up mouse move events that can't be delivered.
-			return;
-		}
-
-		if((x == mLastMouseX) && (y == mLastMouseY))
-		{
-			// Don't spam unnecessary mouse move events.
-			return;
-		}
-		
-		mLastMouseX = x;
-		mLastMouseY = y;
-	}
-	
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
-	std::string temp;
-	switch(type)
-	{
-		case MOUSE_EVENT_DOWN:			temp = "down";			break;
-		case MOUSE_EVENT_UP:			temp = "up";			break;
-		case MOUSE_EVENT_MOVE:			temp = "move";			break;
-		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break;
-	}
-	message.setValue("event", temp);
-
-	message.setValueS32("button", button);
-
-	message.setValueS32("x", x);
-	
-	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
-	if(!mRequestedTextureCoordsOpenGL)
-	{
-		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
-		y = mMediaHeight - y;
-	}
-	message.setValueS32("y", y);
-
-	message.setValue("modifiers", translateModifiers(modifiers));
-	
-	sendMessage(message);
-}
-
-bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
-{
-	bool result = true;
-	
-	// FIXME:
-	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
-	// For now, return false for the ones the webkit plugin won't handle properly.
-	
-	switch(key_code)
-	{
-		case KEY_BACKSPACE:		
-		case KEY_TAB:			
-		case KEY_RETURN:		
-		case KEY_PAD_RETURN:	
-		case KEY_SHIFT:			
-		case KEY_CONTROL:		
-		case KEY_ALT:			
-		case KEY_CAPSLOCK:		
-		case KEY_ESCAPE:		
-		case KEY_PAGE_UP:		
-		case KEY_PAGE_DOWN:		
-		case KEY_END:			
-		case KEY_HOME:			
-		case KEY_LEFT:			
-		case KEY_UP:			
-		case KEY_RIGHT:			
-		case KEY_DOWN:			
-		case KEY_INSERT:		
-		case KEY_DELETE:
-			// These will be handled		
-		break;
-		
-		default:
-			// regular ASCII characters will also be handled
-			if(key_code >= KEY_SPECIAL)
-			{
-				// Other "special" codes will not work properly.
-				result = false;
-			}
-		break;
-	}
-
-#if LL_DARWIN	
-	if(modifiers & MASK_ALT)
-	{
-		// Option-key modified characters should be handled by the unicode input path instead of this one.
-		result = false;
-	}
-#endif
-
-	if(result)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
-		std::string temp;
-		switch(type)
-		{
-			case KEY_EVENT_DOWN:			temp = "down";			break;
-			case KEY_EVENT_UP:				temp = "up";			break;
-			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
-		}
-		message.setValue("event", temp);
-		
-		message.setValueS32("key", key_code);
-
-		message.setValue("modifiers", translateModifiers(modifiers));
-		message.setValueLLSD("native_key_data", native_key_data);
-		
-		sendMessage(message);
-	}
-		
-	return result;
-}
-
-void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
-
-	message.setValueS32("x", x);
-	message.setValueS32("y", y);
-	message.setValue("modifiers", translateModifiers(modifiers));
-	
-	sendMessage(message);
-}
-	
-bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
-
-	message.setValue("text", text);
-	message.setValue("modifiers", translateModifiers(modifiers));
-	message.setValueLLSD("native_key_data", native_key_data);
-	
-	sendMessage(message);
-	
-	return true;
-}
-
-void LLPluginClassMedia::loadURI(const std::string &uri)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
-
-	message.setValue("uri", uri);
-	
-	sendMessage(message);
-}
-
-const char* LLPluginClassMedia::priorityToString(EPriority priority)
-{
-	const char* result = "UNKNOWN";
-	switch(priority)
-	{
-		case PRIORITY_UNLOADED:		result = "unloaded";	break;
-		case PRIORITY_STOPPED:		result = "stopped";		break;
-		case PRIORITY_HIDDEN:		result = "hidden";		break;
-		case PRIORITY_SLIDESHOW:	result = "slideshow";	break;
-		case PRIORITY_LOW:			result = "low";			break;
-		case PRIORITY_NORMAL:		result = "normal";		break;
-		case PRIORITY_HIGH:			result = "high";		break;
-	}
-	
-	return result;
-}
-
-void LLPluginClassMedia::setPriority(EPriority priority)
-{
-	if(mPriority != priority)
-	{
-		mPriority = priority;
-
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
-		
-		std::string priority_string = priorityToString(priority);
-		switch(priority)
-		{
-			case PRIORITY_UNLOADED:	
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_STOPPED:	
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_HIDDEN:	
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_SLIDESHOW:
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_LOW:		
-				mSleepTime = 1.0f / 25.0f;
-			break;
-			case PRIORITY_NORMAL:	
-				mSleepTime = 1.0f / 50.0f;
-			break;
-			case PRIORITY_HIGH:		
-				mSleepTime = 1.0f / 100.0f;
-			break;
-		}
-		
-		message.setValue("priority", priority_string);
-
-		sendMessage(message);
-		
-		if(mPlugin)
-		{
-			mPlugin->setSleepTime(mSleepTime);
-		}
-		
-		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
-		
-		// This may affect the calculated size, so recalculate it here.
-		setSizeInternal();
-	}
-}
-
-void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
-{
-	int power = nextPowerOf2(size);
-	if(mLowPrioritySizeLimit != power)
-	{
-		mLowPrioritySizeLimit = power;
-
-		// This may affect the calculated size, so recalculate it here.
-		setSizeInternal();
-	}
-}
-
-F64 LLPluginClassMedia::getCPUUsage()
-{
-	F64 result = 0.0f;
-	
-	if(mPlugin)
-	{
-		result = mPlugin->getCPUUsage();
-	}
-	
-	return result;
-}
-
-void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
-	message.setValue("file", file);
-	if(mPlugin && mPlugin->isBlocked())
-	{
-		// If the plugin sent a blocking pick-file request, the response should unblock it.
-		message.setValueBoolean("blocking_response", true);
-	}
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
-	message.setValueBoolean("ok", ok);
-	message.setValue("username", username);
-	message.setValue("password", password);
-	if(mPlugin && mPlugin->isBlocked())
-	{
-		// If the plugin sent a blocking pick-file request, the response should unblock it.
-		message.setValueBoolean("blocking_response", true);
-	}
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::cut()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::copy()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::paste()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
-	message.setValue("path", user_data_path);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
-	message.setValue("language", language_code);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
-	message.setValueBoolean("enable", enabled);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
-	message.setValueBoolean("enable", enabled);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setTarget(const std::string &target)
-{
-	mTarget = target;
-}
-
-/* virtual */ 
-void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
-{
-	std::string message_class = message.getClass();
-	
-	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
-	{
-		std::string message_name = message.getName();
-		if(message_name == "texture_params")
-		{
-			mRequestedTextureDepth = message.getValueS32("depth");
-			mRequestedTextureInternalFormat = message.getValueU32("internalformat");
-			mRequestedTextureFormat = message.getValueU32("format");
-			mRequestedTextureType = message.getValueU32("type");
-			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
-			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
-			
-			// These two are optional, and will default to 0 if they're not specified.
-			mDefaultMediaWidth = message.getValueS32("default_width");
-			mDefaultMediaHeight = message.getValueS32("default_height");
-			
-			mAllowDownsample = message.getValueBoolean("allow_downsample");
-			mPadding = message.getValueS32("padding");
-
-			setSizeInternal();
-			
-			mTextureParamsReceived = true;
-		}
-		else if(message_name == "updated")
-		{			
-			if(message.hasValue("left"))
-			{
-				LLRect newDirtyRect;
-				newDirtyRect.mLeft = message.getValueS32("left");
-				newDirtyRect.mTop = message.getValueS32("top");
-				newDirtyRect.mRight = message.getValueS32("right");
-				newDirtyRect.mBottom = message.getValueS32("bottom");
-							
-				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
-				// If they're backwards, swap them.
-				if(newDirtyRect.mTop < newDirtyRect.mBottom)
-				{
-					S32 temp = newDirtyRect.mTop;
-					newDirtyRect.mTop = newDirtyRect.mBottom;
-					newDirtyRect.mBottom = temp;
-				}
-				
-				if(mDirtyRect.isEmpty())
-				{
-					mDirtyRect = newDirtyRect;
-				}
-				else
-				{
-					mDirtyRect.unionWith(newDirtyRect);
-				}
-
-				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
-					<< newDirtyRect.mLeft << ", "
-					<< newDirtyRect.mTop << ", "
-					<< newDirtyRect.mRight << ", "
-					<< newDirtyRect.mBottom << "), new dirty rect is: ("
-					<< mDirtyRect.mLeft << ", "
-					<< mDirtyRect.mTop << ", "
-					<< mDirtyRect.mRight << ", "
-					<< mDirtyRect.mBottom << ")"
-					<< LL_ENDL;
-				
-				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
-			}			
-			
-
-			bool time_duration_updated = false;
-			int previous_percent = mProgressPercent;
-
-			if(message.hasValue("current_time"))
-			{
-				mCurrentTime = message.getValueReal("current_time");
-				time_duration_updated = true;
-			}
-			if(message.hasValue("duration"))
-			{
-				mDuration = message.getValueReal("duration");
-				time_duration_updated = true;
-			}
-
-			if(message.hasValue("current_rate"))
-			{
-				mCurrentRate = message.getValueReal("current_rate");
-			}
-			
-			if(message.hasValue("loaded_duration"))
-			{
-				mLoadedDuration = message.getValueReal("loaded_duration");
-				time_duration_updated = true;
-			}
-			else
-			{
-				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
-				mLoadedDuration = mDuration;
-			}
-			
-			// Calculate a percentage based on the loaded duration and total duration.
-			if(mDuration != 0.0f)	// Don't divide by zero.
-			{
-				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
-			}
-
-			if(time_duration_updated)
-			{
-				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
-			}
-			
-			if(previous_percent != mProgressPercent)
-			{
-				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
-			}
-		}
-		else if(message_name == "media_status")
-		{
-			std::string status = message.getValue("status");
-			
-			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
-			
-			if(status == "loading")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
-			}
-			else if(status == "loaded")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
-			}
-			else if(status == "error")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
-			}
-			else if(status == "playing")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
-			}
-			else if(status == "paused")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
-			}
-			else if(status == "done")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
-			}
-			else
-			{
-				// empty string or any unknown string
-				mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
-			}
-		}
-		else if(message_name == "size_change_request")
-		{
-			S32 width = message.getValueS32("width");
-			S32 height = message.getValueS32("height");
-			std::string name = message.getValue("name");
-
-			// TODO: check that name matches?
-			mNaturalMediaWidth = width;
-			mNaturalMediaHeight = height;
-			
-			setSizeInternal();
-		}
-		else if(message_name == "size_change_response")
-		{
-			std::string name = message.getValue("name");
-			
-			// TODO: check that name matches?
-			
-			mTextureWidth = message.getValueS32("texture_width");
-			mTextureHeight = message.getValueS32("texture_height");
-			mMediaWidth = message.getValueS32("width");
-			mMediaHeight = message.getValueS32("height");
-			
-			// This invalidates any existing dirty rect.
-			resetDirty();
-			
-			// TODO: should we verify that the plugin sent back the right values?  
-			// Two size changes in a row may cause them to not match, due to queueing, etc.
-
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
-		}
-		else if(message_name == "cursor_changed")
-		{
-			mCursorName = message.getValue("name");
-
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
-		}
-		else if(message_name == "edit_state")
-		{
-			if(message.hasValue("cut"))
-			{
-				mCanCut = message.getValueBoolean("cut");
-			}
-			if(message.hasValue("copy"))
-			{
-				mCanCopy = message.getValueBoolean("copy");
-			}
-			if(message.hasValue("paste"))
-			{
-				mCanPaste = message.getValueBoolean("paste");
-			}
-		}
-		else if(message_name == "name_text")
-		{
-			mMediaName = message.getValue("name");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
-		}
-		else if(message_name == "pick_file")
-		{
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
-		}
-		else if(message_name == "auth_request")
-		{
-			mAuthURL = message.getValue("url");
-			mAuthRealm = message.getValue("realm");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
-		}
-		else
-		{
-			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
-		}
-	}
-	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
-	{
-		std::string message_name = message.getName();
-		if(message_name == "navigate_begin")
-		{
-			mNavigateURI = message.getValue("uri");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
-		}
-		else if(message_name == "navigate_complete")
-		{
-			mNavigateURI = message.getValue("uri");
-			mNavigateResultCode = message.getValueS32("result_code");
-			mNavigateResultString = message.getValue("result_string");
-			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
-			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
-			
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
-		}
-		else if(message_name == "progress")
-		{
-			mProgressPercent = message.getValueS32("percent");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
-		}
-		else if(message_name == "status_text")
-		{
-			mStatusText = message.getValue("status");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
-		}
-		else if(message_name == "location_changed")
-		{
-			mLocation = message.getValue("uri");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
-		}
-		else if(message_name == "click_href")
-		{
-			mClickURL = message.getValue("uri");
-			mClickTarget = message.getValue("target");
-			mClickUUID = message.getValue("uuid");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
-		}
-		else if(message_name == "click_nofollow")
-		{
-			mClickURL = message.getValue("uri");
-			mClickNavType = message.getValue("nav_type");
-			mClickTarget.clear();
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
-		}
-		else if(message_name == "navigate_error_page")
-		{
-			mStatusCode = message.getValueS32("status_code");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
-		}
-		else if(message_name == "cookie_set")
-		{
-			if(mOwner)
-			{
-				mOwner->handleCookieSet(this, message.getValue("cookie"));
-			}
-		}
-		else if(message_name == "close_request")
-		{
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
-		}
-		else if(message_name == "geometry_change")
-		{
-			mClickUUID = message.getValue("uuid");
-			mGeometryX = message.getValueS32("x");
-			mGeometryY = message.getValueS32("y");
-			mGeometryWidth = message.getValueS32("width");
-			mGeometryHeight = message.getValueS32("height");
-				
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
-		}
-		else if(message_name == "link_hovered")
-		{
-			// text is not currently used -- the tooltip hover text is taken from the "title".
-			mHoverLink = message.getValue("link");
-			mHoverText = message.getValue("title");
-			// message.getValue("text");
-				
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
-		}
-		else
-		{
-			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
-		}
-	}
-	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
-	{
-		std::string message_name = message.getName();
-
-		// This class hasn't defined any incoming messages yet.
-//		if(message_name == "message_name")
-//		{
-//		}
-//		else 
-		{
-			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
-		}
-	}
-
-}
-
-/* virtual */ 
-void LLPluginClassMedia::pluginLaunchFailed()
-{
-	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
-}
-
-/* virtual */ 
-void LLPluginClassMedia::pluginDied()
-{
-	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
-}
-
-void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
-{
-	if(mOwner)
-	{
-		mOwner->handleMediaEvent(this, event);
-	}
-}
-
-void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
-{
-	if(mPlugin && mPlugin->isRunning())
-	{
-		mPlugin->sendMessage(message);
-	}
-	else
-	{
-		// The plugin isn't set up yet -- queue this message to be sent after initialization.
-		mSendQueue.push(message);
-	}
-}
-
-////////////////////////////////////////////////////////////
-// MARK: media_browser class functions
-bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
-{
-	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
-	return !version.empty();
-}
-
-void LLPluginClassMedia::focus(bool focused)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
-
-	message.setValueBoolean("focused", focused);
-	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::clear_cache()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::clear_cookies()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::set_cookies(const std::string &cookies)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
-	message.setValue("cookies", cookies);	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::enable_cookies(bool enable)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
-	message.setValueBoolean("enable", enable);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
-
-	message.setValueBoolean("enable", enable);
-	message.setValue("host", host);
-	message.setValueS32("port", port);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_stop()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_reload(bool ignore_cache)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
-
-	message.setValueBoolean("ignore_cache", ignore_cache);
-	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_forward()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_back()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
-
-	message.setValue("user_agent", user_agent);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
-
-	message.setValue("target", target);
-	message.setValue("uuid", uuid);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
-
-	message.setValue("uuid", uuid);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
-	message.setValueBoolean("ignore", ignore);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
-	message.setValue("path", path);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::crashPlugin()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::hangPlugin()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
-
-	sendMessage(message);
-}
-
-
-////////////////////////////////////////////////////////////
-// MARK: media_time class functions
-bool LLPluginClassMedia::pluginSupportsMediaTime(void)
-{
-	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
-	return !version.empty();
-}
-
-void LLPluginClassMedia::stop()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::start(float rate)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
-
-	message.setValueReal("rate", rate);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::pause()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::seek(float time)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
-
-	message.setValueReal("time", time);
-	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setLoop(bool loop)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
-
-	message.setValueBoolean("loop", loop);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setVolume(float volume)
-{
-	if(volume != mRequestedVolume)
-	{
-		mRequestedVolume = volume;
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
-
-		message.setValueReal("volume", volume);
-		
-		sendMessage(message);
-	}
-}
-
-float LLPluginClassMedia::getVolume()
-{
-	return mRequestedVolume;
-}
-
-void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
-{
-	// Send URL history to plugin
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
-	message.setValueLLSD("history", url_history);
-	sendMessage(message);
-
-	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
-}
-
+/** 
+ * @file llpluginclassmedia.cpp
+ * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+#include "linden_common.h"
+#include "indra_constants.h"
+
+#include "llpluginclassmedia.h"
+#include "llpluginmessageclasses.h"
+
+#include "llqtwebkit.h"
+
+static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
+
+static int nextPowerOf2( int value )
+{
+	int next_power_of_2 = 1;
+	while ( next_power_of_2 < value )
+	{
+		next_power_of_2 <<= 1;
+	}
+	
+	return next_power_of_2;
+}
+
+LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
+{
+	mOwner = owner;
+	mPlugin = NULL;
+	reset();
+
+	//debug use
+	mDeleteOK = true ;
+}
+
+
+LLPluginClassMedia::~LLPluginClassMedia()
+{
+	llassert_always(mDeleteOK) ;
+	reset();
+}
+
+bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
+{	
+	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
+	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
+	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
+	
+	mPlugin = new LLPluginProcessParent(this);
+	mPlugin->setSleepTime(mSleepTime);
+	
+	// Queue up the media init message -- it will be sent after all the currently queued messages.
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
+	message.setValue("target", mTarget);
+	sendMessage(message);
+	
+	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
+
+	return true;
+}
+
+
+void LLPluginClassMedia::reset()
+{
+	if(mPlugin != NULL)
+	{
+		delete mPlugin;
+		mPlugin = NULL;
+	}
+
+	mTextureParamsReceived = false;
+	mRequestedTextureDepth = 0;
+	mRequestedTextureInternalFormat = 0;
+	mRequestedTextureFormat = 0;
+	mRequestedTextureType = 0;
+	mRequestedTextureSwapBytes = false;
+	mRequestedTextureCoordsOpenGL = false;
+	mTextureSharedMemorySize = 0;
+	mTextureSharedMemoryName.clear();
+	mDefaultMediaWidth = 0;
+	mDefaultMediaHeight = 0;
+	mNaturalMediaWidth = 0;
+	mNaturalMediaHeight = 0;
+	mSetMediaWidth = -1;
+	mSetMediaHeight = -1;
+	mRequestedMediaWidth = 0;
+	mRequestedMediaHeight = 0;
+	mRequestedTextureWidth = 0;
+	mRequestedTextureHeight = 0;
+	mFullMediaWidth = 0;
+	mFullMediaHeight = 0;
+	mTextureWidth = 0;
+	mTextureHeight = 0;
+	mMediaWidth = 0;
+	mMediaHeight = 0;
+	mDirtyRect = LLRect::null;	
+	mAutoScaleMedia = false;
+	mRequestedVolume = 1.0f;
+	mPriority = PRIORITY_NORMAL;
+	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
+	mAllowDownsample = false;
+	mPadding = 0;
+	mLastMouseX = 0;
+	mLastMouseY = 0;
+	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
+	mSleepTime = 1.0f / 100.0f;
+	mCanCut = false;
+	mCanCopy = false;
+	mCanPaste = false;
+	mMediaName.clear();
+	mMediaDescription.clear();
+	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
+	
+	// media_browser class
+	mNavigateURI.clear();
+	mNavigateResultCode = -1;
+	mNavigateResultString.clear();
+	mHistoryBackAvailable = false;
+	mHistoryForwardAvailable = false;
+	mStatusText.clear();
+	mProgressPercent = 0;	
+	mClickURL.clear();
+	mClickNavType.clear();
+	mClickTarget.clear();
+	mClickUUID.clear();
+	mStatusCode = 0;
+	
+	// media_time class
+	mCurrentTime = 0.0f;
+	mDuration = 0.0f;
+	mCurrentRate = 0.0f;
+	mLoadedDuration = 0.0f;
+}
+
+void LLPluginClassMedia::idle(void)
+{
+	if(mPlugin)
+	{
+		mPlugin->idle();
+	}
+	
+	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
+	{
+		// Can't process a size change at this time
+	}
+	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
+	{
+		// Calculate the correct size for the media texture
+		mRequestedTextureHeight = mRequestedMediaHeight;
+		if(mPadding < 0)
+		{
+			// negative values indicate the plugin wants a power of 2
+			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
+		}
+		else
+		{
+			mRequestedTextureWidth = mRequestedMediaWidth;
+			
+			if(mPadding > 1)
+			{
+				// Pad up to a multiple of the specified number of bytes per row
+				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
+				int pad = rowbytes % mPadding;
+				if(pad != 0)
+				{
+					rowbytes += mPadding - pad;
+				}
+				
+				if(rowbytes % mRequestedTextureDepth == 0)
+				{
+					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
+				}
+				else
+				{
+					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
+				}
+			}
+		}
+
+		
+		// Size change has been requested but not initiated yet.
+		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
+
+		// Add an extra line for padding, just in case.
+		newsize += mRequestedTextureWidth * mRequestedTextureDepth;
+
+		if(newsize != mTextureSharedMemorySize)
+		{
+			if(!mTextureSharedMemoryName.empty())
+			{
+				// Tell the plugin to remove the old memory segment
+				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
+				mTextureSharedMemoryName.clear();
+			}
+			
+			mTextureSharedMemorySize = newsize;
+			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
+			if(!mTextureSharedMemoryName.empty())
+			{
+				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
+				
+				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
+				memset( addr, 0x00, newsize );
+				
+				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
+				// so it may not be worthwhile.
+				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
+			}
+		}
+		
+		// This is our local indicator that a change is in progress.
+		mTextureWidth = -1;
+		mTextureHeight = -1;
+		mMediaWidth = -1;
+		mMediaHeight = -1;
+
+		// This invalidates any existing dirty rect.
+		resetDirty();
+		
+		// Send a size change message to the plugin
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
+			message.setValue("name", mTextureSharedMemoryName);
+			message.setValueS32("width", mRequestedMediaWidth);
+			message.setValueS32("height", mRequestedMediaHeight);
+			message.setValueS32("texture_width", mRequestedTextureWidth);
+			message.setValueS32("texture_height", mRequestedTextureHeight);
+			message.setValueReal("background_r", mBackgroundColor.mV[VX]);
+			message.setValueReal("background_g", mBackgroundColor.mV[VY]);
+			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
+			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
+			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
+			
+			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
+		}
+	}
+	
+	if(mPlugin && mPlugin->isRunning())
+	{
+		// Send queued messages
+		while(!mSendQueue.empty())
+		{
+			LLPluginMessage message = mSendQueue.front();
+			mSendQueue.pop();
+			mPlugin->sendMessage(message);
+		}
+	}
+}
+
+int LLPluginClassMedia::getTextureWidth() const
+{
+	return nextPowerOf2(mTextureWidth);
+}
+
+int LLPluginClassMedia::getTextureHeight() const
+{
+	return nextPowerOf2(mTextureHeight);
+}
+
+unsigned char* LLPluginClassMedia::getBitsData()
+{
+	unsigned char *result = NULL;
+	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
+	{
+		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
+	}
+	return result;
+}
+
+void LLPluginClassMedia::setSize(int width, int height)
+{
+	if((width > 0) && (height > 0))
+	{
+		mSetMediaWidth = width;
+		mSetMediaHeight = height;
+	}
+	else
+	{
+		mSetMediaWidth = -1;
+		mSetMediaHeight = -1;
+	}
+
+	setSizeInternal();
+}
+
+void LLPluginClassMedia::setSizeInternal(void)
+{
+	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
+	{
+		mRequestedMediaWidth = mSetMediaWidth;
+		mRequestedMediaHeight = mSetMediaHeight;
+	}
+	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
+	{
+		mRequestedMediaWidth = mNaturalMediaWidth;
+		mRequestedMediaHeight = mNaturalMediaHeight;
+	}
+	else
+	{
+		mRequestedMediaWidth = mDefaultMediaWidth;
+		mRequestedMediaHeight = mDefaultMediaHeight;
+	}
+	
+	// Save these for size/interest calculations
+	mFullMediaWidth = mRequestedMediaWidth;
+	mFullMediaHeight = mRequestedMediaHeight;
+	
+	if(mAllowDownsample)
+	{
+		switch(mPriority)
+		{
+			case PRIORITY_SLIDESHOW:
+			case PRIORITY_LOW:
+				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
+				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
+				{
+					mRequestedMediaWidth /= 2;
+					mRequestedMediaHeight /= 2;
+				}
+			break;
+			
+			default:
+				// Don't adjust texture size
+			break;
+		}
+	}
+	
+	if(mAutoScaleMedia)
+	{
+		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
+		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
+	}
+	
+	if(mRequestedMediaWidth > 2048)
+		mRequestedMediaWidth = 2048;
+
+	if(mRequestedMediaHeight > 2048)
+		mRequestedMediaHeight = 2048;
+}
+
+void LLPluginClassMedia::setAutoScale(bool auto_scale)
+{
+	if(auto_scale != mAutoScaleMedia)
+	{
+		mAutoScaleMedia = auto_scale;
+		setSizeInternal();
+	}
+}
+
+bool LLPluginClassMedia::textureValid(void)
+{
+	if(
+		!mTextureParamsReceived ||
+		mTextureWidth <= 0 ||
+		mTextureHeight <= 0 ||
+		mMediaWidth <= 0 ||
+		mMediaHeight <= 0 ||
+		mRequestedMediaWidth != mMediaWidth ||
+		mRequestedMediaHeight != mMediaHeight ||
+		getBitsData() == NULL
+	)	
+		return false;
+	
+	return true;
+}
+
+bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
+{
+	bool result = !mDirtyRect.isEmpty();
+
+	if(dirty_rect != NULL)
+	{
+		*dirty_rect = mDirtyRect;
+	}
+
+	return result;
+}
+
+void LLPluginClassMedia::resetDirty(void)
+{
+	mDirtyRect = LLRect::null;
+}
+
+std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
+{
+	std::string result;
+	
+	
+	if(modifiers & MASK_CONTROL)
+	{
+		result += "control|";
+	}
+
+	if(modifiers & MASK_ALT)
+	{
+		result += "alt|";
+	}
+
+	if(modifiers & MASK_SHIFT)
+	{
+		result += "shift|";
+	}
+
+	// TODO: should I deal with platform differences here or in callers?
+	// TODO: how do we deal with the Mac "command" key?
+/*
+	if(modifiers & MASK_SOMETHING)
+	{
+		result += "meta|";
+	}
+*/	
+	return result;
+}
+
+void LLPluginClassMedia::jsEnableObject( bool enable )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
+	message.setValueBoolean( "enable", enable );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location");
+	message.setValueReal( "x", x );
+	message.setValueReal( "y", y );
+	message.setValueReal( "z", z );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location");
+	message.setValueReal( "x", x );
+	message.setValueReal( "y", y );
+	message.setValueReal( "z", z );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentOrientationEvent( double angle )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation");
+	message.setValueReal( "angle", angle );
+
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language");
+	message.setValue( "language", language );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region");
+	message.setValue( "region", region );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity");
+	message.setValue( "maturity", maturity );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
+{
+	if(type == MOUSE_EVENT_MOVE)
+	{
+		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
+		{
+			// Don't queue up mouse move events that can't be delivered.
+			return;
+		}
+
+		if((x == mLastMouseX) && (y == mLastMouseY))
+		{
+			// Don't spam unnecessary mouse move events.
+			return;
+		}
+		
+		mLastMouseX = x;
+		mLastMouseY = y;
+	}
+	
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
+	std::string temp;
+	switch(type)
+	{
+		case MOUSE_EVENT_DOWN:			temp = "down";			break;
+		case MOUSE_EVENT_UP:			temp = "up";			break;
+		case MOUSE_EVENT_MOVE:			temp = "move";			break;
+		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break;
+	}
+	message.setValue("event", temp);
+
+	message.setValueS32("button", button);
+
+	message.setValueS32("x", x);
+	
+	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
+	if(!mRequestedTextureCoordsOpenGL)
+	{
+		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
+		y = mMediaHeight - y;
+	}
+	message.setValueS32("y", y);
+
+	message.setValue("modifiers", translateModifiers(modifiers));
+	
+	sendMessage(message);
+}
+
+bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
+{
+	bool result = true;
+	
+	// FIXME:
+	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
+	// For now, return false for the ones the webkit plugin won't handle properly.
+	
+	switch(key_code)
+	{
+		case KEY_BACKSPACE:		
+		case KEY_TAB:			
+		case KEY_RETURN:		
+		case KEY_PAD_RETURN:	
+		case KEY_SHIFT:			
+		case KEY_CONTROL:		
+		case KEY_ALT:			
+		case KEY_CAPSLOCK:		
+		case KEY_ESCAPE:		
+		case KEY_PAGE_UP:		
+		case KEY_PAGE_DOWN:		
+		case KEY_END:			
+		case KEY_HOME:			
+		case KEY_LEFT:			
+		case KEY_UP:			
+		case KEY_RIGHT:			
+		case KEY_DOWN:			
+		case KEY_INSERT:		
+		case KEY_DELETE:
+			// These will be handled		
+		break;
+		
+		default:
+			// regular ASCII characters will also be handled
+			if(key_code >= KEY_SPECIAL)
+			{
+				// Other "special" codes will not work properly.
+				result = false;
+			}
+		break;
+	}
+
+#if LL_DARWIN	
+	if(modifiers & MASK_ALT)
+	{
+		// Option-key modified characters should be handled by the unicode input path instead of this one.
+		result = false;
+	}
+#endif
+
+	if(result)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
+		std::string temp;
+		switch(type)
+		{
+			case KEY_EVENT_DOWN:			temp = "down";			break;
+			case KEY_EVENT_UP:				temp = "up";			break;
+			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
+		}
+		message.setValue("event", temp);
+		
+		message.setValueS32("key", key_code);
+
+		message.setValue("modifiers", translateModifiers(modifiers));
+		message.setValueLLSD("native_key_data", native_key_data);
+		
+		sendMessage(message);
+	}
+		
+	return result;
+}
+
+void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
+
+	message.setValueS32("x", x);
+	message.setValueS32("y", y);
+	message.setValue("modifiers", translateModifiers(modifiers));
+	
+	sendMessage(message);
+}
+	
+bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
+
+	message.setValue("text", text);
+	message.setValue("modifiers", translateModifiers(modifiers));
+	message.setValueLLSD("native_key_data", native_key_data);
+	
+	sendMessage(message);
+	
+	return true;
+}
+
+void LLPluginClassMedia::loadURI(const std::string &uri)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
+
+	message.setValue("uri", uri);
+	
+	sendMessage(message);
+}
+
+const char* LLPluginClassMedia::priorityToString(EPriority priority)
+{
+	const char* result = "UNKNOWN";
+	switch(priority)
+	{
+		case PRIORITY_UNLOADED:		result = "unloaded";	break;
+		case PRIORITY_STOPPED:		result = "stopped";		break;
+		case PRIORITY_HIDDEN:		result = "hidden";		break;
+		case PRIORITY_SLIDESHOW:	result = "slideshow";	break;
+		case PRIORITY_LOW:			result = "low";			break;
+		case PRIORITY_NORMAL:		result = "normal";		break;
+		case PRIORITY_HIGH:			result = "high";		break;
+	}
+	
+	return result;
+}
+
+void LLPluginClassMedia::setPriority(EPriority priority)
+{
+	if(mPriority != priority)
+	{
+		mPriority = priority;
+
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
+		
+		std::string priority_string = priorityToString(priority);
+		switch(priority)
+		{
+			case PRIORITY_UNLOADED:	
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_STOPPED:	
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_HIDDEN:	
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_SLIDESHOW:
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_LOW:		
+				mSleepTime = 1.0f / 25.0f;
+			break;
+			case PRIORITY_NORMAL:	
+				mSleepTime = 1.0f / 50.0f;
+			break;
+			case PRIORITY_HIGH:		
+				mSleepTime = 1.0f / 100.0f;
+			break;
+		}
+		
+		message.setValue("priority", priority_string);
+
+		sendMessage(message);
+		
+		if(mPlugin)
+		{
+			mPlugin->setSleepTime(mSleepTime);
+		}
+		
+		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
+		
+		// This may affect the calculated size, so recalculate it here.
+		setSizeInternal();
+	}
+}
+
+void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
+{
+	int power = nextPowerOf2(size);
+	if(mLowPrioritySizeLimit != power)
+	{
+		mLowPrioritySizeLimit = power;
+
+		// This may affect the calculated size, so recalculate it here.
+		setSizeInternal();
+	}
+}
+
+F64 LLPluginClassMedia::getCPUUsage()
+{
+	F64 result = 0.0f;
+	
+	if(mPlugin)
+	{
+		result = mPlugin->getCPUUsage();
+	}
+	
+	return result;
+}
+
+void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
+	message.setValue("file", file);
+	if(mPlugin && mPlugin->isBlocked())
+	{
+		// If the plugin sent a blocking pick-file request, the response should unblock it.
+		message.setValueBoolean("blocking_response", true);
+	}
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
+	message.setValueBoolean("ok", ok);
+	message.setValue("username", username);
+	message.setValue("password", password);
+	if(mPlugin && mPlugin->isBlocked())
+	{
+		// If the plugin sent a blocking pick-file request, the response should unblock it.
+		message.setValueBoolean("blocking_response", true);
+	}
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::cut()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::copy()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::paste()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
+	message.setValue("path", user_data_path);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
+	message.setValue("language", language_code);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
+	message.setValueBoolean("enable", enabled);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
+	message.setValueBoolean("enable", enabled);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setTarget(const std::string &target)
+{
+	mTarget = target;
+}
+
+/* virtual */ 
+void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
+{
+	std::string message_class = message.getClass();
+	
+	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+	{
+		std::string message_name = message.getName();
+		if(message_name == "texture_params")
+		{
+			mRequestedTextureDepth = message.getValueS32("depth");
+			mRequestedTextureInternalFormat = message.getValueU32("internalformat");
+			mRequestedTextureFormat = message.getValueU32("format");
+			mRequestedTextureType = message.getValueU32("type");
+			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
+			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
+			
+			// These two are optional, and will default to 0 if they're not specified.
+			mDefaultMediaWidth = message.getValueS32("default_width");
+			mDefaultMediaHeight = message.getValueS32("default_height");
+			
+			mAllowDownsample = message.getValueBoolean("allow_downsample");
+			mPadding = message.getValueS32("padding");
+
+			setSizeInternal();
+			
+			mTextureParamsReceived = true;
+		}
+		else if(message_name == "updated")
+		{			
+			if(message.hasValue("left"))
+			{
+				LLRect newDirtyRect;
+				newDirtyRect.mLeft = message.getValueS32("left");
+				newDirtyRect.mTop = message.getValueS32("top");
+				newDirtyRect.mRight = message.getValueS32("right");
+				newDirtyRect.mBottom = message.getValueS32("bottom");
+							
+				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
+				// If they're backwards, swap them.
+				if(newDirtyRect.mTop < newDirtyRect.mBottom)
+				{
+					S32 temp = newDirtyRect.mTop;
+					newDirtyRect.mTop = newDirtyRect.mBottom;
+					newDirtyRect.mBottom = temp;
+				}
+				
+				if(mDirtyRect.isEmpty())
+				{
+					mDirtyRect = newDirtyRect;
+				}
+				else
+				{
+					mDirtyRect.unionWith(newDirtyRect);
+				}
+
+				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
+					<< newDirtyRect.mLeft << ", "
+					<< newDirtyRect.mTop << ", "
+					<< newDirtyRect.mRight << ", "
+					<< newDirtyRect.mBottom << "), new dirty rect is: ("
+					<< mDirtyRect.mLeft << ", "
+					<< mDirtyRect.mTop << ", "
+					<< mDirtyRect.mRight << ", "
+					<< mDirtyRect.mBottom << ")"
+					<< LL_ENDL;
+				
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
+			}			
+			
+
+			bool time_duration_updated = false;
+			int previous_percent = mProgressPercent;
+
+			if(message.hasValue("current_time"))
+			{
+				mCurrentTime = message.getValueReal("current_time");
+				time_duration_updated = true;
+			}
+			if(message.hasValue("duration"))
+			{
+				mDuration = message.getValueReal("duration");
+				time_duration_updated = true;
+			}
+
+			if(message.hasValue("current_rate"))
+			{
+				mCurrentRate = message.getValueReal("current_rate");
+			}
+			
+			if(message.hasValue("loaded_duration"))
+			{
+				mLoadedDuration = message.getValueReal("loaded_duration");
+				time_duration_updated = true;
+			}
+			else
+			{
+				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
+				mLoadedDuration = mDuration;
+			}
+			
+			// Calculate a percentage based on the loaded duration and total duration.
+			if(mDuration != 0.0f)	// Don't divide by zero.
+			{
+				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
+			}
+
+			if(time_duration_updated)
+			{
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
+			}
+			
+			if(previous_percent != mProgressPercent)
+			{
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
+			}
+		}
+		else if(message_name == "media_status")
+		{
+			std::string status = message.getValue("status");
+			
+			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
+			
+			if(status == "loading")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
+			}
+			else if(status == "loaded")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
+			}
+			else if(status == "error")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
+			}
+			else if(status == "playing")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
+			}
+			else if(status == "paused")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
+			}
+			else if(status == "done")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
+			}
+			else
+			{
+				// empty string or any unknown string
+				mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
+			}
+		}
+		else if(message_name == "size_change_request")
+		{
+			S32 width = message.getValueS32("width");
+			S32 height = message.getValueS32("height");
+			std::string name = message.getValue("name");
+
+			// TODO: check that name matches?
+			mNaturalMediaWidth = width;
+			mNaturalMediaHeight = height;
+			
+			setSizeInternal();
+		}
+		else if(message_name == "size_change_response")
+		{
+			std::string name = message.getValue("name");
+			
+			// TODO: check that name matches?
+			
+			mTextureWidth = message.getValueS32("texture_width");
+			mTextureHeight = message.getValueS32("texture_height");
+			mMediaWidth = message.getValueS32("width");
+			mMediaHeight = message.getValueS32("height");
+			
+			// This invalidates any existing dirty rect.
+			resetDirty();
+			
+			// TODO: should we verify that the plugin sent back the right values?  
+			// Two size changes in a row may cause them to not match, due to queueing, etc.
+
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
+		}
+		else if(message_name == "cursor_changed")
+		{
+			mCursorName = message.getValue("name");
+
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
+		}
+		else if(message_name == "edit_state")
+		{
+			if(message.hasValue("cut"))
+			{
+				mCanCut = message.getValueBoolean("cut");
+			}
+			if(message.hasValue("copy"))
+			{
+				mCanCopy = message.getValueBoolean("copy");
+			}
+			if(message.hasValue("paste"))
+			{
+				mCanPaste = message.getValueBoolean("paste");
+			}
+		}
+		else if(message_name == "name_text")
+		{
+			mMediaName = message.getValue("name");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
+		}
+		else if(message_name == "pick_file")
+		{
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
+		}
+		else if(message_name == "auth_request")
+		{
+			mAuthURL = message.getValue("url");
+			mAuthRealm = message.getValue("realm");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
+		}
+		else
+		{
+			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
+		}
+	}
+	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
+	{
+		std::string message_name = message.getName();
+		if(message_name == "navigate_begin")
+		{
+			mNavigateURI = message.getValue("uri");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
+		}
+		else if(message_name == "navigate_complete")
+		{
+			mNavigateURI = message.getValue("uri");
+			mNavigateResultCode = message.getValueS32("result_code");
+			mNavigateResultString = message.getValue("result_string");
+			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
+			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
+			
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
+		}
+		else if(message_name == "progress")
+		{
+			mProgressPercent = message.getValueS32("percent");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
+		}
+		else if(message_name == "status_text")
+		{
+			mStatusText = message.getValue("status");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
+		}
+		else if(message_name == "location_changed")
+		{
+			mLocation = message.getValue("uri");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
+		}
+		else if(message_name == "click_href")
+		{
+			mClickURL = message.getValue("uri");
+			mClickTarget = message.getValue("target");
+			mClickUUID = message.getValue("uuid");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
+		}
+		else if(message_name == "click_nofollow")
+		{
+			mClickURL = message.getValue("uri");
+			mClickNavType = message.getValue("nav_type");
+			mClickTarget.clear();
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
+		}
+		else if(message_name == "navigate_error_page")
+		{
+			mStatusCode = message.getValueS32("status_code");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
+		}
+		else if(message_name == "cookie_set")
+		{
+			if(mOwner)
+			{
+				mOwner->handleCookieSet(this, message.getValue("cookie"));
+			}
+		}
+		else if(message_name == "close_request")
+		{
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
+		}
+		else if(message_name == "geometry_change")
+		{
+			mClickUUID = message.getValue("uuid");
+			mGeometryX = message.getValueS32("x");
+			mGeometryY = message.getValueS32("y");
+			mGeometryWidth = message.getValueS32("width");
+			mGeometryHeight = message.getValueS32("height");
+				
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
+		}
+		else if(message_name == "link_hovered")
+		{
+			// text is not currently used -- the tooltip hover text is taken from the "title".
+			mHoverLink = message.getValue("link");
+			mHoverText = message.getValue("title");
+			// message.getValue("text");
+				
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
+		}
+		else
+		{
+			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
+		}
+	}
+	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+	{
+		std::string message_name = message.getName();
+
+		// This class hasn't defined any incoming messages yet.
+//		if(message_name == "message_name")
+//		{
+//		}
+//		else 
+		{
+			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
+		}
+	}
+
+}
+
+/* virtual */ 
+void LLPluginClassMedia::pluginLaunchFailed()
+{
+	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
+}
+
+/* virtual */ 
+void LLPluginClassMedia::pluginDied()
+{
+	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
+}
+
+void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
+{
+	if(mOwner)
+	{
+		mOwner->handleMediaEvent(this, event);
+	}
+}
+
+void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
+{
+	if(mPlugin && mPlugin->isRunning())
+	{
+		mPlugin->sendMessage(message);
+	}
+	else
+	{
+		// The plugin isn't set up yet -- queue this message to be sent after initialization.
+		mSendQueue.push(message);
+	}
+}
+
+////////////////////////////////////////////////////////////
+// MARK: media_browser class functions
+bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
+{
+	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
+	return !version.empty();
+}
+
+void LLPluginClassMedia::focus(bool focused)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
+
+	message.setValueBoolean("focused", focused);
+	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::clear_cache()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::clear_cookies()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::set_cookies(const std::string &cookies)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
+	message.setValue("cookies", cookies);	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::enable_cookies(bool enable)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
+	message.setValueBoolean("enable", enable);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
+
+	message.setValueBoolean("enable", enable);
+	message.setValue("host", host);
+	message.setValueS32("port", port);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_stop()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_reload(bool ignore_cache)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
+
+	message.setValueBoolean("ignore_cache", ignore_cache);
+	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_forward()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_back()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
+
+	message.setValue("user_agent", user_agent);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
+
+	message.setValue("target", target);
+	message.setValue("uuid", uuid);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
+
+	message.setValue("uuid", uuid);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
+	message.setValueBoolean("ignore", ignore);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
+	message.setValue("path", path);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::crashPlugin()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::hangPlugin()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
+
+	sendMessage(message);
+}
+
+
+////////////////////////////////////////////////////////////
+// MARK: media_time class functions
+bool LLPluginClassMedia::pluginSupportsMediaTime(void)
+{
+	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
+	return !version.empty();
+}
+
+void LLPluginClassMedia::stop()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::start(float rate)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
+
+	message.setValueReal("rate", rate);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::pause()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::seek(float time)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
+
+	message.setValueReal("time", time);
+	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setLoop(bool loop)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
+
+	message.setValueBoolean("loop", loop);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setVolume(float volume)
+{
+	if(volume != mRequestedVolume)
+	{
+		mRequestedVolume = volume;
+		
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
+
+		message.setValueReal("volume", volume);
+		
+		sendMessage(message);
+	}
+}
+
+float LLPluginClassMedia::getVolume()
+{
+	return mRequestedVolume;
+}
+
+void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
+{
+	// Send URL history to plugin
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
+	message.setValueLLSD("history", url_history);
+	sendMessage(message);
+
+	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
+}
+
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index f8ed89f644a098297ff7a23f3d3a60e6ee5654f1..e7f303275e92fa1f6632a5465210b25c61f6fd46 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -1,425 +1,425 @@
-/** 
- * @file llpluginclassmedia.h
- * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class.
- *
- * @cond
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#ifndef LL_LLPLUGINCLASSMEDIA_H
-#define LL_LLPLUGINCLASSMEDIA_H
-
-#include "llgltypes.h"
-#include "llpluginprocessparent.h"
-#include "llrect.h"
-#include "llpluginclassmediaowner.h"
-#include <queue>
-#include "v4color.h"
-
-class LLPluginClassMedia : public LLPluginProcessParentOwner
-{
-	LOG_CLASS(LLPluginClassMedia);
-public:
-	LLPluginClassMedia(LLPluginClassMediaOwner *owner);
-	virtual ~LLPluginClassMedia();
-
-	// local initialization, called by the media manager when creating a source
-	virtual bool init(const std::string &launcher_filename, 
-					  const std::string &plugin_dir, 
-					  const std::string &plugin_filename, 
-					  bool debug);
-
-	// undoes everything init() didm called by the media manager when destroying a source
-	virtual void reset();
-	
-	void idle(void);
-	
-	// All of these may return 0 or an actual valid value.
-	// Callers need to check the return for 0, and not use the values in that case.
-	int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; };
-	int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; };
-	int getNaturalWidth() const { return mNaturalMediaWidth; };
-	int getNaturalHeight() const { return mNaturalMediaHeight; };
-	int getSetWidth() const { return mSetMediaWidth; };
-	int getSetHeight() const { return mSetMediaHeight; };
-	int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; };
-	int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; };
-	int getTextureWidth() const;
-	int getTextureHeight() const;
-	int getFullWidth() const { return mFullMediaWidth; };
-	int getFullHeight() const { return mFullMediaHeight; };
-	
-	// This may return NULL.  Callers need to check for and handle this case.
-	unsigned char* getBitsData();
-
-	// gets the format details of the texture data
-	// These may return 0 if they haven't been set up yet.  The caller needs to detect this case.
-	int getTextureDepth() const { return mRequestedTextureDepth; };
-	int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; };
-	int getTextureFormatPrimary() const { return mRequestedTextureFormat; };
-	int getTextureFormatType() const { return mRequestedTextureType; };
-	bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; };
-	bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; };
-
-	void setSize(int width, int height);
-	void setAutoScale(bool auto_scale);
-	
-	void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; };
-	
-	void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; };
-	
-	// Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent.
-	// This will initially be false, and will also be false for some time after setSize while the resize is processed.
-	// Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values
-	// until you call idle() again.
-	bool textureValid(void);
-	
-	bool getDirty(LLRect *dirty_rect = NULL);
-	void resetDirty(void);
-	
-	typedef enum 
-	{
-		MOUSE_EVENT_DOWN,
-		MOUSE_EVENT_UP,
-		MOUSE_EVENT_MOVE,
-		MOUSE_EVENT_DOUBLE_CLICK
-	}EMouseEventType;
-	
-	void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers);
-
-	typedef enum 
-	{
-		KEY_EVENT_DOWN,
-		KEY_EVENT_UP,
-		KEY_EVENT_REPEAT
-	}EKeyEventType;
-	
-	bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data);
-
-	void scrollEvent(int x, int y, MASK modifiers);
-
-	// Javascript <-> viewer events
-	void jsEnableObject( bool enable );
-	void jsAgentLocationEvent( double x, double y, double z );
-	void jsAgentGlobalLocationEvent( double x, double y, double z );
-	void jsAgentOrientationEvent( double angle );
-	void jsAgentLanguageEvent( const std::string& language );
-	void jsAgentRegionEvent( const std::string& region_name );
-	void jsAgentMaturityEvent( const std::string& maturity );
-		
-	// Text may be unicode (utf8 encoded)
-	bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
-	
-	void loadURI(const std::string &uri);
-	
-	// "Loading" means uninitialized or any state prior to fully running (processing commands)
-	bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; };
-
-	// "Running" means the steady state -- i.e. processing messages
-	bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; };
-	
-	// "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally)
-	bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; };
-
-	std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); };
-
-	bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; };
-	void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); };
-	
-	// Inherited from LLPluginProcessParentOwner
-	/* virtual */ void receivePluginMessage(const LLPluginMessage &message);
-	/* virtual */ void pluginLaunchFailed();
-	/* virtual */ void pluginDied();
-	
-	
-	typedef enum 
-	{
-		PRIORITY_UNLOADED,	// media plugin isn't even loaded.
-		PRIORITY_STOPPED,	// media is not playing, shouldn't need to update at all.
-		PRIORITY_HIDDEN,	// media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc.
-		PRIORITY_SLIDESHOW,	// media is in the far distance, updates very infrequently
-		PRIORITY_LOW,		// media is in the distance, may be rendered at reduced size
-		PRIORITY_NORMAL,	// normal (default) priority
-		PRIORITY_HIGH		// media has user focus and/or is taking up most of the screen
-	}EPriority;
-
-	static const char* priorityToString(EPriority priority);
-	void setPriority(EPriority priority);
-	void setLowPrioritySizeLimit(int size);
-	
-	F64 getCPUUsage();
-	
-	void sendPickFileResponse(const std::string &file);
-
-	void sendAuthResponse(bool ok, const std::string &username, const std::string &password);
-
-	// Valid after a MEDIA_EVENT_CURSOR_CHANGED event
-	std::string getCursorName() const { return mCursorName; };
-
-	LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; }
-
-	void	cut();
-	bool	canCut() const { return mCanCut; };
-
-	void	copy();
-	bool	canCopy() const { return mCanCopy; };
-
-	void	paste();
-	bool	canPaste() const { return mCanPaste; };
-	
-	// These can be called before init(), and they will be queued and sent before the media init message.
-	void	setUserDataPath(const std::string &user_data_path);
-	void	setLanguageCode(const std::string &language_code);
-	void	setPluginsEnabled(const bool enabled);
-	void	setJavascriptEnabled(const bool enabled);
-	void	setTarget(const std::string &target);
-	
-	///////////////////////////////////
-	// media browser class functions
-	bool pluginSupportsMediaBrowser(void);
-	
-	void focus(bool focused);
-	void clear_cache();
-	void clear_cookies();
-	void set_cookies(const std::string &cookies);
-	void enable_cookies(bool enable);
-	void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0);
-	void browse_stop();
-	void browse_reload(bool ignore_cache = false);
-	void browse_forward();
-	void browse_back();
-	void setBrowserUserAgent(const std::string& user_agent);
-	void proxyWindowOpened(const std::string &target, const std::string &uuid);
-	void proxyWindowClosed(const std::string &uuid);
-	void ignore_ssl_cert_errors(bool ignore);
-	void addCertificateFilePath(const std::string& path);
-	
-	// This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE
-	std::string	getNavigateURI() const { return mNavigateURI; };
-
-	// These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE
-	S32			getNavigateResultCode() const { return mNavigateResultCode; };
-	std::string getNavigateResultString() const { return mNavigateResultString; };
-	bool		getHistoryBackAvailable() const { return mHistoryBackAvailable; };
-	bool		getHistoryForwardAvailable() const { return mHistoryForwardAvailable; };
-
-	// This is valid after MEDIA_EVENT_PROGRESS_UPDATED
-	int			getProgressPercent() const { return mProgressPercent; };
-	
-	// This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED
-	std::string getStatusText() const { return mStatusText; };
-	
-	// This is valid after MEDIA_EVENT_LOCATION_CHANGED
-	std::string getLocation() const { return mLocation; };
-	
-	// This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW
-	std::string getClickURL() const { return mClickURL; };
-
-	// This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW
-	std::string getClickNavType() const { return mClickNavType; };
-
-	// This is valid after MEDIA_EVENT_CLICK_LINK_HREF
-	std::string getClickTarget() const { return mClickTarget; };
-
-	// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
-	std::string getClickUUID() const { return mClickUUID; };
-
-	// This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE
-	S32 getStatusCode() const { return mStatusCode; };
-	
-	// These are valid during MEDIA_EVENT_GEOMETRY_CHANGE
-	S32 getGeometryX() const { return mGeometryX; };
-	S32 getGeometryY() const { return mGeometryY; };
-	S32 getGeometryWidth() const { return mGeometryWidth; };
-	S32 getGeometryHeight() const { return mGeometryHeight; };
-	
-	// These are valid during MEDIA_EVENT_AUTH_REQUEST
-	std::string	getAuthURL() const { return mAuthURL; };
-	std::string	getAuthRealm() const { return mAuthRealm; };
-
-	// These are valid during MEDIA_EVENT_LINK_HOVERED
-	std::string	getHoverText() const { return mHoverText; };
-	std::string	getHoverLink() const { return mHoverLink; };
-	
-	std::string getMediaName() const { return mMediaName; };
-	std::string getMediaDescription() const { return mMediaDescription; };
-
-	// Crash the plugin.  If you use this outside of a testbed, you will be punished.
-	void		crashPlugin();
-	
-	// Hang the plugin.  If you use this outside of a testbed, you will be punished.
-	void		hangPlugin();
-
-	///////////////////////////////////
-	// media time class functions
-	bool pluginSupportsMediaTime(void);
-	void stop();
-	void start(float rate = 0.0f);
-	void pause();
-	void seek(float time);
-	void setLoop(bool loop);
-	void setVolume(float volume);
-	float getVolume();
-	
-	F64 getCurrentTime(void) const { return mCurrentTime; };
-	F64 getDuration(void) const { return mDuration; };
-	F64 getCurrentPlayRate(void) { return mCurrentRate; };
-	F64 getLoadedDuration(void) const { return mLoadedDuration; };
-	
-	// Initialize the URL history of the plugin by sending
-	// "init_history" message 
-	void initializeUrlHistory(const LLSD& url_history);
-
-protected:
-
-	LLPluginClassMediaOwner *mOwner;
-
-	// Notify this object's owner that an event has occurred.
-	void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event);
-		
-	void sendMessage(const LLPluginMessage &message);  // Send message internally, either queueing or sending directly.
-	std::queue<LLPluginMessage> mSendQueue;		// Used to queue messages while the plugin initializes.
-	
-	void setSizeInternal(void);
-
-	bool		mTextureParamsReceived;		// the mRequestedTexture* fields are only valid when this is true
-	S32 		mRequestedTextureDepth;
-	LLGLenum	mRequestedTextureInternalFormat;
-	LLGLenum	mRequestedTextureFormat;
-	LLGLenum	mRequestedTextureType;
-	bool		mRequestedTextureSwapBytes;
-	bool		mRequestedTextureCoordsOpenGL;
-	
-	std::string mTextureSharedMemoryName;
-	size_t		mTextureSharedMemorySize;
-	
-	// True to scale requested media up to the full size of the texture (i.e. next power of two)
-	bool		mAutoScaleMedia;
-
-	// default media size for the plugin, from the texture_params message.
-	int			mDefaultMediaWidth;
-	int			mDefaultMediaHeight;
-
-	// Size that has been requested by the plugin itself
-	int			mNaturalMediaWidth;
-	int			mNaturalMediaHeight;
-
-	// Size that has been requested with setSize()
-	int			mSetMediaWidth;
-	int			mSetMediaHeight;
-	
-	// Full calculated media size (before auto-scale and downsample calculations)
-	int			mFullMediaWidth;
-	int			mFullMediaHeight;
-
-	// Actual media size being set (after auto-scale)
-	int			mRequestedMediaWidth;
-	int			mRequestedMediaHeight;
-	
-	// Texture size calculated from actual media size
-	int			mRequestedTextureWidth;
-	int			mRequestedTextureHeight;
-	
-	// Size that the plugin has acknowledged
-	int			mTextureWidth;
-	int			mTextureHeight;
-	int			mMediaWidth;
-	int			mMediaHeight;
-	
-	float		mRequestedVolume;
-	
-	// Priority of this media stream
-	EPriority	mPriority;
-	int			mLowPrioritySizeLimit;
-	
-	bool		mAllowDownsample;
-	int			mPadding;
-	
-	
-	LLPluginProcessParent *mPlugin;
-	
-	LLRect mDirtyRect;
-	
-	std::string translateModifiers(MASK modifiers);
-	
-	std::string mCursorName;
-	int			mLastMouseX;
-	int			mLastMouseY;
-
-	LLPluginClassMediaOwner::EMediaStatus mStatus;
-	
-	F64				mSleepTime;
-
-	bool			mCanCut;
-	bool			mCanCopy;
-	bool			mCanPaste;
-	
-	std::string		mMediaName;
-	std::string		mMediaDescription;
-	
-	LLColor4		mBackgroundColor;
-	
-	std::string		mTarget;
-	
-	/////////////////////////////////////////
-	// media_browser class
-	std::string		mNavigateURI;
-	S32				mNavigateResultCode;
-	std::string		mNavigateResultString;
-	bool			mHistoryBackAvailable;
-	bool			mHistoryForwardAvailable;
-	std::string		mStatusText;
-	int				mProgressPercent;
-	std::string		mLocation;
-	std::string		mClickURL;
-	std::string		mClickNavType;
-	std::string		mClickTarget;
-	std::string		mClickUUID;
-	S32				mGeometryX;
-	S32				mGeometryY;
-	S32				mGeometryWidth;
-	S32				mGeometryHeight;
-	S32				mStatusCode;
-	std::string		mAuthURL;
-	std::string		mAuthRealm;
-	std::string		mHoverText;
-	std::string		mHoverLink;
-	
-	/////////////////////////////////////////
-	// media_time class
-	F64				mCurrentTime;
-	F64				mDuration;
-	F64				mCurrentRate;
-	F64				mLoadedDuration;
-	
-//--------------------------------------
-	//debug use only
-	//
-private:
-	bool  mDeleteOK ;
-public:
-	void setDeleteOK(bool flag) { mDeleteOK = flag ;}
-//--------------------------------------
-};
-
-#endif // LL_LLPLUGINCLASSMEDIA_H
+/** 
+ * @file llpluginclassmedia.h
+ * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class.
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+#ifndef LL_LLPLUGINCLASSMEDIA_H
+#define LL_LLPLUGINCLASSMEDIA_H
+
+#include "llgltypes.h"
+#include "llpluginprocessparent.h"
+#include "llrect.h"
+#include "llpluginclassmediaowner.h"
+#include <queue>
+#include "v4color.h"
+
+class LLPluginClassMedia : public LLPluginProcessParentOwner
+{
+	LOG_CLASS(LLPluginClassMedia);
+public:
+	LLPluginClassMedia(LLPluginClassMediaOwner *owner);
+	virtual ~LLPluginClassMedia();
+
+	// local initialization, called by the media manager when creating a source
+	virtual bool init(const std::string &launcher_filename, 
+					  const std::string &plugin_dir, 
+					  const std::string &plugin_filename, 
+					  bool debug);
+
+	// undoes everything init() didm called by the media manager when destroying a source
+	virtual void reset();
+	
+	void idle(void);
+	
+	// All of these may return 0 or an actual valid value.
+	// Callers need to check the return for 0, and not use the values in that case.
+	int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; };
+	int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; };
+	int getNaturalWidth() const { return mNaturalMediaWidth; };
+	int getNaturalHeight() const { return mNaturalMediaHeight; };
+	int getSetWidth() const { return mSetMediaWidth; };
+	int getSetHeight() const { return mSetMediaHeight; };
+	int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; };
+	int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; };
+	int getTextureWidth() const;
+	int getTextureHeight() const;
+	int getFullWidth() const { return mFullMediaWidth; };
+	int getFullHeight() const { return mFullMediaHeight; };
+	
+	// This may return NULL.  Callers need to check for and handle this case.
+	unsigned char* getBitsData();
+
+	// gets the format details of the texture data
+	// These may return 0 if they haven't been set up yet.  The caller needs to detect this case.
+	int getTextureDepth() const { return mRequestedTextureDepth; };
+	int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; };
+	int getTextureFormatPrimary() const { return mRequestedTextureFormat; };
+	int getTextureFormatType() const { return mRequestedTextureType; };
+	bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; };
+	bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; };
+
+	void setSize(int width, int height);
+	void setAutoScale(bool auto_scale);
+	
+	void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; };
+	
+	void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; };
+	
+	// Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent.
+	// This will initially be false, and will also be false for some time after setSize while the resize is processed.
+	// Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values
+	// until you call idle() again.
+	bool textureValid(void);
+	
+	bool getDirty(LLRect *dirty_rect = NULL);
+	void resetDirty(void);
+	
+	typedef enum 
+	{
+		MOUSE_EVENT_DOWN,
+		MOUSE_EVENT_UP,
+		MOUSE_EVENT_MOVE,
+		MOUSE_EVENT_DOUBLE_CLICK
+	}EMouseEventType;
+	
+	void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers);
+
+	typedef enum 
+	{
+		KEY_EVENT_DOWN,
+		KEY_EVENT_UP,
+		KEY_EVENT_REPEAT
+	}EKeyEventType;
+	
+	bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data);
+
+	void scrollEvent(int x, int y, MASK modifiers);
+
+	// Javascript <-> viewer events
+	void jsEnableObject( bool enable );
+	void jsAgentLocationEvent( double x, double y, double z );
+	void jsAgentGlobalLocationEvent( double x, double y, double z );
+	void jsAgentOrientationEvent( double angle );
+	void jsAgentLanguageEvent( const std::string& language );
+	void jsAgentRegionEvent( const std::string& region_name );
+	void jsAgentMaturityEvent( const std::string& maturity );
+		
+	// Text may be unicode (utf8 encoded)
+	bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
+	
+	void loadURI(const std::string &uri);
+	
+	// "Loading" means uninitialized or any state prior to fully running (processing commands)
+	bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; };
+
+	// "Running" means the steady state -- i.e. processing messages
+	bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; };
+	
+	// "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally)
+	bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; };
+
+	std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); };
+
+	bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; };
+	void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); };
+	
+	// Inherited from LLPluginProcessParentOwner
+	/* virtual */ void receivePluginMessage(const LLPluginMessage &message);
+	/* virtual */ void pluginLaunchFailed();
+	/* virtual */ void pluginDied();
+	
+	
+	typedef enum 
+	{
+		PRIORITY_UNLOADED,	// media plugin isn't even loaded.
+		PRIORITY_STOPPED,	// media is not playing, shouldn't need to update at all.
+		PRIORITY_HIDDEN,	// media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc.
+		PRIORITY_SLIDESHOW,	// media is in the far distance, updates very infrequently
+		PRIORITY_LOW,		// media is in the distance, may be rendered at reduced size
+		PRIORITY_NORMAL,	// normal (default) priority
+		PRIORITY_HIGH		// media has user focus and/or is taking up most of the screen
+	}EPriority;
+
+	static const char* priorityToString(EPriority priority);
+	void setPriority(EPriority priority);
+	void setLowPrioritySizeLimit(int size);
+	
+	F64 getCPUUsage();
+	
+	void sendPickFileResponse(const std::string &file);
+
+	void sendAuthResponse(bool ok, const std::string &username, const std::string &password);
+
+	// Valid after a MEDIA_EVENT_CURSOR_CHANGED event
+	std::string getCursorName() const { return mCursorName; };
+
+	LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; }
+
+	void	cut();
+	bool	canCut() const { return mCanCut; };
+
+	void	copy();
+	bool	canCopy() const { return mCanCopy; };
+
+	void	paste();
+	bool	canPaste() const { return mCanPaste; };
+	
+	// These can be called before init(), and they will be queued and sent before the media init message.
+	void	setUserDataPath(const std::string &user_data_path);
+	void	setLanguageCode(const std::string &language_code);
+	void	setPluginsEnabled(const bool enabled);
+	void	setJavascriptEnabled(const bool enabled);
+	void	setTarget(const std::string &target);
+	
+	///////////////////////////////////
+	// media browser class functions
+	bool pluginSupportsMediaBrowser(void);
+	
+	void focus(bool focused);
+	void clear_cache();
+	void clear_cookies();
+	void set_cookies(const std::string &cookies);
+	void enable_cookies(bool enable);
+	void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0);
+	void browse_stop();
+	void browse_reload(bool ignore_cache = false);
+	void browse_forward();
+	void browse_back();
+	void setBrowserUserAgent(const std::string& user_agent);
+	void proxyWindowOpened(const std::string &target, const std::string &uuid);
+	void proxyWindowClosed(const std::string &uuid);
+	void ignore_ssl_cert_errors(bool ignore);
+	void addCertificateFilePath(const std::string& path);
+	
+	// This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE
+	std::string	getNavigateURI() const { return mNavigateURI; };
+
+	// These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE
+	S32			getNavigateResultCode() const { return mNavigateResultCode; };
+	std::string getNavigateResultString() const { return mNavigateResultString; };
+	bool		getHistoryBackAvailable() const { return mHistoryBackAvailable; };
+	bool		getHistoryForwardAvailable() const { return mHistoryForwardAvailable; };
+
+	// This is valid after MEDIA_EVENT_PROGRESS_UPDATED
+	int			getProgressPercent() const { return mProgressPercent; };
+	
+	// This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED
+	std::string getStatusText() const { return mStatusText; };
+	
+	// This is valid after MEDIA_EVENT_LOCATION_CHANGED
+	std::string getLocation() const { return mLocation; };
+	
+	// This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW
+	std::string getClickURL() const { return mClickURL; };
+
+	// This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW
+	std::string getClickNavType() const { return mClickNavType; };
+
+	// This is valid after MEDIA_EVENT_CLICK_LINK_HREF
+	std::string getClickTarget() const { return mClickTarget; };
+
+	// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
+	std::string getClickUUID() const { return mClickUUID; };
+
+	// This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE
+	S32 getStatusCode() const { return mStatusCode; };
+	
+	// These are valid during MEDIA_EVENT_GEOMETRY_CHANGE
+	S32 getGeometryX() const { return mGeometryX; };
+	S32 getGeometryY() const { return mGeometryY; };
+	S32 getGeometryWidth() const { return mGeometryWidth; };
+	S32 getGeometryHeight() const { return mGeometryHeight; };
+	
+	// These are valid during MEDIA_EVENT_AUTH_REQUEST
+	std::string	getAuthURL() const { return mAuthURL; };
+	std::string	getAuthRealm() const { return mAuthRealm; };
+
+	// These are valid during MEDIA_EVENT_LINK_HOVERED
+	std::string	getHoverText() const { return mHoverText; };
+	std::string	getHoverLink() const { return mHoverLink; };
+	
+	std::string getMediaName() const { return mMediaName; };
+	std::string getMediaDescription() const { return mMediaDescription; };
+
+	// Crash the plugin.  If you use this outside of a testbed, you will be punished.
+	void		crashPlugin();
+	
+	// Hang the plugin.  If you use this outside of a testbed, you will be punished.
+	void		hangPlugin();
+
+	///////////////////////////////////
+	// media time class functions
+	bool pluginSupportsMediaTime(void);
+	void stop();
+	void start(float rate = 0.0f);
+	void pause();
+	void seek(float time);
+	void setLoop(bool loop);
+	void setVolume(float volume);
+	float getVolume();
+	
+	F64 getCurrentTime(void) const { return mCurrentTime; };
+	F64 getDuration(void) const { return mDuration; };
+	F64 getCurrentPlayRate(void) { return mCurrentRate; };
+	F64 getLoadedDuration(void) const { return mLoadedDuration; };
+	
+	// Initialize the URL history of the plugin by sending
+	// "init_history" message 
+	void initializeUrlHistory(const LLSD& url_history);
+
+protected:
+
+	LLPluginClassMediaOwner *mOwner;
+
+	// Notify this object's owner that an event has occurred.
+	void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event);
+		
+	void sendMessage(const LLPluginMessage &message);  // Send message internally, either queueing or sending directly.
+	std::queue<LLPluginMessage> mSendQueue;		// Used to queue messages while the plugin initializes.
+	
+	void setSizeInternal(void);
+
+	bool		mTextureParamsReceived;		// the mRequestedTexture* fields are only valid when this is true
+	S32 		mRequestedTextureDepth;
+	LLGLenum	mRequestedTextureInternalFormat;
+	LLGLenum	mRequestedTextureFormat;
+	LLGLenum	mRequestedTextureType;
+	bool		mRequestedTextureSwapBytes;
+	bool		mRequestedTextureCoordsOpenGL;
+	
+	std::string mTextureSharedMemoryName;
+	size_t		mTextureSharedMemorySize;
+	
+	// True to scale requested media up to the full size of the texture (i.e. next power of two)
+	bool		mAutoScaleMedia;
+
+	// default media size for the plugin, from the texture_params message.
+	int			mDefaultMediaWidth;
+	int			mDefaultMediaHeight;
+
+	// Size that has been requested by the plugin itself
+	int			mNaturalMediaWidth;
+	int			mNaturalMediaHeight;
+
+	// Size that has been requested with setSize()
+	int			mSetMediaWidth;
+	int			mSetMediaHeight;
+	
+	// Full calculated media size (before auto-scale and downsample calculations)
+	int			mFullMediaWidth;
+	int			mFullMediaHeight;
+
+	// Actual media size being set (after auto-scale)
+	int			mRequestedMediaWidth;
+	int			mRequestedMediaHeight;
+	
+	// Texture size calculated from actual media size
+	int			mRequestedTextureWidth;
+	int			mRequestedTextureHeight;
+	
+	// Size that the plugin has acknowledged
+	int			mTextureWidth;
+	int			mTextureHeight;
+	int			mMediaWidth;
+	int			mMediaHeight;
+	
+	float		mRequestedVolume;
+	
+	// Priority of this media stream
+	EPriority	mPriority;
+	int			mLowPrioritySizeLimit;
+	
+	bool		mAllowDownsample;
+	int			mPadding;
+	
+	
+	LLPluginProcessParent *mPlugin;
+	
+	LLRect mDirtyRect;
+	
+	std::string translateModifiers(MASK modifiers);
+	
+	std::string mCursorName;
+	int			mLastMouseX;
+	int			mLastMouseY;
+
+	LLPluginClassMediaOwner::EMediaStatus mStatus;
+	
+	F64				mSleepTime;
+
+	bool			mCanCut;
+	bool			mCanCopy;
+	bool			mCanPaste;
+	
+	std::string		mMediaName;
+	std::string		mMediaDescription;
+	
+	LLColor4		mBackgroundColor;
+	
+	std::string		mTarget;
+	
+	/////////////////////////////////////////
+	// media_browser class
+	std::string		mNavigateURI;
+	S32				mNavigateResultCode;
+	std::string		mNavigateResultString;
+	bool			mHistoryBackAvailable;
+	bool			mHistoryForwardAvailable;
+	std::string		mStatusText;
+	int				mProgressPercent;
+	std::string		mLocation;
+	std::string		mClickURL;
+	std::string		mClickNavType;
+	std::string		mClickTarget;
+	std::string		mClickUUID;
+	S32				mGeometryX;
+	S32				mGeometryY;
+	S32				mGeometryWidth;
+	S32				mGeometryHeight;
+	S32				mStatusCode;
+	std::string		mAuthURL;
+	std::string		mAuthRealm;
+	std::string		mHoverText;
+	std::string		mHoverLink;
+	
+	/////////////////////////////////////////
+	// media_time class
+	F64				mCurrentTime;
+	F64				mDuration;
+	F64				mCurrentRate;
+	F64				mLoadedDuration;
+	
+//--------------------------------------
+	//debug use only
+	//
+private:
+	bool  mDeleteOK ;
+public:
+	void setDeleteOK(bool flag) { mDeleteOK = flag ;}
+//--------------------------------------
+};
+
+#endif // LL_LLPLUGINCLASSMEDIA_H
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 0463d5364bd6af6490e4751bb1995315a75b35dc..434fb7650b54079f8c26f08ea24f9132bbd9e3cc 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -27,6 +27,7 @@
 #include "linden_common.h"
 
 #include "llmodel.h"
+#include "llmemory.h"
 #include "llconvexdecomposition.h"
 #include "llsdserialize.h"
 #include "llvector4a.h"
@@ -71,88 +72,10 @@ LLModel::~LLModel()
 	}
 }
 
-void load_face_from_dom_inputs(LLVolumeFace& face, const domInputLocalOffset_Array& inputs, U32 min_idx, U32 max_idx)
-{
-	for (U32 j = 0; j < inputs.getCount(); ++j)
-	{
-		if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0)
-		{ //found vertex array
-			const domURIFragmentType& uri = inputs[j]->getSource();
-			daeElementRef elem = uri.getElement();
-			domVertices* vertices = (domVertices*) elem.cast();
-
-			domInputLocal_Array& v_inp = vertices->getInput_array();
-			if (inputs[j]->getOffset() != 0)
-			{
-				llerrs << "Vertex array offset MUST be zero." << llendl;
-			}
-
-			for (U32 k = 0; k < v_inp.getCount(); ++k)
-			{
-				if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
-				{
-					const domURIFragmentType& uri = v_inp[k]->getSource();
-					
-					daeElementRef elem = uri.getElement();
-					domSource* src = (domSource*) elem.cast();
-
-					if (src->getTechnique_common()->getAccessor()->getStride() != 3)
-					{
-						llerrs << "Vertex array stride MUST be three." << llendl;
-					}
-
-					domListOfFloats& v = src->getFloat_array()->getValue();
-
-					LLVector4a min;
-					min.set(v[min_idx], v[min_idx+1], v[min_idx+2]);
-					LLVector4a max = min;
-
-					for (U32 j = min_idx; j <= max_idx; ++j)
-					{ //copy vertex array
-						face.mPositions[j-min_idx].set(v[j*3+0], v[j*3+1], v[j*3+2]);
-						update_min_max(min, max, face.mPositions[j-min_idx]);
-					}
-
-					face.mExtents[0] = min;
-					face.mExtents[1] = max;
-				}
-			}
-		}
-
-		if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0)
-		{
-			//found normal array for this triangle list
-			const domURIFragmentType& uri = inputs[j]->getSource();
-			daeElementRef elem = uri.getElement();
-			domSource* src = (domSource*) elem.cast();
-			domListOfFloats& n = src->getFloat_array()->getValue();
-			
-			for (U32 j = min_idx; j <= max_idx; ++j)
-			{
-				LLVector4a* norm = (LLVector4a*) face.mNormals + (j-min_idx);
-				norm->set(n[j*3+0], n[j*3+1], n[j*3+2]);
-				norm->normalize3();
-			}
-		}
-		else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0)
-		{ //found texCoords
-			const domURIFragmentType& uri = inputs[j]->getSource();
-			daeElementRef elem = uri.getElement();
-			domSource* src = (domSource*) elem.cast();
-			domListOfFloats& u = src->getFloat_array()->getValue();
-			
-			for (U32 j = min_idx; j <= max_idx; ++j)
-			{
-				face.mTexCoords[j-min_idx].setVec(u[j*2+0], u[j*2+1]);
-			}
-		}
-	}
-}
 
 bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride,
 					 domSource* &pos_source, domSource* &tc_source, domSource* &norm_source)
 {
-	
 	idx_stride = 0;
 
 	for (U32 j = 0; j < inputs.getCount(); ++j)
@@ -271,14 +194,13 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 			cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0],
 								tc[idx[i+tc_offset]*2+1]);
 		}
-
+		
 		if (norm_source)
 		{
 			cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0],
 								n[idx[i+norm_offset]*3+1],
 								n[idx[i+norm_offset]*3+2]));
 		}
-
 		
 		BOOL found = FALSE;
 			
@@ -329,10 +251,22 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 		{
 			face_list.push_back(face);
 			face_list.rbegin()->fillFromLegacyData(verts, indices);
+			LLVolumeFace& new_face = *face_list.rbegin();
+			if (!norm_source)
+			{
+				ll_aligned_free_16(new_face.mNormals);
+				new_face.mNormals = NULL;
+			}
+
+			if (!tc_source)
+			{
+				ll_aligned_free_16(new_face.mTexCoords);
+				new_face.mTexCoords = NULL;
+			}
+
 			face = LLVolumeFace();
 			point_map.clear();
 		}
-
 	}
 
 	if (!verts.empty())
@@ -348,6 +282,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 		face_list.push_back(face);
 
 		face_list.rbegin()->fillFromLegacyData(verts, indices);
+		LLVolumeFace& new_face = *face_list.rbegin();
+		if (!norm_source)
+		{
+			ll_aligned_free_16(new_face.mNormals);
+			new_face.mNormals = NULL;
+		}
+
+		if (!tc_source)
+		{
+			ll_aligned_free_16(new_face.mTexCoords);
+			new_face.mTexCoords = NULL;
+		}
 	}
 
 	return LLModel::NO_ERRORS ;
@@ -433,14 +379,14 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 				cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0],
 									tc[idx[cur_idx+tc_offset]*2+1]);
 			}
-
+			
 			if (norm_source)
 			{
 				cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0],
 									n[idx[cur_idx+norm_offset]*3+1],
 									n[idx[cur_idx+norm_offset]*3+2]);
 			}
-
+			
 			cur_idx += idx_stride;
 			
 			BOOL found = FALSE;
@@ -524,6 +470,19 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 			{
 				face_list.push_back(face);
 				face_list.rbegin()->fillFromLegacyData(verts, indices);
+				LLVolumeFace& new_face = *face_list.rbegin();
+				if (!norm_source)
+				{
+					ll_aligned_free_16(new_face.mNormals);
+					new_face.mNormals = NULL;
+				}
+
+				if (!tc_source)
+				{
+					ll_aligned_free_16(new_face.mTexCoords);
+					new_face.mTexCoords = NULL;
+				}
+
 				face = LLVolumeFace();
 				verts.clear();
 				indices.clear();
@@ -540,10 +499,23 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 		{
 			material = std::string(poly->getMaterial());
 		}
-		
+	
 		materials.push_back(material);
 		face_list.push_back(face);
 		face_list.rbegin()->fillFromLegacyData(verts, indices);
+
+		LLVolumeFace& new_face = *face_list.rbegin();
+		if (!norm_source)
+		{
+			ll_aligned_free_16(new_face.mNormals);
+			new_face.mNormals = NULL;
+		}
+
+		if (!tc_source)
+		{
+			ll_aligned_free_16(new_face.mTexCoords);
+			new_face.mTexCoords = NULL;
+		}
 	}
 
 	return LLModel::NO_ERRORS ;
@@ -557,7 +529,6 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 
 	const domInputLocalOffset_Array& inputs = poly->getInput_array();
 
-
 	S32 v_offset = -1;
 	S32 n_offset = -1;
 	S32 t_offset = -1;
@@ -662,15 +633,14 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 								n->get(n_idx+1),
 								n->get(n_idx+2));
 			}
-
+			
 			if (t)
 			{
 				U32 t_idx = idx[j*stride+t_offset]*2;
 				vert.mTexCoord.setVec(t->get(t_idx),
 								t->get(t_idx+1));								
 			}
-		
-			
+						
 			verts.push_back(vert);
 		}
 	}
@@ -733,6 +703,19 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 		materials.push_back(material);
 		face_list.push_back(face);
 		face_list.rbegin()->fillFromLegacyData(new_verts, indices);
+
+		LLVolumeFace& new_face = *face_list.rbegin();
+		if (!n)
+		{
+			ll_aligned_free_16(new_face.mNormals);
+			new_face.mNormals = NULL;
+		}
+
+		if (!t)
+		{
+			ll_aligned_free_16(new_face.mTexCoords);
+			new_face.mTexCoords = NULL;
+		}
 	}
 
 	return LLModel::NO_ERRORS ;
@@ -817,9 +800,9 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
 		
 		if (getNumVolumeFaces() > 0)
 		{
-			optimizeVolumeFaces();
 			normalizeVolumeFaces();
-
+			optimizeVolumeFaces();
+			
 			if (getNumVolumeFaces() > 0)
 			{
 				return TRUE;
@@ -853,81 +836,10 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint )
 
 void LLModel::optimizeVolumeFaces()
 {
-#if 0 //VECTORIZE ?
-	for (std::vector<LLVolumeFace>::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); )
-	{
-		std::vector<LLVolumeFace>::iterator cur_iter = iter++;
-		LLVolumeFace& face = *cur_iter;
-
-		for (S32 i = 0; i < (S32) face.mNumIndices; i += 3)
-		{ //remove zero area triangles
-			U16 i0 = face.mIndices[i+0];
-			U16 i1 = face.mIndices[i+1];
-			U16 i2 = face.mIndices[i+2];
-
-			if (i0 == i1 || 
-				i1 == i2 || 
-				i0 == i2)
-			{ //duplicate index in triangle, remove triangle
-				face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3);
-				i -= 3;
-			}
-			else
-			{ 
-				LLVolumeFace::VertexData& v0 = face.mVertices[i0];
-				LLVolumeFace::VertexData& v1 = face.mVertices[i1];
-				LLVolumeFace::VertexData& v2 = face.mVertices[i2];
-
-				if (v0.mPosition == v1.mPosition ||
-					v1.mPosition == v2.mPosition ||
-					v2.mPosition == v0.mPosition)
-				{ //zero area triangle, delete
-					face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3);
-					i-=3;
-				}
-			}
-		}
-
-		//remove unreference vertices
-		std::vector<bool> ref;
-		ref.resize(face.mNumVertices);
-
-		for (U32 i = 0; i < ref.size(); ++i)
-		{
-			ref[i] = false;
-		}
-
-		for (U32 i = 0; i < face.mNumIndices; ++i)
-		{ 
-			ref[face.mIndices[i]] = true;
-		}
-
-		U32 unref_count = 0;
-		for (U32 i = 0; i < ref.size(); ++i)
-		{
-			if (!ref[i])
-			{
-				//vertex is unreferenced
-				face.mVertices.erase(face.mVertices.begin()+(i-unref_count));
-				U16 idx = (U16) (i-unref_count);
-
-				for (U32 j = 0; j < face.mNumIndices; ++j)
-				{ //decrement every index array value greater than idx
-					if (face.mIndices[j] > idx)
-					{
-						--face.mIndices[j];
-					}
-				}
-				++unref_count;
-			}
-		}
-
-		if (face.mVertices.empty() || face.mIndices.empty())
-		{ //face is empty, remove it
-			iter = mVolumeFaces.erase(cur_iter);
-		}
+	for (U32 i = 0; i < getNumVolumeFaces(); ++i)
+	{
+		mVolumeFaces[i].optimize();
 	}
-#endif
 }
 
 // Shrink the model to fit
@@ -962,6 +874,25 @@ void LLModel::normalizeVolumeFaces()
 
 			update_min_max(min, max, face.mExtents[0]);
 			update_min_max(min, max, face.mExtents[1]);
+
+			if (face.mTexCoords)
+			{
+				LLVector2& min_tc = face.mTexCoordExtents[0];
+				LLVector2& max_tc = face.mTexCoordExtents[1];
+
+				min_tc = face.mTexCoords[0];
+				max_tc = face.mTexCoords[0];
+
+				for (U32 j = 1; j < face.mNumVertices; ++j)
+				{
+					update_min_max(min_tc, max_tc, face.mTexCoords[j]);
+				}
+			}
+			else
+			{
+				face.mTexCoordExtents[0].set(0,0);
+				face.mTexCoordExtents[1].set(1,1);
+			}
 		}
 
 		// Now that we have the extents of the model
@@ -1029,8 +960,11 @@ void LLModel::normalizeVolumeFaces()
 			{
 			 	pos[j].add(trans);
 				pos[j].mul(scale);
-				norm[j].mul(inv_scale);
-				norm[j].normalize3();
+				if (norm && !norm[j].equals3(LLVector4a::getZero()))
+				{
+					norm[j].mul(inv_scale);
+					norm[j].normalize3();
+				}
 			}
 		}
 
@@ -1073,8 +1007,26 @@ void LLModel::setVolumeFaceData(
 	face.resizeIndices(num_indices);
 
 	LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
-	LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
-	LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
+	if (norm.get())
+	{
+		LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
+	}
+	else
+	{
+		ll_aligned_free_16(face.mNormals);
+		face.mNormals = NULL;
+	}
+
+	if (tc.get())
+	{
+		LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
+	}
+	else
+	{
+		ll_aligned_free_16(face.mTexCoords);
+		face.mTexCoords = NULL;
+	}
+
 	U32 size = (num_indices*2+0xF)&~0xF;
 	LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size);
 }
@@ -1257,10 +1209,23 @@ void LLModel::generateNormals(F32 angle_cutoff)
 			LLVolumeFace::VertexData v;
 			new_face.mPositions[i] = vol_face.mPositions[idx];
 			new_face.mNormals[i].clear();
-			new_face.mTexCoords[i] = vol_face.mTexCoords[idx];
 			new_face.mIndices[i] = i;
 		}
 
+		if (vol_face.mTexCoords)
+		{
+			for (U32 i = 0; i < vol_face.mNumIndices; i++)
+			{
+				U32 idx = vol_face.mIndices[i];
+				new_face.mTexCoords[i] = vol_face.mTexCoords[idx];
+			}
+		}
+		else
+		{
+			ll_aligned_free_16(new_face.mTexCoords);
+			new_face.mTexCoords = NULL;
+		}
+
 		//generate normals for new face
 		for (U32 i = 0; i < new_face.mNumIndices; i += 3)
 		{ //for each triangle
@@ -1395,7 +1360,8 @@ LLSD LLModel::writeModel(
 	const LLModel::Decomposition& decomp,
 	BOOL upload_skin,
 	BOOL upload_joints,
-	BOOL nowrite)
+	BOOL nowrite,
+	BOOL as_slm)
 {
 	LLSD mdl;
 
@@ -1419,12 +1385,20 @@ LLSD LLModel::writeModel(
 		!decomp.mHull.empty())		
 	{
 		mdl["physics_convex"] = decomp.asLLSD();
-		if (!decomp.mHull.empty())
-		{ //convex decomposition exists, physics mesh will not be used
+		if (!decomp.mHull.empty() && !as_slm)
+		{ //convex decomposition exists, physics mesh will not be used (unless this is an slm file)
 			model[LLModel::LOD_PHYSICS] = NULL;
 		}
 	}
 
+	if (as_slm)
+	{ //save material list names
+		for (U32 i = 0; i < high->mMaterialList.size(); ++i)
+		{
+			mdl["material_list"][i] = high->mMaterialList[i];
+		}
+	}
+
 	for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx)
 	{
 		if (model[idx] && model[idx]->getNumVolumeFaces() > 0)
@@ -1462,13 +1436,19 @@ LLSD LLModel::writeModel(
 				U32 tc_idx = 0;
 			
 				LLVector2* ftc = (LLVector2*) face.mTexCoords;
-				LLVector2 min_tc = ftc[0];
-				LLVector2 max_tc = min_tc;
-	
-				//get texture coordinate domain
-				for (U32 j = 0; j < face.mNumVertices; ++j)
+				LLVector2 min_tc;
+				LLVector2 max_tc;
+
+				if (ftc)
 				{
-					update_min_max(min_tc, max_tc, ftc[j]);
+					min_tc = ftc[0];
+					max_tc = min_tc;
+					
+					//get texture coordinate domain
+					for (U32 j = 0; j < face.mNumVertices; ++j)
+					{
+						update_min_max(min_tc, max_tc, ftc[j]);
+					}
 				}
 
 				LLVector2 tc_range = max_tc - min_tc;
@@ -1477,9 +1457,8 @@ LLSD LLModel::writeModel(
 				{ //for each vert
 		
 					F32* pos = face.mPositions[j].getF32ptr();
-					F32* norm = face.mNormals[j].getF32ptr();
-
-					//position + normal
+										
+					//position
 					for (U32 k = 0; k < 3; ++k)
 					{ //for each component
 						//convert to 16-bit normalized across domain
@@ -1489,29 +1468,40 @@ LLSD LLModel::writeModel(
 						//write to binary buffer
 						verts[vert_idx++] = buff[0];
 						verts[vert_idx++] = buff[1];
-						
-						//convert to 16-bit normalized
-						val = (U16) ((norm[k]+1.f)*0.5f*65535);
-
-						//write to binary buffer
-						normals[norm_idx++] = buff[0];
-						normals[norm_idx++] = buff[1];
 					}
 
-					F32* src_tc = (F32*) face.mTexCoords[j].mV;
+					if (face.mNormals)
+					{ //normals
+						F32* norm = face.mNormals[j].getF32ptr();
 
-					//texcoord
-					for (U32 k = 0; k < 2; ++k)
-					{ //for each component
-						//convert to 16-bit normalized
-						U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535);
+						for (U32 k = 0; k < 3; ++k)
+						{ //for each component
+							//convert to 16-bit normalized
+							U16 val = (U16) ((norm[k]+1.f)*0.5f*65535);
+							U8* buff = (U8*) &val;
 
-						U8* buff = (U8*) &val;
-						//write to binary buffer
-						tc[tc_idx++] = buff[0];
-						tc[tc_idx++] = buff[1];
+							//write to binary buffer
+							normals[norm_idx++] = buff[0];
+							normals[norm_idx++] = buff[1];
+						}
 					}
 					
+					F32* src_tc = (F32*) face.mTexCoords[j].mV;
+
+					//texcoord
+					if (face.mTexCoords)
+					{
+						for (U32 k = 0; k < 2; ++k)
+						{ //for each component
+							//convert to 16-bit normalized
+							U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535);
+
+							U8* buff = (U8*) &val;
+							//write to binary buffer
+							tc[tc_idx++] = buff[0];
+							tc[tc_idx++] = buff[1];
+						}
+					}
 				}
 
 				U32 idx_idx = 0;
@@ -1525,12 +1515,20 @@ LLSD LLModel::writeModel(
 				//write out face data
 				mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue();
 				mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue();
-				mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue();
-				mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
-
 				mdl[model_names[idx]][i]["Position"] = verts;
-				mdl[model_names[idx]][i]["Normal"] = normals;
-				mdl[model_names[idx]][i]["TexCoord0"] = tc;
+				
+				if (face.mNormals)
+				{
+					mdl[model_names[idx]][i]["Normal"] = normals;
+				}
+
+				if (face.mTexCoords)
+				{
+					mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue();
+					mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
+					mdl[model_names[idx]][i]["TexCoord0"] = tc;
+				}
+
 				mdl[model_names[idx]][i]["TriangleList"] = indices;
 
 				if (skinning)
@@ -1588,10 +1586,10 @@ LLSD LLModel::writeModel(
 		}
 	}
 	
-	return writeModelToStream(ostr, mdl, nowrite);
+	return writeModelToStream(ostr, mdl, nowrite, as_slm);
 }
 
-LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
+LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BOOL as_slm)
 {
 	U32 bytes = 0;
 	
@@ -1599,6 +1597,11 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
 
 	LLSD header;
 
+	if (as_slm && mdl.has("material_list"))
+	{ //save material binding names to header
+		header["material_list"] = mdl["material_list"];
+	}
+
 	std::string skin;
 
 	if (mdl.has("skin"))
@@ -1792,6 +1795,15 @@ bool LLModel::loadModel(std::istream& is)
 		}
 	}
 	
+	if (header.has("material_list"))
+	{ //load material list names
+		mMaterialList.clear();
+		for (U32 i = 0; i < header["material_list"].size(); ++i)
+		{
+			mMaterialList.push_back(header["material_list"][i].asString());
+		}
+	}
+
 	std::string nm[] = 
 	{
 		"lowest_lod",
@@ -1808,6 +1820,7 @@ bool LLModel::loadModel(std::istream& is)
 	if (header[nm[lod]]["offset"].asInteger() == -1 || 
 		header[nm[lod]]["size"].asInteger() == 0 )
 	{ //cannot load requested LOD
+		llwarns << "LoD data is invalid!" << llendl;
 		return false;
 	}
 
@@ -1821,7 +1834,7 @@ bool LLModel::loadModel(std::istream& is)
 		is.seekg(cur_pos);
 	}
 
-	if (lod == LLModel::LOD_PHYSICS)
+	if (lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS)
 	{
 		std::ios::pos_type cur_pos = is.tellg();
 		loadDecomposition(header, is);
@@ -1868,11 +1881,66 @@ bool LLModel::loadModel(std::istream& is)
 		}
 		return true;
 	}
+	else
+	{
+		llwarns << "unpackVolumeFaces failed!" << llendl;
+	}
 
 	return false;
 
 }
 
+void LLModel::matchMaterialOrder(LLModel* ref)
+{
+	llassert(ref->mMaterialList.size() == mMaterialList.size());
+
+	std::map<std::string, U32> index_map;
+	
+	//build a map of material slot names to face indexes
+	bool reorder = false;
+	std::set<std::string> base_mat;
+	std::set<std::string> cur_mat;
+
+	for (U32 i = 0; i < mMaterialList.size(); i++)
+	{
+		index_map[ref->mMaterialList[i]] = i;
+		if (!reorder)
+		{ //if any material name does not match reference, we need to reorder
+			reorder = ref->mMaterialList[i] != mMaterialList[i];
+		}
+		base_mat.insert(ref->mMaterialList[i]);
+		cur_mat.insert(mMaterialList[i]);
+	}
+
+
+	if (reorder && 
+		base_mat == cur_mat) //don't reorder if material name sets don't match
+	{
+		std::vector<LLVolumeFace> new_face_list;
+		new_face_list.resize(mVolumeFaces.size());
+
+		std::vector<std::string> new_material_list;
+		new_material_list.resize(mVolumeFaces.size());
+
+		//rebuild face list so materials have the same order 
+		//as the reference model
+		for (U32 i = 0; i < mMaterialList.size(); ++i)
+		{ 
+			U32 ref_idx = index_map[mMaterialList[i]];
+			new_face_list[ref_idx] = mVolumeFaces[i];
+
+			new_material_list[ref_idx] = mMaterialList[i];
+		}
+
+		llassert(new_material_list == ref->mMaterialList);
+		
+		mVolumeFaces = new_face_list;
+	}
+
+	//override material list with reference model ordering
+	mMaterialList = ref->mMaterialList;
+}
+
 
 bool LLModel::loadSkinInfo(LLSD& header, std::istream &is)
 {
@@ -2034,7 +2102,7 @@ LLModel::Decomposition::Decomposition(LLSD& data)
 
 void LLModel::Decomposition::fromLLSD(LLSD& decomp)
 {
-	if (decomp.has("HullList"))
+	if (decomp.has("HullList") && decomp.has("Positions"))
 	{
 		// updated for const-correctness. gcc is picky about this type of thing - Nyx
 		const LLSD::Binary& hulls = decomp["HullList"].asBinary();
@@ -2190,6 +2258,8 @@ LLSD LLModel::Decomposition::asLLSD() const
 	ret["Min"] = min.getValue();
 	ret["Max"] = max.getValue();
 
+	LLVector3 range = max-min;
+
 	if (!hulls.empty())
 	{
 		ret["HullList"] = hulls;
@@ -2199,10 +2269,6 @@ LLSD LLModel::Decomposition::asLLSD() const
 	{
 		LLSD::Binary p(total*3*2);
 
-		LLVector3 min(-0.5f, -0.5f, -0.5f);
-		LLVector3 max(0.5f, 0.5f, 0.5f);
-		LLVector3 range = max-min;
-
 		U32 vert_idx = 0;
 		
 		for (U32 i = 0; i < mHull.size(); ++i)
@@ -2214,12 +2280,10 @@ LLSD LLModel::Decomposition::asLLSD() const
 			for (U32 j = 0; j < mHull[i].size(); ++j)
 			{
 				U64 test = 0;
+				const F32* src = mHull[i][j].mV;
+
 				for (U32 k = 0; k < 3; k++)
 				{
-					F32* src = (F32*) (mHull[i][j].mV);
-
-					llassert(src[k] <= 0.501f && src[k] >= -0.501f);
-
 					//convert to 16-bit normalized across domain
 					U16 val = (U16) (((src[k]-min.mV[k])/range.mV[k])*65535);
 
@@ -2258,19 +2322,17 @@ LLSD LLModel::Decomposition::asLLSD() const
 	{
 		LLSD::Binary p(mBaseHull.size()*3*2);
 
-		LLVector3 min(-0.5f, -0.5f, -0.5f);
-		LLVector3 max(0.5f, 0.5f, 0.5f);
-		LLVector3 range = max-min;
-
 		U32 vert_idx = 0;
 		for (U32 j = 0; j < mBaseHull.size(); ++j)
 		{
+			const F32* v = mBaseHull[j].mV;
+
 			for (U32 k = 0; k < 3; k++)
 			{
-				llassert(mBaseHull[j].mV[k] <= 0.51f && mBaseHull[j].mV[k] >= -0.51f);
+				llassert(v[k] <= 0.51f && v[k] >= -0.51f);
 
 				//convert to 16-bit normalized across domain
-				U16 val = (U16) (((mBaseHull[j].mV[k]-min.mV[k])/range.mV[k])*65535);
+				U16 val = (U16) (((v[k]-min.mV[k])/range.mV[k])*65535);
 
 				U8* buff = (U8*) &val;
 				//write to binary buffer
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index cd9f76fcb740026fd1239bc73f904ac3a4eeed9b..3f58eba07d3c02151a62ac8590c97d44529a2716 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -137,12 +137,13 @@ class LLModel : public LLVolume
 		const LLModel::Decomposition& decomp,
 		BOOL upload_skin,
 		BOOL upload_joints,
-		BOOL nowrite = FALSE);
+		BOOL nowrite = FALSE,
+		BOOL as_slm = FALSE);
 
 	static LLSD writeModelToStream(
 		std::ostream& ostr,
 		LLSD& mdl,
-		BOOL nowrite = FALSE);
+		BOOL nowrite = FALSE, BOOL as_slm = FALSE);
 
 	static LLModel* loadModelFromDomMesh(domMesh* mesh);
 	static std::string getElementLabel(daeElement* element);
@@ -171,6 +172,11 @@ class LLModel : public LLVolume
 	void optimizeVolumeFaces();
 	void offsetMesh( const LLVector3& pivotPoint );
 	void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
+	
+	//reorder face list based on mMaterialList in this and reference so 
+	//order matches that of reference (material ordering touchup)
+	void matchMaterialOrder(LLModel* reference);
+
 	std::vector<std::string> mMaterialList;
 
 	//data used for skin weights
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 76faa1b8c54d5364fe964b15dc68ee2aa53388bd..998016f8f6a4fd56ead0b31df6c703b1804ffa00 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -103,6 +103,8 @@ class LLNetworkData
 		PARAMS_LIGHT    = 0x20,
 		PARAMS_SCULPT   = 0x30,
 		PARAMS_LIGHT_IMAGE = 0x40,
+		PARAMS_RESERVED = 0x50, // Used on server-side
+		PARAMS_MESH     = 0x60,
 	};
 	
 public:
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 1180afa6313758f760a643c10f078e69ba5f8a52..b6a252e8fa82bf5b2f7735e8c278f1d9ef7373eb 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -296,7 +296,8 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
 {
 	U32 count = pos.size();
-	llassert(norm.size() >= pos.size());
+	llassert_always(norm.size() >= pos.size());
+	llassert_always(count > 0) ;
 
 	unbind();
 	
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 349dbc340537bd9d3a559445dc261ccaf4f98d3c..919364be632a6dce3b38ae2f7885770366fe97e5 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -2024,8 +2024,17 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
 		}
 		else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd)
 		{
-			// segment wraps to next line, so just set doc pos to the end of the line
-			pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength());
+			if (getLineNumFromDocIndex(line_iter->mDocIndexEnd - 1) == line_iter->mLineNum)
+			{
+				// if segment wraps to the next line we should step one char back
+				// to compensate for the space char between words
+				// which is removed due to wrapping
+				pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength());
+			}
+			else
+			{
+				pos = llclamp(line_iter->mDocIndexEnd, 0, getLength());
+			}
 			break;
 		}
 		start_x += text_width;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 935dd2e88753810e4f9771b9c000abe9c595f369..6292ee97c8a7b09abde2f4d665a0654ce70f07bd 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -209,6 +209,7 @@ set(viewer_SOURCE_FILES
     llfloatermediasettings.cpp
     llfloatermemleak.cpp
     llfloatermodelpreview.cpp
+    llfloatermodeluploadbase.cpp
     llfloatermodelwizard.cpp
     llfloaternamedesc.cpp
     llfloaternotificationsconsole.cpp
@@ -503,6 +504,7 @@ set(viewer_SOURCE_FILES
     lltranslate.cpp
     lluilistener.cpp
     lluploaddialog.cpp
+    lluploadfloaterobservers.cpp
     llurl.cpp
     llurldispatcher.cpp
     llurldispatcherlistener.cpp
@@ -769,6 +771,7 @@ set(viewer_HEADER_FILES
     llfloatermediasettings.h
     llfloatermemleak.h
     llfloatermodelpreview.h
+    llfloatermodeluploadbase.h
     llfloatermodelwizard.h
     llfloaternamedesc.h
     llfloaternotificationsconsole.h
@@ -1060,6 +1063,7 @@ set(viewer_HEADER_FILES
     lluiconstants.h
     lluilistener.h
     lluploaddialog.h
+    lluploadfloaterobservers.h
     llurl.h
     llurldispatcher.h
     llurldispatcherlistener.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 708bb60fcaf75813292a5d519ca11c01d34f6c80..01842d1037aa87490a7ffd92541ef081bd8310a4 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1805,6 +1805,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>CurlUseMultipleThreads</key>
+  <map>
+    <key>Comment</key>
+    <string>Use background threads for executing curl_multi_perform (requires restart)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
     <key>Cursor3D</key>
     <map>
       <key>Comment</key>
@@ -1937,17 +1948,6 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-  <key>DebugShowUploadCost</key>
-  <map>
-    <key>Comment</key>
-    <string>Show what it would cost to upload assets in current scene</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>Boolean</string>
-    <key>Value</key>
-    <integer>0</integer>
-  </map>
   <key>DebugShowRenderMatrices</key>
   <map>
     <key>Comment</key>
@@ -1981,6 +1981,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>DebugShowUploadCost</key>
+  <map>
+    <key>Comment</key>
+    <string>Show mesh upload cost</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
   <key>DebugShowXUINames</key>
     <map>
       <key>Comment</key>
@@ -4863,7 +4874,7 @@
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
-      <string>http://viewer-login.agni.lindenlab.com/</string>
+      <string/>
     </map>
     <key>LosslessJ2CUpload</key>
     <map>
@@ -5600,7 +5611,7 @@
     <key>Type</key>
     <string>Boolean</string>
     <key>Value</key>
-    <real>0</real>
+    <real>1</real>
   </map>
   <key>MeshImportUseSLM</key>
   <map>
@@ -5611,7 +5622,7 @@
     <key>Type</key>
     <string>Boolean</string>
     <key>Value</key>
-    <real>0</real>
+    <real>1</real>
   </map>
   <key>MeshUploadLogXML</key>
   <map>
@@ -5635,6 +5646,17 @@
     <key>Value</key>
     <real>0</real>
   </map>
+  <key>MeshUploadTimeOut</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum time in seconds for llcurl to execute a mesh uoloading request</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>S32</string>
+    <key>Value</key>
+    <real>600</real>
+  </map>
   <key>MigrateCacheDirectory</key>
     <map>
       <key>Comment</key>
@@ -9183,28 +9205,51 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
-  <key>MeshStreamingCostScaler</key>
+  <key>MeshTriangleBudget</key>
   <map>
     <key>Comment</key>
-    <string>DEBUG</string>
+    <string>Target visible triangle budget to use when estimating streaming cost.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
-    <string>F32</string>
+    <string>U32</string>
     <key>Value</key>
-    <real>2.0</real>
+    <real>250000</real>
   </map>
-  <key>MeshThreadCount</key>
+  <key>MeshMetaDataDiscount</key>
   <map>
     <key>Comment</key>
-    <string>Number of threads to use for loading meshes.</string>
+    <string>Number of bytes to deduct for metadata when determining streaming cost.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>384</real>
+  </map>
+  <key>MeshMinimumByteSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Minimum number of bytes per LoD block when determining streaming cost.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>16</real>
+  </map>
+  <key>MeshBytesPerTriangle</key>
+  <map>
+    <key>Comment</key>
+    <string>Approximation of bytes per triangle to use for determining mesh streaming cost.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
     <string>U32</string>
     <key>Value</key>
-    <integer>8</integer>
+    <real>16</real>
   </map>
+
   <key>MeshMaxConcurrentRequests</key>
   <map>
     <key>Comment</key>
@@ -9436,6 +9481,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>ShowAdvancedBuilderOptions</key>
+    <map>
+      <key>Comment</key>
+      <string>Shows physics and display weight</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>ShowAdvancedGraphicsSettings</key>
     <map>
       <key>Comment</key>
@@ -12579,7 +12635,7 @@
       <key>Type</key>
       <string>S32</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
     <key>WaterGLFogDensityScale</key>
     <map>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 60082f40d691feee85946a50b180123a28c6b45a..d327216a0cbd16e54c9c20e4da40ac5b25a8248a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -270,72 +270,41 @@ void main()
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
 	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
 	
-	calcAtmospherics(pos.xyz, 1.0);
+	vec3 col;
+	float bloom = 0.0;
+	if (diffuse.a < 0.9)
+	{
+		calcAtmospherics(pos.xyz, 1.0);
+	
+		col = atmosAmbient(vec3(0));
+		col += atmosAffectDirectionalLight(max(min(da, 1.0), diffuse.a));
 	
-	vec3 col = atmosAmbient(vec3(0));
-	col += atmosAffectDirectionalLight(max(min(da, 1.0), diffuse.a));
+		col *= diffuse.rgb;
 	
-	col *= diffuse.rgb;
+		if (spec.a > 0.0) // specular reflection
+		{
+			// the old infinite-sky shiny reflection
+			//
+			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+			float sa = dot(refnormpersp, vary_light.xyz);
+			vec3 dumbshiny = vary_SunlitColor*texture2D(lightFunc, vec2(sa, spec.a)).a;
+			
+			// add the two types of shiny together
+			vec3 spec_contrib = dumbshiny * spec.rgb;
+			bloom = dot(spec_contrib, spec_contrib);
+			col += spec_contrib;
+		}
 	
-	if (spec.a > 0.0) // specular reflection
+		col = atmosLighting(col);
+		col = scaleSoftClip(col);
+
+		col = mix(col.rgb, diffuse.rgb, diffuse.a);
+	}
+	else
 	{
-		// the old infinite-sky shiny reflection
-		//
-		vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
-		float sa = dot(refnormpersp, vary_light.xyz);
-		vec3 dumbshiny = vary_SunlitColor*texture2D(lightFunc, vec2(sa, spec.a)).a;
-
-		/*
-		// screen-space cheap fakey reflection map
-		//
-		vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz));
-		depth -= 0.5; // unbias depth
-		// first figure out where we'll make our 2D guess from
-		vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth;
-		// Offset the guess source a little according to a trivial
-		// checkerboard dither function and spec.a.
-		// This is meant to be similar to sampling a blurred version
-		// of the diffuse map.  LOD would be better in that regard.
-		// The goal of the blur is to soften reflections in surfaces
-		// with low shinyness, and also to disguise our lameness.
-		float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0
-		float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5);
-		ref2d += vec2(checkoffset, checkoffset);
-		ref2d += tc.xy; // use as offset from destination
-		// Get attributes from the 2D guess point.
-		// We average two samples of diffuse (not of anything else) per
-		// pixel to try to reduce aliasing some more.
-		vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb +
-				     texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb);
-		float refdepth = texture2DRect(depthMap, ref2d).a;
-		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
-		vec3 refn = texture2DRect(normalMap, ref2d).rgb;
-		refn = normalize(vec3((refn.xy-0.5)*2.0,refn.z)); // unpack norm
-		// figure out how appropriate our guess actually was
-		float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos)));
-		// darken reflections from points which face away from the reflected ray - our guess was a back-face
-		//refapprop *= step(dot(refnorm, refn), 0.0);
-		refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant
-		// get appropriate light strength for guess-point.
-		// reflect light direction to increase the illusion that
-		// these are reflections.
-		vec3 reflight = reflect(lightnorm.xyz, norm.xyz);
-		float reflit = max(dot(refn, reflight.xyz), 0.0);
-		// apply sun color to guess-point, dampen according to inappropriateness of guess
-		float refmod = min(refapprop, reflit);
-		vec3 refprod = vary_SunlitColor * refcol.rgb * refmod;
-		vec3 ssshiny = (refprod * spec.a);
-		ssshiny *= 0.3; // dampen it even more
-		*/
-		vec3 ssshiny = vec3(0,0,0);
-
-		// add the two types of shiny together
-		col += (ssshiny + dumbshiny) * spec.rgb;
+		col = diffuse.rgb;
 	}
-	
-	col = atmosLighting(col);
-	col = scaleSoftClip(col);
-		
+
 	gl_FragColor.rgb = col;
-	gl_FragColor.a = 0.0;
+	gl_FragColor.a = bloom;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl
index 9dfacfb520cd8638b252a2845d3560f5806a4a7e..2cce43e2bfb322c3b7412cacf03149ef24481047 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl
@@ -266,7 +266,7 @@ void main()
 	vec2 tc = vary_fragcoord.xy;
 	ivec2 itc = ivec2(tc);
 
-	vec3 fcol = vec3(0,0,0);
+	vec4 fcol = vec4(0,0,0,0);
 
 	for (int i = 0; i < samples; ++i)
 	{
@@ -280,17 +280,16 @@ void main()
 		float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
 	
 		vec4 diffuse = texelFetch(diffuseRect, itc, i);
-		if (diffuse.a >= 1.0)
-		{
-			fcol += diffuse.rgb;
-		}
-		else
+		vec3 col;
+		float bloom = 0.0;
+
+		if (diffuse.a < 0.9)
 		{
 			vec4 spec = texelFetch(specularRect, itc, i);
 	
 			calcAtmospherics(pos.xyz, 1.0);
 	
-			vec3 col = atmosAmbient(vec3(0));
+			col = atmosAmbient(vec3(0));
 			col += atmosAffectDirectionalLight(max(min(da, 1.0), diffuse.a));
 	
 			col *= diffuse.rgb;
@@ -304,15 +303,22 @@ void main()
 				vec3 dumbshiny = vary_SunlitColor*texture2D(lightFunc, vec2(sa, spec.a)).a;
 
 				// add the two types of shiny together
-				col += dumbshiny * spec.rgb;
+				vec3 spec_contrib = dumbshiny * spec.rgb;
+				bloom = dot(spec_contrib, spec_contrib);
+				col += spec_contrib;
 			}
 
 			col = atmosLighting(col);
 			col = scaleSoftClip(col);
-			fcol += col;
+			col = mix(col, diffuse.rgb, diffuse.a);
 		}
+		else
+		{
+			col = diffuse.rgb;
+		}
+
+		fcol += vec4(col, bloom);
 	}
 				
-	gl_FragColor.rgb = fcol.rgb/samples;
-	gl_FragColor.a = 0.0;
+	gl_FragColor = fcol/samples;
 }
diff --git a/indra/newview/app_settings/shaders/class1/interface/solidcolorF.glsl b/indra/newview/app_settings/shaders/class1/interface/solidcolorF.glsl
index ae943cc438d4a62b87147bd73e16e9692a335f08..5b7cc5757498f2a745fbf4a210fce97b68996007 100644
--- a/indra/newview/app_settings/shaders/class1/interface/solidcolorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/solidcolorF.glsl
@@ -9,7 +9,7 @@ uniform sampler2D tex0;
 
 void main() 
 {
-	float alpha = texture2D(tex0, gl_TexCoord[0].xy).a;
+	float alpha = texture2D(tex0, gl_TexCoord[0].xy).a * gl_Color.a;
 
 	gl_FragColor = vec4(gl_Color.rgb, alpha);
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
index f44a5ce32e5ab4760f27269a464b65a7ee5f9121..5283e80407ff188ba4c692c81c0c0c505eacfbb2 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
@@ -10,8 +10,6 @@
 void calcAtmospherics(vec3 inPositionEye);
 mat4 getObjectSkinnedTransform();
 
-attribute vec4 object_weight;
-
 void main()
 {
 	mat4 mat = getObjectSkinnedTransform();
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
index e5dafa8c789e07ee9069ba1ae34ec30718888004..1db79791de38741a6b2d9e85f957de858f634f91 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
@@ -10,8 +10,6 @@
 void calcAtmospherics(vec3 inPositionEye);
 mat4 getObjectSkinnedTransform();
 
-attribute vec4 object_weight;
-
 void main()
 {
 	//transform vertex
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
index cd655f3bb51cde3cf018f6cfa20cef2f5efa5416..eea41bb4f0d2c70543dc2a7c32d6c964ecb4ec4e 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
@@ -11,8 +11,6 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
 void calcAtmospherics(vec3 inPositionEye);
 mat4 getObjectSkinnedTransform();
 
-attribute vec4 object_weight;
-
 void main()
 {
 	mat4 mat = getObjectSkinnedTransform();
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
index 900448035c44a78a29fde95f33dff7b05852efe8..af92e5e00268a7b8242410914f3601de747adebb 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
@@ -11,8 +11,6 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
 void calcAtmospherics(vec3 inPositionEye);
 mat4 getObjectSkinnedTransform();
 
-attribute vec4 object_weight;
-
 void main()
 {
 	//transform vertex
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 66a1a8515f257bf4fc7fa610edb12afe455d20cb..f0c9b01671fc2dcfbae8b2bc11ffcf7471cab439 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -267,34 +267,49 @@ void main()
 	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
 	
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
-	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
-	
-	vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
-	float scol = max(scol_ambocc.r, diffuse.a); 
-	float ambocc = scol_ambocc.g;
+
+	vec3 col;
+	float bloom = 0.0;
+
+	if (diffuse.a < 0.9)
+	{
+		vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
+		
+		vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+		float scol = max(scol_ambocc.r, diffuse.a); 
+		float ambocc = scol_ambocc.g;
 	
-	calcAtmospherics(pos.xyz, ambocc);
+		calcAtmospherics(pos.xyz, ambocc);
 	
-	vec3 col = atmosAmbient(vec3(0));
-	col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
+		col = atmosAmbient(vec3(0));
+		col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
 	
-	col *= diffuse.rgb;
+		col *= diffuse.rgb;
 	
-	if (spec.a > 0.0) // specular reflection
+		if (spec.a > 0.0) // specular reflection
+		{
+			// the old infinite-sky shiny reflection
+			//
+			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+			float sa = dot(refnormpersp, vary_light.xyz);
+			vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+			// add the two types of shiny together
+			vec3 spec_contrib = dumbshiny * spec.rgb;
+			bloom = dot(spec_contrib, spec_contrib);
+			col += spec_contrib;
+		}
+			
+		col = atmosLighting(col);
+		col = scaleSoftClip(col);
+
+		col = mix(col, diffuse.rgb, diffuse.a);
+	}
+	else
 	{
-		// the old infinite-sky shiny reflection
-		//
-		vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
-		float sa = dot(refnormpersp, vary_light.xyz);
-		vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
-
-		// add the two types of shiny together
-		col += dumbshiny * spec.rgb;
+		col = diffuse.rgb;
 	}
-	
-	col = atmosLighting(col);
-	col = scaleSoftClip(col);
 		
 	gl_FragColor.rgb = col;
-	gl_FragColor.a = 0.0;
+	gl_FragColor.a = bloom;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl
index 0bae10ca7d218a844f7fd4562548a6cb9881fb0d..3b572320c3298fee827b083bd40dbdb19e77bef7 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl
@@ -255,7 +255,7 @@ void main()
 	vec2 tc = vary_fragcoord.xy;
 	ivec2 itc = ivec2(tc);
 
-	vec3 fcol = vec3(0,0,0);
+	vec4 fcol = vec4(0,0,0,0);
 
 	vec2 scol_ambocc = texture2DRect(lightMap, tc).rg;
 	float ambocc = scol_ambocc.g;
@@ -270,38 +270,50 @@ void main()
 		float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
 	
 		vec4 diffuse = texelFetch(diffuseRect, itc, i);
-		vec4 spec = texelFetch(specularRect, itc, i);
+		vec3 col;
+		float bloom = 0.0;
+		if (diffuse.a < 0.9)
+		{
+			vec4 spec = texelFetch(specularRect, itc, i);
 	
-		float amb = 0;
+			float amb = 0;
 
-		float scol = max(scol_ambocc.r, diffuse.a); 
-		amb += ambocc;
+			float scol = max(scol_ambocc.r, diffuse.a); 
+			amb += ambocc;
 
-		calcAtmospherics(pos.xyz, ambocc);
+			calcAtmospherics(pos.xyz, ambocc);
+	
+			col = atmosAmbient(vec3(0));
+			col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
 	
-		vec3 col = atmosAmbient(vec3(0));
-		col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
+			col *= diffuse.rgb;
 	
-		col *= diffuse.rgb;
+			if (spec.a > 0.0) // specular reflection
+			{
+				// the old infinite-sky shiny reflection
+				//
+				vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+				float sa = dot(refnormpersp, vary_light.xyz);
+				vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+				// add the two types of shiny together
+				vec3 spec_contrib = dumbshiny * spec.rgb;
+				bloom = dot(spec_contrib, spec_contrib);
+				col += spec_contrib;
+			}
 	
-		if (spec.a > 0.0) // specular reflection
+			col = atmosLighting(col);
+			col = scaleSoftClip(col);
+
+			col = mix(col, diffuse.rgb, diffuse.a);
+		}
+		else
 		{
-			// the old infinite-sky shiny reflection
-			//
-			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
-			float sa = dot(refnormpersp, vary_light.xyz);
-			vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
-
-			// add the two types of shiny together
-			col += dumbshiny * spec.rgb;
+			col = diffuse.rgb;
 		}
-	
-		col = atmosLighting(col);
-		col = scaleSoftClip(col);
 
-		fcol += col;
+		fcol += vec4(col, bloom);
 	}
 		
-	gl_FragColor.rgb = fcol/samples; 
-	gl_FragColor.a = 0.0;
+	gl_FragColor = fcol/samples; 
 }
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index d38d33cc2193cd64280e863bdd958d8beb595954..1ae10a5faaea8f78a964e073161ead5dd9a28e27 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -268,91 +268,50 @@ void main()
 	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
 	
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
-	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
+	vec3 col;
+	float bloom = 0.0;
+
+	if (diffuse.a < 0.9)
+	{
+		vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
 	
-	da = texture2D(lightFunc, vec2(da, 0.0)).a;
+		da = texture2D(lightFunc, vec2(da, 0.0)).a;
 		
-	vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
-	float scol = max(scol_ambocc.r, diffuse.a); 
-	float ambocc = scol_ambocc.g;
+		vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+		float scol = max(scol_ambocc.r, diffuse.a); 
+		float ambocc = scol_ambocc.g;
 	
-	calcAtmospherics(pos.xyz, ambocc);
+		calcAtmospherics(pos.xyz, ambocc);
 	
-	vec3 col = atmosAmbient(vec3(0));
-	col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
+		col = atmosAmbient(vec3(0));
+		col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
 	
-	col *= diffuse.rgb;
+		col *= diffuse.rgb;
 	
-	if (spec.a > 0.0) // specular reflection
+		if (spec.a > 0.0) // specular reflection
+		{
+			// the old infinite-sky shiny reflection
+			//
+			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+			float sa = dot(refnormpersp, vary_light.xyz);
+			vec3 dumbshiny = vary_SunlitColor*scol*texture2D(lightFunc, vec2(sa, spec.a)).a;
+		
+			// add the two types of shiny together
+			vec3 spec_contrib = dumbshiny * spec.rgb;
+			bloom = dot(spec_contrib, spec_contrib);
+			col += spec_contrib;		
+		}
+	
+		col = atmosLighting(col);
+		col = scaleSoftClip(col);
+
+		col = mix(col, diffuse.rgb, diffuse.a);
+	}
+	else
 	{
-		// the old infinite-sky shiny reflection
-		//
-		vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
-		float sa = dot(refnormpersp, vary_light.xyz);
-		vec3 dumbshiny = vary_SunlitColor*scol*texture2D(lightFunc, vec2(sa, spec.a)).a;
-
-		/*
-		// screen-space cheap fakey reflection map
-		//
-		vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz));
-		depth -= 0.5; // unbias depth
-		// first figure out where we'll make our 2D guess from
-		vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth;
-		// Offset the guess source a little according to a trivial
-		// checkerboard dither function and spec.a.
-		// This is meant to be similar to sampling a blurred version
-		// of the diffuse map.  LOD would be better in that regard.
-		// The goal of the blur is to soften reflections in surfaces
-		// with low shinyness, and also to disguise our lameness.
-		float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0
-		float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5);
-
-		ref2d += vec2(checkoffset, checkoffset);
-		ref2d += tc.xy; // use as offset from destination
-		// Get attributes from the 2D guess point.
-		// We average two samples of diffuse (not of anything else) per
-		// pixel to try to reduce aliasing some more.
-		vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb +
-				     texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb);
-		float refdepth = texture2DRect(depthMap, ref2d).a;
-		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
-		float refshad = texture2DRect(lightMap, ref2d).r;
-		vec3 refn = texture2DRect(normalMap, ref2d).rgb;
-		refn = vec3((refn.xy-0.5)*2.0,refn.z); // unpack norm
-		refn = normalize(refn);
-		// figure out how appropriate our guess actually was
-		float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos)));
-		// darken reflections from points which face away from the reflected ray - our guess was a back-face
-		//refapprop *= step(dot(refnorm, refn), 0.0);
-		refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant
-		// get appropriate light strength for guess-point.
-		// reflect light direction to increase the illusion that
-		// these are reflections.
-		vec3 reflight = reflect(lightnorm.xyz, norm.xyz);
-		float reflit = min(max(dot(refn, reflight.xyz), 0.0), refshad);
-		// apply sun color to guess-point, dampen according to inappropriateness of guess
-		float refmod = min(refapprop, reflit);
-		vec3 refprod = vary_SunlitColor * refcol.rgb * refmod;
-		vec3 ssshiny = (refprod * spec.a);
-		ssshiny *= 0.3; // dampen it even more
-		*/
-		vec3 ssshiny = vec3(0,0,0);
-
-		// add the two types of shiny together
-		col += (ssshiny + dumbshiny) * spec.rgb;
+		col = diffuse.rgb;
 	}
-	
-	col = atmosLighting(col);
-	col = scaleSoftClip(col);
 		
 	gl_FragColor.rgb = col;
-	
-	//gl_FragColor.rgb = gi_col.rgb;
-	gl_FragColor.a = 0.0;
-	
-	//gl_FragColor.rg = scol_ambocc.rg;
-	//gl_FragColor.rgb = texture2DRect(lightMap, vary_fragcoord.xy).rgb;
-	//gl_FragColor.rgb = norm.rgb*0.5+0.5;
-	//gl_FragColor.rgb = vec3(ambocc);
-	//gl_FragColor.rgb = vec3(scol);
+	gl_FragColor.a = bloom;
 }
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index fa67ee547c6daaf21d97b5a9faf1788bf77c2044..2690e8ec70800fd76b3c8583af315d2f7bbc72f1 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 29
+version 30
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 492cfe7c1ba8cde93ca0be2c85d29a8a76030e4b..642a1907f0078f10a7ae7f3eb317a90e1b792150 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -3356,8 +3356,8 @@ bool LLAgent::teleportCore(bool is_local)
 	// hide the Region/Estate floater
 	LLFloaterReg::hideInstance("region_info");
 
-	// hide the search floater (EXT-8276)
-	LLFloaterReg::hideInstance("search");
+	// minimize the Search floater (STORM-1474)
+	LLFloaterReg::getInstance("search")->setMinimized(TRUE);
 
 	LLViewerParcelMgr::getInstance()->deselectLand();
 	LLViewerMediaFocus::getInstance()->clearFocus();
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index c30d3b9aa3e5e92a2376176c2d3e48d8ef985342..f195c985c08cb825a59040d9f0b737049cf258c6 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -393,8 +393,6 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi
 	
 	LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation
 	LLVector3 object_extents = object->getScale();	
-	const LLVector4a* oe4 = object->mDrawable->getSpatialExtents();
-	object_extents.set( oe4[1][0], oe4[1][1], oe4[1][2] );
 	
 	// make sure they object extents are non-zero
 	object_extents.clamp(0.001f, F32_MAX);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index b65933f8a1d1866c3f953bf038031453df713d45..d12b971bde9c174be71bfff66a56efe9904fd3c9 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -708,7 +708,7 @@ bool LLAppViewer::init()
 
     // *NOTE:Mani - LLCurl::initClass is not thread safe. 
     // Called before threads are created.
-    LLCurl::initClass();
+    LLCurl::initClass(gSavedSettings.getBOOL("CurlUseMultipleThreads"));
 	LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ;
 
     LLMachineID::init();
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index 5b9a449be15bd7a02f12c314e27b2b0a062fa309..966f5b941e0adfcbbd22b074eb420223dc1b23e8 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -127,6 +127,15 @@ void on_new_single_inventory_upload_complete(
 			group_perms,
 			next_owner_perms);
 
+		U32 inventory_item_flags = 0;
+		if (server_response.has("inventory_flags"))
+		{
+			inventory_item_flags = (U32) server_response["inventory_flags"].asInteger();
+			if (inventory_item_flags != 0)
+			{
+				llinfos << "inventory_item_flags " << inventory_item_flags << llendl;
+			}
+		}
 		S32 creation_date_now = time_corrected();
 		LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
 			server_response["new_inventory_item"].asUUID(),
@@ -138,7 +147,7 @@ void on_new_single_inventory_upload_complete(
 			item_name,
 			item_description,
 			LLSaleInfo::DEFAULT,
-			LLInventoryItemFlags::II_FLAGS_NONE,
+			inventory_item_flags,
 			creation_date_now);
 
 		gInventory.updateItem(item);
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index f9fd50107230cd6e34008dfea1c4dad6fd420a4c..a219386b530c02fc109fd4169949f1060a3fc0a9 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -62,13 +62,24 @@ LLDrawPoolWLSky::LLDrawPoolWLSky(void) :
 		llerrs << "Error: Failed to load cloud noise image " << cloudNoiseFilename << llendl;
 	}
 
-	cloudNoiseFile->load(cloudNoiseFilename);
-
-	sCloudNoiseRawImage = new LLImageRaw();
+	if(cloudNoiseFile->load(cloudNoiseFilename))
+	{
+		sCloudNoiseRawImage = new LLImageRaw();
 
-	cloudNoiseFile->decode(sCloudNoiseRawImage, 0.0f);
+		if(cloudNoiseFile->decode(sCloudNoiseRawImage, 0.0f))
+		{
+			//debug use			
+			lldebugs << "cloud noise raw image width: " << sCloudNoiseRawImage->getWidth() << " : height: " << sCloudNoiseRawImage->getHeight() << " : components: " << 
+				(S32)sCloudNoiseRawImage->getComponents() << " : data size: " << sCloudNoiseRawImage->getDataSize() << llendl ;
+			llassert_always(sCloudNoiseRawImage->getData()) ;
 
-	sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
+			sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
+		}
+		else
+		{
+			sCloudNoiseRawImage = NULL ;
+		}
+	}
 
 	LLWLParamManager::getInstance()->propagateParameters();
 }
@@ -218,7 +229,7 @@ void LLDrawPoolWLSky::renderStars(void) const
 
 void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const
 {
-	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))
+	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS) && sCloudNoiseTexture.notNull())
 	{
 		LLGLEnable blend(GL_BLEND);
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
@@ -399,5 +410,8 @@ void LLDrawPoolWLSky::cleanupGL()
 //static
 void LLDrawPoolWLSky::restoreGL()
 {
-	sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
+	if(sCloudNoiseRawImage.notNull())
+	{
+		sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
+	}
 }
diff --git a/indra/newview/llenvmanager.cpp b/indra/newview/llenvmanager.cpp
index c2720eaf28e884108474d9b2313ff4bed64016b8..86fe6754dc8d652217d50bc6226552d440d06d22 100644
--- a/indra/newview/llenvmanager.cpp
+++ b/indra/newview/llenvmanager.cpp
@@ -2,31 +2,25 @@
  * @file llenvmanager.cpp
  * @brief Implementation of classes managing WindLight and water settings.
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * 
- * Copyright (c) 2009, Linden Research, Inc.
- * 
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
  * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/llenvmanager.h b/indra/newview/llenvmanager.h
index 96af102c1a6b989d104cc91d8ce2df3b60d47046..ad56761bc772e2a5c4921fd63667e629503c6d7c 100644
--- a/indra/newview/llenvmanager.h
+++ b/indra/newview/llenvmanager.h
@@ -2,31 +2,25 @@
  * @file llenvmanager.h
  * @brief Declaration of classes managing WindLight and water settings.
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * 
- * Copyright (c) 2009, Linden Research, Inc.
- * 
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
  * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp
index 5501b8c2ac24639da7e1b1a55fe84b992e9e57f8..2abfbf37ca9c3e347cfdd792b52902ac33d6c403 100644
--- a/indra/newview/llexpandabletextbox.cpp
+++ b/indra/newview/llexpandabletextbox.cpp
@@ -415,6 +415,15 @@ void LLExpandableTextBox::onTopLost()
 	LLUICtrl::onTopLost();
 }
 
+void LLExpandableTextBox::updateTextShape()
+{
+	// I guess this should be done on every reshape(),
+	// but adding this code to reshape() currently triggers bug VWR-26455,
+	// which makes the text virtually unreadable.
+	llassert(!mExpanded);
+	updateTextBoxRect();
+}
+
 void LLExpandableTextBox::setValue(const LLSD& value)
 {
 	collapseTextBox();
diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h
index f75ef954ffa6210f9f1cf6bcb8c679dd17f64e76..399e48bea2b0ac2119cc9cd4722371bec233d588 100644
--- a/indra/newview/llexpandabletextbox.h
+++ b/indra/newview/llexpandabletextbox.h
@@ -143,6 +143,10 @@ class LLExpandableTextBox : public LLUICtrl
 	 */
 	/*virtual*/ void onTopLost();
 
+	/**
+	 * *HACK: Update the inner textbox shape.
+	 */
+	void updateTextShape();
 
 	/**
 	 * Draws text box, collapses text box if its expanded and its parent's position changed
diff --git a/indra/newview/llfloaterbuildoptions.cpp b/indra/newview/llfloaterbuildoptions.cpp
index 4b6fe4a1157847a528f402e482041074361b8f80..86c1bf0534ed1b4eabe37a0c5cc8accf95a81d9d 100644
--- a/indra/newview/llfloaterbuildoptions.cpp
+++ b/indra/newview/llfloaterbuildoptions.cpp
@@ -34,15 +34,81 @@
 #include "llfloaterbuildoptions.h"
 #include "lluictrlfactory.h"
 
+#include "llcombobox.h"
+#include "llselectmgr.h"
+
 //
 // Methods
 //
+
+void commit_grid_mode(LLUICtrl *);
+
 LLFloaterBuildOptions::LLFloaterBuildOptions(const LLSD& key)
-  : LLFloater(key)
+  : LLFloater(key),
+    mComboGridMode(NULL)
 {
+	mCommitCallbackRegistrar.add("GridOptions.gridMode", boost::bind(&commit_grid_mode,_1));
 }
 
 LLFloaterBuildOptions::~LLFloaterBuildOptions()
+{}
+
+BOOL LLFloaterBuildOptions::postBuild()
+{
+	mComboGridMode = getChild<LLComboBox>("combobox grid mode");
+
+	return TRUE;
+}
+
+void LLFloaterBuildOptions::setGridMode(EGridMode mode)
+{
+	mComboGridMode->setCurrentByIndex((S32)mode);
+}
+
+void LLFloaterBuildOptions::updateGridMode()
 {
+	if (mComboGridMode)
+	{
+		S32 index = mComboGridMode->getCurrentIndex();
+		mComboGridMode->removeall();
+
+		switch (mObjectSelection->getSelectType())
+		{
+		case SELECT_TYPE_HUD:
+		  mComboGridMode->add(getString("grid_screen_text"));
+		  mComboGridMode->add(getString("grid_local_text"));
+		  break;
+		case SELECT_TYPE_WORLD:
+		  mComboGridMode->add(getString("grid_world_text"));
+		  mComboGridMode->add(getString("grid_local_text"));
+		  mComboGridMode->add(getString("grid_reference_text"));
+		  break;
+		case SELECT_TYPE_ATTACHMENT:
+		  mComboGridMode->add(getString("grid_attachment_text"));
+		  mComboGridMode->add(getString("grid_local_text"));
+		  mComboGridMode->add(getString("grid_reference_text"));
+		  break;
+		}
+
+		mComboGridMode->setCurrentByIndex(index);
+	}
+}
+
+// virtual
+void LLFloaterBuildOptions::onOpen(const LLSD& key)
+{
+	mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
 }
 
+// virtual
+void LLFloaterBuildOptions::onClose(bool app_quitting)
+{
+	mObjectSelection = NULL;
+}
+
+void commit_grid_mode(LLUICtrl *ctrl)
+{
+	LLComboBox* combo = (LLComboBox*)ctrl;
+
+	LLSelectMgr::getInstance()->setGridMode((EGridMode)combo->getCurrentIndex());
+}
diff --git a/indra/newview/llfloaterbuildoptions.h b/indra/newview/llfloaterbuildoptions.h
index 164944d7bcfefc461552ce1a6e553c2ef7673ad9..7f3811bf1cba1f8fe9948fb189a6f37993a7c69b 100644
--- a/indra/newview/llfloaterbuildoptions.h
+++ b/indra/newview/llfloaterbuildoptions.h
@@ -33,15 +33,34 @@
 #define LL_LLFLOATERBUILDOPTIONS_H
 
 #include "llfloater.h"
+#include "llselectmgr.h"
 
+class LLComboBox;
+class LLObjectSelection;
+
+typedef LLSafeHandle<LLObjectSelection> LLObjectSelectionHandle;
 
 class LLFloaterBuildOptions
 	:	public LLFloater
 {
-	friend class LLFloaterReg;
+public:
+
+	virtual BOOL postBuild();
+
+	/*virtual*/ void onOpen(const LLSD& key);
+	/*virtual*/	void onClose(bool app_quitting);
+
+	void setGridMode(EGridMode mode);
+	void updateGridMode();
+
 private:
+
+	friend class LLFloaterReg;
+
 	LLFloaterBuildOptions(const LLSD& key);
 	~LLFloaterBuildOptions();
-};
 
+	LLComboBox*	mComboGridMode;
+	LLObjectSelectionHandle	mObjectSelection;
+};
 #endif
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index 610142b5a9c63bc51825c8f5cff04c3f09e73be7..5cfdd69f7b6cde8e84d1252c44c961d95fad48c5 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -529,7 +529,7 @@ void LLFloaterBuyLandUI::updateCovenantInfo()
 	LLTextBox* region_type = getChild<LLTextBox>("region_type_text");
 	if (region_type)
 	{
-		region_type->setText(region->getSimProductName());
+		region_type->setText(region->getLocalizedSimProductName());
 	}
 	
 	LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause");
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 9b7593ce615bba15ada99a43c20efc5bcd78a9c0..4746f93009295e937f69219028357237e2ae928b 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -566,10 +566,7 @@ void LLPanelLandGeneral::refresh()
 		if (regionp)
 		{
 			insert_maturity_into_textbox(mContentRating, gFloaterView->getParentFloater(this), MATURITY);
-
-			std::string land_type;
-			bool is_land_type_localized = LLTrans::findString(land_type, regionp->getSimProductName());
-			mLandType->setText(is_land_type_localized ? land_type : regionp->getSimProductName());
+			mLandType->setText(regionp->getLocalizedSimProductName());
 		}
 
 		// estate owner/manager cannot edit other parts of the parcel
@@ -2883,13 +2880,7 @@ void LLPanelLandCovenant::refresh()
 	}
 
 	LLTextBox* region_landtype = getChild<LLTextBox>("region_landtype_text");
-	if (region_landtype)
-	{
-		std::string land_type;
-		bool is_land_type_localized = LLTrans::findString(land_type, region->getSimProductName());
-
-		region_landtype->setText(is_land_type_localized ? land_type : region->getSimProductName());
-	}
+	region_landtype->setText(region->getLocalizedSimProductName());
 	
 	LLTextBox* region_maturity = getChild<LLTextBox>("region_maturity_text");
 	if (region_maturity)
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index ab6753b4be31b9f4ea0ab1cfc4c98170f2f7f671..ef846ec42e0a46c2467bd49a8283daedd91cb591 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -71,6 +71,7 @@
 #include "llmatrix4a.h"
 #include "llmenubutton.h"
 #include "llmeshrepository.h"
+#include "llnotificationsutil.h"
 #include "llsdutil_math.h"
 #include "lltextbox.h"
 #include "lltoolmgr.h"
@@ -100,7 +101,12 @@
 #include "llcallbacklist.h"
 #include "llviewerobjectlist.h"
 #include "llanimationstates.h"
+#include "llviewernetwork.h"
 #include "glod/glod.h"
+#include <boost/algorithm/string.hpp>
+
+
+const S32 SLM_SUPPORTED_VERSION = 2;
 
 //static
 S32 LLFloaterModelPreview::sUploadAmount = 10;
@@ -353,13 +359,16 @@ void LLMeshFilePicker::notify(const std::string& filename)
 // LLFloaterModelPreview()
 //-----------------------------------------------------------------------------
 LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) :
-LLFloater(key)
+LLFloaterModelUploadBase(key),
+mUploadBtn(NULL),
+mCalculateBtn(NULL)
 {
 	sInstance = this;
 	mLastMouseX = 0;
 	mLastMouseY = 0;
 	mGLName = 0;
 	mStatusLock = new LLMutex(NULL);
+	mModelPreview = NULL;
 
 	mLODMode[LLModel::LOD_HIGH] = 0;
 	for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
@@ -394,16 +403,17 @@ BOOL LLFloaterModelPreview::postBuild()
 	childSetCommitCallback("border_mode", onLODParamCommit, this);
 	childSetCommitCallback("share_tolerance", onLODParamCommit, this);
 
+	childSetCommitCallback("upload_skin", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
+	childSetCommitCallback("upload_joints", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
+	childSetCommitCallback("upload_textures", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
+
 	childSetTextArg("status", "[STATUS]", getString("status_idle"));
 
-	//childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount));
 	childSetAction("ok_btn", onUpload, this);
 	childDisable("ok_btn");
 
 	childSetAction("reset_btn", onReset, this);
 
-	childSetAction("clear_materials", onClearMaterials, this);
-
 	childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this);
 
 	childSetCommitCallback("upload_skin", onUploadSkinCommit, this);
@@ -422,8 +432,6 @@ BOOL LLFloaterModelPreview::postBuild()
 	
 	childDisable("ok_btn");
 
-	childSetCommitCallback("confirm_checkbox", refresh, this);
-
 	mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn");
 
 	mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2));
@@ -441,9 +449,7 @@ BOOL LLFloaterModelPreview::postBuild()
 
 	mPreviewRect = preview_panel->getRect();
 
-	mModelPreview = new LLModelPreview(512, 512, this );
-	mModelPreview->setPreviewTarget(16.f);
-	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5));
+	initModelPreview();
 
 	//set callbacks for left click on line editor rows
 	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
@@ -472,6 +478,25 @@ BOOL LLFloaterModelPreview::postBuild()
 			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 		}
 	}
+	std::string current_grid = LLGridManager::getInstance()->getGridLabel();
+	std::transform(current_grid.begin(),current_grid.end(),current_grid.begin(),::tolower);
+	std::string validate_url;
+	if (current_grid == "agni")
+	{
+		validate_url = "http://secondlife.com/my/account/mesh.php";
+	}
+	else
+	{
+		validate_url = llformat("http://secondlife.%s.lindenlab.com/my/account/mesh.php",current_grid.c_str());
+	}
+	getChild<LLTextBox>("warning_message")->setTextArg("[VURL]", validate_url);
+
+	mUploadBtn = getChild<LLButton>("ok_btn");
+	mCalculateBtn = getChild<LLButton>("calculate_btn");
+
+	mCalculateBtn->setClickedCallback(boost::bind(&LLFloaterModelPreview::onClickCalculateBtn, this));
+
+	toggleCalculateButton(true);
 
 	return TRUE;
 }
@@ -497,6 +522,19 @@ LLFloaterModelPreview::~LLFloaterModelPreview()
 	mStatusLock = NULL;
 }
 
+void LLFloaterModelPreview::initModelPreview()
+{
+	if (mModelPreview)
+	{
+		delete mModelPreview;
+	}
+
+	mModelPreview = new LLModelPreview(512, 512, this );
+	mModelPreview->setPreviewTarget(16.f);
+	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5));
+	mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1));
+}
+
 void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata)
 {
 	if (mModelPreview)
@@ -544,6 +582,30 @@ void LLFloaterModelPreview::loadModel(S32 lod)
 	(new LLMeshFilePicker(mModelPreview, lod))->getFile();
 }
 
+void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name, bool force_disable_slm)
+{
+	mModelPreview->mLoading = true;
+
+	mModelPreview->loadModel(file_name, lod, force_disable_slm);
+}
+
+void LLFloaterModelPreview::onClickCalculateBtn()
+{
+	mModelPreview->rebuildUploadData();
+
+	bool upload_skinweights = childGetValue("upload_skin").asBoolean();
+	bool upload_joint_positions = childGetValue("upload_joints").asBoolean();
+
+	mUploadModelUrl.clear();
+
+	gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale,
+			childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mUploadModelUrl, false,
+						  getWholeModelFeeObserverHandle());
+
+	toggleCalculateButton(false);
+	mUploadBtn->setEnabled(false);
+}
+
 //static
 void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata)
 {
@@ -554,7 +616,10 @@ void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata)
 		return;
 	}
 
-	fp->mModelPreview->calcResourceCost();
+	fp->mModelPreview->mDirty = true;
+
+	fp->toggleCalculateButton(true);
+
 	fp->mModelPreview->refresh();
 }
 //static
@@ -566,7 +631,11 @@ void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata )
 	{
 		return;
 	}
-	fp->mModelPreview->calcResourceCost();
+
+	fp->mModelPreview->mDirty = true;
+
+	fp->toggleCalculateButton(true);
+
 	fp->mModelPreview->refresh();
 }
 
@@ -615,8 +684,6 @@ void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata)
 	{
 		return;
 	}
-	
-	fp->mModelPreview->calcResourceCost();
 	fp->mModelPreview->refresh();
 	fp->mModelPreview->resetPreviewTarget();
 	fp->mModelPreview->clearBuffers();
@@ -669,6 +736,7 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
 void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata)
 {
 	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+
 	fp->mModelPreview->onLODParamCommit(false);
 }
 
@@ -707,31 +775,11 @@ void LLFloaterModelPreview::draw()
 		}
 	}
 
+	childSetEnabled("ok_btn", mHasUploadPerm && !mUploadModelUrl.empty());
+
 	childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost));
 	childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size()));
 
-	if (!mCurRequest.empty())
-	{
-		LLMutexLock lock(mStatusLock);
-		childSetTextArg("status", "[STATUS]", mStatusMessage);
-	}
-	else
-	{
-		childSetVisible("Simplify", true);
-		childSetVisible("simplify_cancel", false);
-		childSetVisible("Decompose", true);
-		childSetVisible("decompose_cancel", false);
-	}
-	
-	U32 resource_cost = mModelPreview->mResourceCost*10;
-
-	if (childGetValue("upload_textures").asBoolean())
-	{
-		resource_cost += mModelPreview->mTextureSet.size()*10;
-	}
-
-	childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost));
-
 	if (mModelPreview)
 	{
 		gGL.color3f(1.f, 1.f, 1.f);
@@ -864,6 +912,12 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return TRUE;
 }
 
+/*virtual*/
+void LLFloaterModelPreview::onOpen(const LLSD& key)
+{
+	requestAgentUploadPermissions();
+}
+
 //static
 void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
 {
@@ -925,12 +979,14 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data)
 			sInstance->setStatusMessage(sInstance->getString("decomposing"));
 			sInstance->childSetVisible("Decompose", false);
 			sInstance->childSetVisible("decompose_cancel", true);
+			sInstance->childDisable("Simplify");
 		}
 		else if (stage == "Simplify")
 		{
 			sInstance->setStatusMessage(sInstance->getString("simplifying"));
 			sInstance->childSetVisible("Simplify", false);
 			sInstance->childSetVisible("simplify_cancel", true);
+			sInstance->childDisable("Decompose");
 		}
 	}
 }
@@ -1883,8 +1939,11 @@ bool LLModelLoader::doLoadModel()
 								mesh_scale *= transformation;
 								transformation = mesh_scale;
 								
-								std::vector<LLImportMaterial> materials;
-								materials.resize(model->getNumVolumeFaces());
+								std::map<std::string, LLImportMaterial> materials;
+								for (U32 i = 0; i < model->mMaterialList.size(); ++i)
+								{
+									materials[model->mMaterialList[i]] = LLImportMaterial();
+								}
 								mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
 								stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
 							}
@@ -1946,6 +2005,11 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
 	//build model list for each LoD
 	model_list model[LLModel::NUM_LODS];
 
+	if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
+	{  //unsupported version
+		return false;
+	}
+
 	LLSD& mesh = data["mesh"];
 
 	LLVolumeParams volume_params;
@@ -1968,10 +2032,6 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
 					mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );					
 				}
 			}
-			else
-			{
-				llassert(model[lod].empty());
-			}
 		}
 	}	
 
@@ -2267,14 +2327,17 @@ void LLModelLoader::loadTextures()
 	{
 		for(U32 i = 0 ; i < iter->second.size(); i++)
 		{
-			for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++)
+			for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
+				j != iter->second[i].mMaterial.end(); ++j)
 			{
-				if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty())
+				LLImportMaterial& material = j->second;
+
+				if(!material.mDiffuseMapFilename.empty())
 				{
-					iter->second[i].mMaterial[j].mDiffuseMap = 
-						LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW);
-					iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE);
-					iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage(0, F32_MAX);
+					material.mDiffuseMap = 
+						LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW);
+					material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE);
+					material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX);
 					mNumOfFetchingTextures++ ;
 				}
 			}
@@ -2574,7 +2637,7 @@ void LLModelLoader::processElement( daeElement* element, bool& badElement )
 				{
 					LLMatrix4 transformation = mTransform;
 
-					std::vector<LLImportMaterial> materials = getMaterials(model, instance_geo);
+					std::map<std::string, LLImportMaterial> materials = getMaterials(model, instance_geo);
 
 					// adjust the transformation to compensate for mesh normalization
 					LLVector3 mesh_scale_vector;
@@ -2630,9 +2693,9 @@ void LLModelLoader::processElement( daeElement* element, bool& badElement )
 	}
 }
 
-std::vector<LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo)
+std::map<std::string, LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo)
 {
-	std::vector<LLImportMaterial> materials;
+	std::map<std::string, LLImportMaterial> materials;
 	for (int i = 0; i < model->mMaterialList.size(); i++)
 	{
 		LLImportMaterial import_material;
@@ -2679,7 +2742,8 @@ std::vector<LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domIns
 			}
 		}
 
-		materials.push_back(import_material);
+		import_material.mBinding = model->mMaterialList[i];
+		materials[model->mMaterialList[i]] = import_material;
 	}
 
 	return materials;
@@ -2919,8 +2983,7 @@ U32 LLModelPreview::calcResourceCost()
 
 	if (mFMP && mModelLoader)
 	{
-		const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean();
-		if ( getLoadState() < LLModelLoader::ERROR_PARSING && confirmed_checkbox )
+		if ( getLoadState() < LLModelLoader::ERROR_PARSING)
 		{
 			mFMP->childEnable("ok_btn");
 		}
@@ -2942,7 +3005,6 @@ U32 LLModelPreview::calcResourceCost()
 		//ok_btn should not have been changed unless something was wrong with joint list
 	}
 	
-	U32 cost = 0;
 	std::set<LLModel*> accounted;
 	U32 num_points = 0;
 	U32 num_hulls = 0;
@@ -2990,8 +3052,7 @@ U32 LLModelPreview::calcResourceCost()
 					   mFMP->childGetValue("upload_skin").asBoolean(),
 					   mFMP->childGetValue("upload_joints").asBoolean(),
 					   TRUE);
-			cost += gMeshRepo.calcResourceCost(ret);
-
+			
 			num_hulls += decomp.mHull.size();
 			for (U32 i = 0; i < decomp.mHull.size(); ++i)
 			{
@@ -3011,7 +3072,7 @@ U32 LLModelPreview::calcResourceCost()
 			F32 z_length = z_transformed.normalize();
 			LLVector3 scale = LLVector3(x_length, y_length, z_length);
 
-			F32 radius = scale.length()*debug_scale;
+			F32 radius = scale.length()*0.5f*debug_scale;
 
 			streaming_cost += LLMeshRepository::getStreamingCost(ret, radius);
 		}
@@ -3023,7 +3084,7 @@ U32 LLModelPreview::calcResourceCost()
 
 	updateStatusMessages();
 
-	return cost;
+	return (U32) streaming_cost;
 }
 
 void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)
@@ -3031,8 +3092,6 @@ void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost,
 	childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x));
 	childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y));
 	childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z));
-	childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost));
-	childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost));	
 }
 
 
@@ -3062,12 +3121,24 @@ void LLModelPreview::rebuildUploadData()
 
 	F32 max_scale = 0.f;
 
-	const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean();
-	if ( mBaseScene.size() > 0 && confirmed_checkbox )
+	if ( mBaseScene.size() > 0)
 	{
 		mFMP->childEnable("ok_btn");
 	}
 
+	//reorder materials to match mBaseModel
+	for (U32 i = 0; i < LLModel::NUM_LODS; i++)
+	{
+		if (mBaseModel.size() == mModel[i].size())
+		{
+			for (U32 j = 0; j < mBaseModel.size(); ++j)
+			{
+				mModel[i][j]->matchMaterialOrder(mBaseModel[j]);
+				llassert(mModel[i][j]->mMaterialList == mBaseModel[j]->mMaterialList);
+			}
+		}
+	}
+
 	for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)
 	{ //for each transform in scene
 		LLMatrix4 mat = iter->first;
@@ -3107,18 +3178,20 @@ void LLModelPreview::rebuildUploadData()
 				}
 			}
 
-			for (U32 i = 0; i < LLModel::NUM_LODS; i++)
-			{ //fill LOD slots based on reference model index
-				if (!mModel[i].empty())
-				{
-					instance.mLOD[i] = mModel[i][idx];
-				}
-				else
-				{
-					instance.mLOD[i] = NULL;
+			if(idx < mBaseModel.size())
+			{
+				for (U32 i = 0; i < LLModel::NUM_LODS; i++)
+				{ //fill LOD slots based on reference model index
+					if (mModel[i].size() > idx)
+					{
+						instance.mLOD[i] = mModel[i][idx];
+					}
+					else
+					{
+						instance.mLOD[i] = NULL;
+					}
 				}
 			}
-
 			instance.mTransform = mat;
 			mUploadData.push_back(instance);
 		}
@@ -3164,6 +3237,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
 
 	LLSD data;
 
+	data["version"] = SLM_SUPPORTED_VERSION;
+
 	S32 mesh_id = 0;
 
 	//build list of unique models and initialize local id
@@ -3190,7 +3265,7 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
 				instance.mLOD[LLModel::LOD_LOW], 
 				instance.mLOD[LLModel::LOD_IMPOSTOR], 
 				decomp, 
-				save_skinweights, save_joint_positions);
+				save_skinweights, save_joint_positions, FALSE, TRUE);
 
 			
 			data["mesh"][instance.mModel->mLocalID] = str.str();
@@ -3217,7 +3292,7 @@ void LLModelPreview::clearModel(S32 lod)
 	mScene[lod].clear();
 }
 
-void LLModelPreview::loadModel(std::string filename, S32 lod)
+void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm)
 {
 	assert_main_thread();
 
@@ -3254,6 +3329,11 @@ void LLModelPreview::loadModel(std::string filename, S32 lod)
 
 	mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode );
 
+	if (force_disable_slm)
+	{
+		mModelLoader->mTrySLM = false;
+	}
+
 	mModelLoader->start();
 
 	mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file"));
@@ -3468,7 +3548,17 @@ void LLModelPreview::loadModelCallback(S32 lod)
 
 	mLoading = false;
 	if (mFMP)
+	{
 		mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->set(FALSE);
+		if (!mBaseModel.empty())
+		{
+			if (mFMP->getChild<LLUICtrl>("description_form")->getValue().asString().empty())
+			{
+				const std::string& model_name = mBaseModel[0]->getName();
+				mFMP->getChild<LLUICtrl>("description_form")->setValue(model_name);
+			}
+		}
+	}
 	refresh();
 
 	mModelLoadedSignal();
@@ -3524,43 +3614,6 @@ void LLModelPreview::generateNormals()
 	updateStatusMessages();
 }
 
-void LLModelPreview::clearMaterials()
-{
-	for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
-	{ //for each transform in current scene
-		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
-		{ //for each instance with that transform
-			LLModelInstance& source_instance = *model_iter;
-			LLModel* source = source_instance.mModel;
-
-			for (S32 i = 0; i < source->getNumVolumeFaces(); ++i)
-			{ //for each face in instance
-				LLImportMaterial& source_material = source_instance.mMaterial[i];
-
-				//clear material info
-				source_material.mDiffuseColor = LLColor4(1,1,1,1);
-				source_material.mDiffuseMap = NULL;
-				source_material.mDiffuseMapFilename.clear();
-				source_material.mDiffuseMapLabel.clear();
-				source_material.mFullbright = false;
-			}
-		}
-	}
-
-	mVertexBuffer[mPreviewLOD].clear();
-
-	if (mPreviewLOD == LLModel::LOD_HIGH)
-	{
-		mBaseScene = mScene[mPreviewLOD];
-		mBaseModel = mModel[mPreviewLOD];
-		clearGLODGroup();
-		mVertexBuffer[5].clear();
-	}
-
-	mResourceCost = calcResourceCost();
-	refresh();
-}
-
 void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
 {
 	if (mBaseModel.empty())
@@ -3734,7 +3787,9 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 			U32 tri_count = 0;
 			for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i)
 			{
-				mVertexBuffer[5][mdl][i]->setBuffer(type_mask);
+				LLVertexBuffer* buff = mVertexBuffer[5][mdl][i];
+				buff->setBuffer(type_mask & buff->getTypeMask());
+				
 				U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices();
 				if (num_indices > 2)
 				{
@@ -3856,6 +3911,8 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 
 			for (GLint i = 0; i < patch_count; ++i)
 			{
+				type_mask = mVertexBuffer[5][base][i]->getTypeMask();
+
 				LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
 
 				if (sizes[i*2+1] > 0 && sizes[i*2] > 0)
@@ -3880,8 +3937,15 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 				LLStrider<U16> index;
 
 				buff->getVertexStrider(pos);
-				buff->getNormalStrider(norm);
-				buff->getTexCoord0Strider(tc);
+				if (type_mask & LLVertexBuffer::MAP_NORMAL)
+				{
+					buff->getNormalStrider(norm);
+				}
+				if (type_mask & LLVertexBuffer::MAP_TEXCOORD0)
+				{
+					buff->getTexCoord0Strider(tc);
+				}
+
 				buff->getIndexStrider(index);
 
 				target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices());
@@ -4087,18 +4151,20 @@ void LLModelPreview::updateStatusMessages()
 			}
 			else if (!verts[lod].empty())
 			{
+				S32 sum_verts_higher_lod = 0;
+				S32 sum_verts_this_lod = 0;
 				for (U32 i = 0; i < verts[lod].size(); ++i)
 				{
-					S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0;
+					sum_verts_higher_lod += ((i < verts[lod+1].size()) ? verts[lod+1][i] : 0);
+					sum_verts_this_lod += verts[lod][i];
+				}
 
-					if (max_verts > 0)
-					{
-						if (verts[lod][i] > max_verts)
-						{ //too many vertices in this lod
-							message = "mesh_status_too_many_vertices";
-							upload_status[lod] = 2;
-						}
-					}
+				if ((sum_verts_higher_lod > 0) &&
+					(sum_verts_this_lod > sum_verts_higher_lod))
+				{
+					//too many vertices in this lod
+					message = "mesh_status_too_many_vertices";
+					upload_status[lod] = 2;
 				}
 			}
 		}
@@ -4163,8 +4229,7 @@ void LLModelPreview::updateStatusMessages()
 		}
 	}
 
-	const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean();
-	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && !has_degenerate && confirmed_checkbox)
+	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && !has_degenerate)
 	{
 		mFMP->childEnable("ok_btn");
 	}
@@ -4269,6 +4334,24 @@ void LLModelPreview::updateStatusMessages()
 			child->setEnabled(enable);
 			child = panel->findNextSibling(child);
 		}
+
+		if (fmp->mCurRequest.empty())
+		{
+			fmp->childSetVisible("Simplify", true);
+			fmp->childSetVisible("simplify_cancel", false);
+			fmp->childSetVisible("Decompose", true);
+			fmp->childSetVisible("decompose_cancel", false);
+
+			if (phys_hulls > 0)
+			{
+				fmp->childEnable("Simplify");
+			}
+		
+			if (phys_tris || phys_hulls > 0)
+			{
+				fmp->childEnable("Decompose");
+			}
+		}
 	}
 
 	const char* lod_controls[] =
@@ -4412,6 +4495,8 @@ void LLModelPreview::updateStatusMessages()
 		crease->forceSetValue(mRequestedCreaseAngle[mPreviewLOD]);
 	}
 
+	mModelUpdatedSignal(true);
+
 }
 
 void LLModelPreview::setPreviewTarget(F32 distance)
@@ -4485,7 +4570,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 
 			bool skinned = include_skin_weights && !mdl->mSkinWeights.empty();
 
-			U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
+			U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0 ;
 
 			if (skinned)
 			{
@@ -4503,8 +4588,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 			LLStrider<LLVector4> weights_strider;
 
 			vb->getVertexStrider(vertex_strider);
-			vb->getNormalStrider(normal_strider);
-			vb->getTexCoord0Strider(tc_strider);
 			vb->getIndexStrider(index_strider);
 
 			if (skinned)
@@ -4513,8 +4596,18 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 			}
 
 			LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32));
-			LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
-			LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32));
+			
+			if (vf.mTexCoords)
+			{
+				vb->getTexCoord0Strider(tc_strider);
+				LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
+			}
+			
+			if (vf.mNormals)
+			{
+				vb->getNormalStrider(normal_strider);
+				LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32));
+			}
 
 			if (skinned)
 			{
@@ -4728,7 +4821,18 @@ BOOL LLModelPreview::render()
 
 	glClear(GL_DEPTH_BUFFER_BIT);
 
-	LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect();
+	LLRect preview_rect;
+
+	LLFloaterModelWizard* floater_wizard = dynamic_cast<LLFloaterModelWizard*>(mFMP);
+	if (floater_wizard)
+	{
+		preview_rect = floater_wizard->getPreviewRect();
+	}
+	else
+	{
+		preview_rect = mFMP->getChildView("preview_panel")->getRect();
+	}
+
 	F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight();
 
 	LLViewerCamera::getInstance()->setAspect(aspect);
@@ -4773,6 +4877,8 @@ BOOL LLModelPreview::render()
 	const F32 BRIGHTNESS = 0.9f;
 	gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
 
+	const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
+
 	LLGLEnable normalize(GL_NORMALIZE);
 
 	if (!mBaseModel.empty() && mVertexBuffer[5].empty())
@@ -4795,6 +4901,19 @@ BOOL LLModelPreview::render()
 			}
 		}
 
+		//make sure material lists all match
+		for (U32 i = 0; i < LLModel::NUM_LODS; i++)
+		{
+			if (mBaseModel.size() == mModel[i].size())
+			{
+				for (U32 j = 0; j < mBaseModel.size(); ++j)
+				{
+					mModel[i][j]->matchMaterialOrder(mBaseModel[j]);
+					llassert(mModel[i][j]->mMaterialList == mBaseModel[j]->mMaterialList);
+				}
+			}
+		}
+
 		if (regen)
 		{
 			genBuffers(mPreviewLOD, skin_weight);
@@ -4821,18 +4940,23 @@ BOOL LLModelPreview::render()
 				for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i)
 				{
 					LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
-
-					buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+				
+					buffer->setBuffer(type_mask & buffer->getTypeMask());
 
 					if (textures)
 					{
-						glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
-						if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull())
+						const std::string& binding = instance.mModel->mMaterialList[i];
+						const LLImportMaterial& material = instance.mMaterial[binding];
+
+						llassert(binding == model->mMaterialList[i]);
+						
+						glColor4fv(material.mDiffuseColor.mV);
+						if (material.mDiffuseMap.notNull())
 						{
-							if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1)
+							if (material.mDiffuseMap->getDiscardLevel() > -1)
 							{
-								gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true);
-								mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get());
+								gGL.getTexUnit(0)->bind(material.mDiffuseMap, true);
+								mTextureSet.insert(material.mDiffuseMap.get());
 							}
 						}
 					}
@@ -4941,7 +5065,7 @@ BOOL LLModelPreview::render()
 						{
 							LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
 
-							buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+							buffer->setBuffer(type_mask & buffer->getTypeMask());
 
 							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -5007,7 +5131,7 @@ BOOL LLModelPreview::render()
 							{
 								LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
 
-								buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+								buffer->setBuffer(type_mask & buffer->getTypeMask());
 
 								LLStrider<LLVector3> pos_strider; 
 								buffer->getVertexStrider(pos_strider, 0);
@@ -5132,8 +5256,10 @@ BOOL LLModelPreview::render()
 								position[j] = v;
 							}
 
-							buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
-							glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
+							const std::string& binding = instance.mModel->mMaterialList[i];
+							const LLImportMaterial& material = instance.mMaterial[binding];
+							buffer->setBuffer(type_mask & buffer->getTypeMask());
+							glColor4fv(material.mDiffuseColor.mV);
 							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 							buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
 							glColor3f(0.4f, 0.4f, 0.4f);
@@ -5253,7 +5379,12 @@ void LLFloaterModelPreview::onReset(void* user_data)
 	LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;
 	LLModelPreview* mp = fmp->mModelPreview;
 	std::string filename = mp->mLODFile[3]; 
-	mp->loadModel(filename,3);
+
+	//reset model preview
+	fmp->initModelPreview();
+
+	mp = fmp->mModelPreview;
+	mp->loadModel(filename,3,true);
 }
 
 //static
@@ -5271,31 +5402,18 @@ void LLFloaterModelPreview::onUpload(void* user_data)
 	mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions);
 
 	gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,
-						  mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions);
-
-	mp->closeFloater(false);
+						  mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mp->mUploadModelUrl,
+						  true, LLHandle<LLWholeModelFeeObserver>(), mp->getWholeModelUploadObserverHandle());
 }
 
 
-//static
-void LLFloaterModelPreview::onClearMaterials(void* user_data)
-{
-	LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data;
-	mp->mModelPreview->clearMaterials();
-}
-
 //static
 void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data)
 {
+	sInstance->toggleCalculateButton(true);
 	sInstance->mModelPreview->mDirty = true;
 }
 
-void LLFloaterModelPreview::updateResourceCost()
-{
-	U32 cost = mModelPreview->mResourceCost;
-	childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost));
-}
-
 //static
 void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata )
 {
@@ -5339,6 +5457,97 @@ void LLFloaterModelPreview::setStatusMessage(const std::string& msg)
 	mStatusMessage = msg;
 }
 
+void LLFloaterModelPreview::toggleCalculateButton()
+{
+	toggleCalculateButton(true);
+}
+
+void LLFloaterModelPreview::toggleCalculateButton(bool visible)
+{
+	mCalculateBtn->setVisible(visible);
+
+	bool uploadingSkin		     = childGetValue("upload_skin").asBoolean();
+	bool uploadingJointPositions = childGetValue("upload_joints").asBoolean();
+	if ( uploadingSkin )
+	{
+		//Disable the calculate button *if* the rig is invalid - which is determined during the critiquing process
+		if ( uploadingJointPositions && !mModelPreview->isRigValidForJointPositionUpload() )
+		{
+			mCalculateBtn->setVisible( false );
+		}
+		else
+		if ( !mModelPreview->isLegacyRigValid() )
+		{			
+			mCalculateBtn->setVisible( false );
+		}
+	}
+	
+	mUploadBtn->setVisible(!visible);
+	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+
+	if (visible)
+	{
+		std::string tbd = getString("tbd");
+		childSetTextArg("weights", "[EQ]", tbd);
+		childSetTextArg("weights", "[ST]", tbd);
+		childSetTextArg("weights", "[SIM]", tbd);
+		childSetTextArg("weights", "[PH]", tbd);
+		childSetTextArg("upload_fee", "[FEE]", tbd);
+		childSetTextArg("price_breakdown", "[STREAMING]", tbd);
+		childSetTextArg("price_breakdown", "[PHYSICS]", tbd);
+		childSetTextArg("price_breakdown", "[INSTANCES]", tbd);
+		childSetTextArg("price_breakdown", "[TEXTURES]", tbd);
+		childSetTextArg("price_breakdown", "[MODEL]", tbd);
+	}
+}
+
+void LLFloaterModelPreview::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url)
+{
+	mModelPhysicsFee = result;
+	mModelPhysicsFee["url"] = upload_url;
+
+	doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::handleModelPhysicsFeeReceived,this));
+}
+
+void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
+{
+	const LLSD& result = mModelPhysicsFee;
+	mUploadModelUrl = result["url"].asString();
+
+	childSetTextArg("weights", "[EQ]", llformat("%0.3f", result["resource_cost"].asReal()));
+	childSetTextArg("weights", "[ST]", llformat("%0.3f", result["model_streaming_cost"].asReal()));
+	childSetTextArg("weights", "[SIM]", llformat("%0.3f", result["simulation_cost"].asReal()));
+	childSetTextArg("weights", "[PH]", llformat("%0.3f", result["physics_cost"].asReal()));
+	childSetTextArg("upload_fee", "[FEE]", llformat("%d", result["upload_price"].asInteger()));
+	childSetTextArg("price_breakdown", "[STREAMING]", llformat("%d", result["upload_price_breakdown"]["mesh_streaming"].asInteger()));
+	childSetTextArg("price_breakdown", "[PHYSICS]", llformat("%d", result["upload_price_breakdown"]["mesh_physics"].asInteger()));
+	childSetTextArg("price_breakdown", "[INSTANCES]", llformat("%d", result["upload_price_breakdown"]["mesh_instance"].asInteger()));
+	childSetTextArg("price_breakdown", "[TEXTURES]", llformat("%d", result["upload_price_breakdown"]["texture"].asInteger()));
+	childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));
+	childSetVisible("weights", true);
+	childSetVisible("upload_fee", true);
+	childSetVisible("price_breakdown", true);
+	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+}
+
+void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason)
+{
+	toggleCalculateButton(true);
+	llwarns << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl;
+}
+
+/*virtual*/ 
+void LLFloaterModelPreview::onModelUploadSuccess()
+{
+	closeFloater(false);
+}
+
+/*virtual*/ 
+void LLFloaterModelPreview::onModelUploadFailure()
+{
+	toggleCalculateButton(true);
+}
+
 S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
 {
 	if (mContinue)
@@ -5378,3 +5587,25 @@ void LLFloaterModelPreview::DecompRequest::completed()
 		llassert(sInstance->mCurRequest.find(this) == sInstance->mCurRequest.end());
 	}
 }
+
+void dump_llsd_to_file(const LLSD& content, std::string filename);
+
+void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)
+{
+	dump_llsd_to_file(result,"perm_received.xml");
+	std::string upload_status = result["mesh_upload_status"].asString();
+	// BAP HACK: handle "" for case that  MeshUploadFlag cap is broken.
+	mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status));
+
+	//mUploadBtn->setEnabled(mHasUploadPerm);
+	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+	getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm);
+	getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);
+}
+
+void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::string& reason)
+{
+	llwarns << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << llendl;
+
+	LLNotificationsUtil::add("MeshUploadPermError");
+}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index d4f6b4d293d49518ac164aebb797161734e73c8b..3a5f7602fe90e4b5fc343e300f87d521f635517a 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -109,7 +109,7 @@ class LLModelLoader : public LLThread
 
 	void loadTextures() ; //called in the main thread.
 	void processElement(daeElement* element, bool& badElement);
-	std::vector<LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);
+	std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);
 	LLImportMaterial profileToMaterial(domProfile_COMMON* material);
 	std::string getElementLabel(daeElement *element);
 	LLColor4 getDaeColor(daeElement* element);
@@ -140,7 +140,7 @@ class LLModelLoader : public LLThread
 	static bool isAlive(LLModelLoader* loader) ;
 };
 
-class LLFloaterModelPreview : public LLFloater
+class LLFloaterModelPreview : public LLFloaterModelUploadBase
 {
 public:
 	
@@ -162,11 +162,15 @@ class LLFloaterModelPreview : public LLFloater
 	
 	virtual BOOL postBuild();
 	
+	void initModelPreview();
+
 	BOOL handleMouseDown(S32 x, S32 y, MASK mask);
 	BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 	BOOL handleHover(S32 x, S32 y, MASK mask);
 	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); 
 	
+	/*virtual*/ void onOpen(const LLSD& key);
+
 	static void onMouseCaptureLostModelPreview(LLMouseHandler*);
 	static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
 
@@ -178,13 +182,10 @@ class LLFloaterModelPreview : public LLFloater
 
 	static void onUpload(void* data);
 	
-	static void onClearMaterials(void* data);
-	
 	static void refresh(LLUICtrl* ctrl, void* data);
 	
-	void updateResourceCost();
-	
 	void			loadModel(S32 lod);
+	void 			loadModel(S32 lod, const std::string& file_name, bool force_disable_slm = false);
 	
 	void onViewOptionChecked(const LLSD& userdata);
 	bool isViewOptionChecked(const LLSD& userdata);
@@ -193,6 +194,20 @@ class LLFloaterModelPreview : public LLFloater
 	void enableViewOption(const std::string& option);
 	void disableViewOption(const std::string& option);
 
+	// shows warning message if agent has no permissions to upload model
+	/*virtual*/ void onPermissionsReceived(const LLSD& result);
+
+	// called when error occurs during permissions request
+	/*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason);
+
+	/*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url);
+				void handleModelPhysicsFeeReceived();
+	/*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason);
+
+	/*virtual*/ void onModelUploadSuccess();
+
+	/*virtual*/ void onModelUploadFailure();
+
 protected:
 	friend class LLModelPreview;
 	friend class LLMeshFilePicker;
@@ -258,6 +273,17 @@ class LLFloaterModelPreview : public LLFloater
 	LLToggleableMenu* mViewOptionMenu;
 	LLMutex* mStatusLock;
 
+	LLSD mModelPhysicsFee;
+
+private:
+	void onClickCalculateBtn();
+	void toggleCalculateButton();
+
+	// Toggles between "Calculate weights & fee" and "Upload" buttons.
+	void toggleCalculateButton(bool visible);
+
+	LLButton* mUploadBtn;
+	LLButton* mCalculateBtn;
 };
 
 class LLMeshFilePicker : public LLFilePickerThread
@@ -276,6 +302,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 {	
 	typedef boost::signals2::signal<void (F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t;
 	typedef boost::signals2::signal<void (void)> model_loaded_signal_t;
+	typedef boost::signals2::signal<void (bool)> model_updated_signal_t;
 
 public:
 	LLModelPreview(S32 width, S32 height, LLFloater* fmp);
@@ -297,11 +324,10 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 	virtual BOOL needsRender() { return mNeedsUpdate; }
 	void setPreviewLOD(S32 lod);
 	void clearModel(S32 lod);
-	void loadModel(std::string filename, S32 lod);
+	void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
 	void loadModelCallback(S32 lod);
 	void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
 	void generateNormals();
-	void clearMaterials();
 	U32 calcResourceCost();
 	void rebuildUploadData();
 	void saveUploadData(bool save_skinweights, bool save_joint_poisitions);
@@ -335,6 +361,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 	
 	boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){  return mDetailsSignal.connect(cb);  }
 	boost::signals2::connection setModelLoadedCallback( const model_loaded_signal_t::slot_type& cb ){  return mModelLoadedSignal.connect(cb);  }
+	boost::signals2::connection setModelUpdatedCallback( const model_updated_signal_t::slot_type& cb ){  return mModelUpdatedSignal.connect(cb);  }
 	
 	void setLoadState( U32 state ) { mLoadState = state; }
 	U32 getLoadState() { return mLoadState; }
@@ -420,6 +447,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 
 	details_signal_t mDetailsSignal;
 	model_loaded_signal_t mModelLoadedSignal;
+	model_updated_signal_t mModelUpdatedSignal;
 	
 	LLVector3	mModelPivot;
 	bool		mHasPivot;
diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6d3800bfa46f26a59bf2a12e941ab3796a0f01c3
--- /dev/null
+++ b/indra/newview/llfloatermodeluploadbase.cpp
@@ -0,0 +1,58 @@
+/**
+ * @file llfloatermodeluploadbase.cpp
+ * @brief LLFloaterUploadModelBase class definition
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatermodeluploadbase.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llnotificationsutil.h"
+
+LLFloaterModelUploadBase::LLFloaterModelUploadBase(const LLSD& key)
+:LLFloater(key),
+ mHasUploadPerm(false)
+{
+}
+
+void LLFloaterModelUploadBase::requestAgentUploadPermissions()
+{
+	std::string capability = "MeshUploadFlag";
+	std::string url = gAgent.getRegion()->getCapability(capability);
+
+	if (!url.empty())
+	{
+		llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<llendl;
+		LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle()));
+	}
+	else
+	{
+		LLSD args;
+		args["CAPABILITY"] = capability;
+		LLNotificationsUtil::add("RegionCapabilityRequestError", args);
+		// BAP HACK avoid being blocked by broken server side stuff
+		mHasUploadPerm = true;
+	}
+}
diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h
new file mode 100644
index 0000000000000000000000000000000000000000..a52bc286874122d5dc64fe7473e8772f7e10f22d
--- /dev/null
+++ b/indra/newview/llfloatermodeluploadbase.h
@@ -0,0 +1,61 @@
+/**
+ * @file llfloatermodeluploadbase.h
+ * @brief LLFloaterUploadModelBase class declaration
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERMODELUPLOADBASE_H
+#define LL_LLFLOATERMODELUPLOADBASE_H
+
+#include "lluploadfloaterobservers.h"
+
+class LLFloaterModelUploadBase : public LLFloater, public LLUploadPermissionsObserver, public LLWholeModelFeeObserver, public LLWholeModelUploadObserver
+{
+public:
+
+	LLFloaterModelUploadBase(const LLSD& key);
+
+	virtual ~LLFloaterModelUploadBase(){};
+
+	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0;
+
+	virtual void onPermissionsReceived(const LLSD& result) = 0;
+
+	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0;
+
+	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0;
+
+	virtual void onModelUploadSuccess() {};
+
+	virtual void onModelUploadFailure() {};
+
+protected:
+
+	// requests agent's permissions to upload model
+	void requestAgentUploadPermissions();
+
+	std::string mUploadModelUrl;
+	bool mHasUploadPerm;
+};
+
+#endif /* LL_LLFLOATERMODELUPLOADBASE_H */
diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp
index 707c8288dfe5dd43b22b39139d5a03b415b8594f..b517b78e5a9d2ae0c5ed7fe73f9299bf37f7cb78 100644
--- a/indra/newview/llfloatermodelwizard.cpp
+++ b/indra/newview/llfloatermodelwizard.cpp
@@ -46,12 +46,21 @@ static	const std::string stateNames[]={
 	"choose_file",
 	"optimize",
 	"physics",
-	"physics2",
 	"review",
 	"upload"};
 
+static void swap_controls(LLUICtrl* first_ctrl, LLUICtrl* second_ctrl, bool first_ctr_visible);
+
 LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key)
-	: LLFloater(key)
+	: LLFloaterModelUploadBase(key)
+	 ,mRecalculateGeometryBtn(NULL)
+	 ,mRecalculatePhysicsBtn(NULL)
+	 ,mRecalculatingPhysicsBtn(NULL)
+	 ,mCalculateWeightsBtn(NULL)
+	 ,mCalculatingWeightsBtn(NULL)
+	 ,mChooseFilePreviewPanel(NULL)
+	 ,mOptimizePreviewPanel(NULL)
+	 ,mPhysicsPreviewPanel(NULL)
 {
 	mLastEnabledState = CHOOSE_FILE;
 	sInstance = this;
@@ -59,7 +68,6 @@ LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key)
 	mCommitCallbackRegistrar.add("Wizard.Choose", boost::bind(&LLFloaterModelWizard::setState, this, CHOOSE_FILE));
 	mCommitCallbackRegistrar.add("Wizard.Optimize", boost::bind(&LLFloaterModelWizard::setState, this, OPTIMIZE));
 	mCommitCallbackRegistrar.add("Wizard.Physics", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS));
-	mCommitCallbackRegistrar.add("Wizard.Physics2", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS2));
 	mCommitCallbackRegistrar.add("Wizard.Review", boost::bind(&LLFloaterModelWizard::setState, this, REVIEW));
 	mCommitCallbackRegistrar.add("Wizard.Upload", boost::bind(&LLFloaterModelWizard::setState, this, UPLOAD));
 }
@@ -81,16 +89,22 @@ void LLFloaterModelWizard::setState(int state)
 		}
 	}
 
+	LLView* current_preview_panel = NULL;
+
 	if (state == CHOOSE_FILE)
 	{
 		mModelPreview->mViewOption["show_physics"] = false;
 
+		current_preview_panel = mChooseFilePreviewPanel;
+
 		getChildView("close")->setVisible(false);
 		getChildView("back")->setVisible(true);
 		getChildView("back")->setEnabled(false);
 		getChildView("next")->setVisible(true);
 		getChildView("upload")->setVisible(false);
 		getChildView("cancel")->setVisible(true);
+		mCalculateWeightsBtn->setVisible(false);
+		mCalculatingWeightsBtn->setVisible(false);
 	}
 
 	if (state == OPTIMIZE)
@@ -102,12 +116,16 @@ void LLFloaterModelWizard::setState(int state)
 
 		mModelPreview->mViewOption["show_physics"] = false;
 
+		current_preview_panel = mOptimizePreviewPanel;
+
 		getChildView("back")->setVisible(true);
 		getChildView("back")->setEnabled(true);
 		getChildView("close")->setVisible(false);
 		getChildView("next")->setVisible(true);
 		getChildView("upload")->setVisible(false);
 		getChildView("cancel")->setVisible(true);
+		mCalculateWeightsBtn->setVisible(false);
+		mCalculatingWeightsBtn->setVisible(false);
 	}
 
 	if (state == PHYSICS)
@@ -115,34 +133,24 @@ void LLFloaterModelWizard::setState(int state)
 		if (mLastEnabledState < state)
 		{
 			mModelPreview->setPhysicsFromLOD(1);
-		}
 
-		mModelPreview->mViewOption["show_physics"] = true;
-
-		getChildView("next")->setVisible(true);
-		getChildView("upload")->setVisible(false);
-		getChildView("close")->setVisible(false);
-		getChildView("back")->setVisible(true);
-		getChildView("back")->setEnabled(true);
-		getChildView("cancel")->setVisible(true);
-	}
-
-	if (state == PHYSICS2)
-	{
-		if (mLastEnabledState < state)
-		{
-			executePhysicsStage("Decompose");
+			// Trigger the recalculate physics when first entering
+			// the Physics step.
+			onClickRecalculatePhysics();
 		}
 
 		mModelPreview->mViewOption["show_physics"] = true;
 
-		getChildView("next")->setVisible(true);
-		getChildView("next")->setEnabled(true);
+		current_preview_panel = mPhysicsPreviewPanel;
+
+		getChildView("next")->setVisible(false);
 		getChildView("upload")->setVisible(false);
 		getChildView("close")->setVisible(false);
 		getChildView("back")->setVisible(true);
 		getChildView("back")->setEnabled(true);
 		getChildView("cancel")->setVisible(true);
+		mCalculateWeightsBtn->setVisible(true);
+		mCalculatingWeightsBtn->setVisible(false);
 	}
 
 	if (state == REVIEW)
@@ -156,6 +164,8 @@ void LLFloaterModelWizard::setState(int state)
 		getChildView("back")->setEnabled(true);
 		getChildView("upload")->setVisible(true);
 		getChildView("cancel")->setVisible(true);
+		mCalculateWeightsBtn->setVisible(false);
+		mCalculatingWeightsBtn->setVisible(false);
 	}
 
 	if (state == UPLOAD)
@@ -165,8 +175,24 @@ void LLFloaterModelWizard::setState(int state)
 		getChildView("back")->setVisible(false);
 		getChildView("upload")->setVisible(false);
 		getChildView("cancel")->setVisible(false);
+		mCalculateWeightsBtn->setVisible(false);
+		mCalculatingWeightsBtn->setVisible(false);
 	}
 
+	if (current_preview_panel)
+	{
+		LLRect rect;
+		current_preview_panel->localRectToOtherView(current_preview_panel->getLocalRect(), &rect, this);
+
+		// Reduce the preview rect by 1 px to fit the borders
+		rect.stretch(-1);
+
+		if (rect != mPreviewRect)
+		{
+			mPreviewRect = rect;
+			mModelPreview->refresh();
+		}
+	}
 	updateButtons();
 }
 
@@ -198,18 +224,60 @@ void LLFloaterModelWizard::updateButtons()
 			button->setEnabled(FALSE);
 		}
 	}
+}
 
-	LLButton *physics_button = getChild<LLButton>(stateNames[PHYSICS]+"_btn");
-	
-	if (mState == PHYSICS2)
+void LLFloaterModelWizard::onClickSwitchToAdvanced()
+{
+	LLFloaterModelPreview* floater_preview = LLFloaterReg::getTypedInstance<LLFloaterModelPreview>("upload_model");
+	if (!floater_preview)
 	{
-		physics_button->setVisible(false);
+		llwarns << "FLoater model preview not found." << llendl;
+		return;
 	}
-	else
+
+	// Open floater model preview
+	floater_preview->openFloater();
+
+	// Close the wizard
+	closeFloater();
+
+	std::string filename = getChild<LLUICtrl>("lod_file")->getValue().asString();
+	if (!filename.empty())
 	{
-		physics_button->setVisible(true);
+		// Re-load the model to the floater model preview if it has been loaded
+		// into the wizard.
+		floater_preview->loadModel(3, filename);
 	}
+}
+
+void LLFloaterModelWizard::onClickRecalculateGeometry()
+{
+	S32 val = getChild<LLUICtrl>("accuracy_slider")->getValue().asInteger();
+
+	mModelPreview->genLODs(-1, NUM_LOD - val);
+
+	mModelPreview->refresh();
+}
+
+void LLFloaterModelWizard::onClickRecalculatePhysics()
+{
+	// Hide the "Recalculate physics" button and show the "Recalculating..."
+	// button instead.
+	swap_controls(mRecalculatePhysicsBtn, mRecalculatingPhysicsBtn, false);
+
+	executePhysicsStage("Decompose");
+}
 
+void LLFloaterModelWizard::onClickCalculateUploadFee()
+{
+	swap_controls(mCalculateWeightsBtn, mCalculatingWeightsBtn, false);
+
+	mModelPreview->rebuildUploadData();
+
+	mUploadModelUrl.clear();
+
+	gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale,
+			true, false, false, mUploadModelUrl, false, getWholeModelFeeObserverHandle());
 }
 
 void LLFloaterModelWizard::loadModel()
@@ -344,6 +412,7 @@ BOOL LLFloaterModelWizard::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return TRUE;
 }
 
+
 void LLFloaterModelWizard::initDecompControls()
 {
 	LLSD key;
@@ -401,12 +470,83 @@ void LLFloaterModelWizard::initDecompControls()
 	mDecompParams["Simplify Method"] = 0; // set it to retain %
 }
 
+/*virtual*/
+void LLFloaterModelWizard::onPermissionsReceived(const LLSD& result)
+{
+	std::string upload_status = result["mesh_upload_status"].asString();
+	// BAP HACK: handle "" for case that  MeshUploadFlag cap is broken.
+	mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status));
+
+	getChildView("warning_label")->setVisible(!mHasUploadPerm);
+	getChildView("warning_text")->setVisible(!mHasUploadPerm);
+}
+
+/*virtual*/
+void LLFloaterModelWizard::setPermissonsErrorStatus(U32 status, const std::string& reason)
+{
+	llwarns << "LLFloaterModelWizard::setPermissonsErrorStatus(" << status << " : " << reason << ")" << llendl;
+}
+
+/*virtual*/
+void LLFloaterModelWizard::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url)
+{
+	swap_controls(mCalculateWeightsBtn, mCalculatingWeightsBtn, true);
+
+	// Enable the "Upload" buton if we have calculated the upload fee
+	// and have the permission to upload.
+	getChildView("upload")->setEnabled(mHasUploadPerm);
+
+	mUploadModelUrl = upload_url;
+
+	S32 fee = result["upload_price"].asInteger();
+	childSetTextArg("review_fee", "[FEE]", llformat("%d", fee));
+	childSetTextArg("charged_fee", "[FEE]", llformat("%d", fee));
+
+	setState(REVIEW);
+}
+
+/*virtual*/
+void LLFloaterModelWizard::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason)
+{
+	swap_controls(mCalculateWeightsBtn, mCalculatingWeightsBtn, true);
+
+	// Disable the "Review" step if it has been previously enabled.
+	modelChangedCallback();
+
+	llwarns << "LLFloaterModelWizard::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl;
+
+	setState(PHYSICS);
+}
+
+/*virtual*/ 
+void LLFloaterModelWizard::onModelUploadSuccess() 
+{
+	// success!
+	setState(UPLOAD);
+}
+
+/*virtual*/
+void LLFloaterModelWizard::onModelUploadFailure()
+{
+	// Failure. Make the user recalculate fees
+	setState(PHYSICS);
+	// Disable the "Review" step if it has been previously enabled.
+	if (mLastEnabledState > PHYSICS)
+	{
+		 mLastEnabledState = PHYSICS;
+	}
+
+	updateButtons();
+}
+
 //static
 void LLFloaterModelWizard::executePhysicsStage(std::string stage_name)
 {
 	if (sInstance)
 	{
-		F64 physics_accuracy = sInstance->getChild<LLSliderCtrl>("physics_slider")->getValue().asReal();
+		// Invert the slider value so that "performance" end is giving the least detailed physics,
+		// and the "accuracy" end is giving the most detailed physics
+		F64 physics_accuracy = 1 - sInstance->getChild<LLSliderCtrl>("physics_slider")->getValue().asReal();
 
 		sInstance->mDecompParams["Retain%"] = physics_accuracy;
 
@@ -471,13 +611,16 @@ void LLFloaterModelWizard::DecompRequest::completed()
 	{
 		executePhysicsStage("Simplify");
 	}
+	else
+	{
+		// Decomp request is complete so we can enable the "Recalculate physics" button again.
+		swap_controls(sInstance->mRecalculatePhysicsBtn, sInstance->mRecalculatingPhysicsBtn, true);
+	}
 }
 
 
 BOOL LLFloaterModelWizard::postBuild()
 {
-	LLView* preview_panel = getChildView("preview_panel");
-
 	childSetValue("import_scale", (F32) 0.67335826);
 
 	getChild<LLUICtrl>("browse")->setCommitCallback(boost::bind(&LLFloaterModelWizard::loadModel, this));
@@ -488,23 +631,36 @@ BOOL LLFloaterModelWizard::postBuild()
 	getChild<LLUICtrl>("next")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this));
 	getChild<LLUICtrl>("preview_lod_combo")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1));
 	getChild<LLUICtrl>("preview_lod_combo2")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1));
-	getChild<LLUICtrl>("preview_lod_combo3")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1));
-	getChild<LLUICtrl>("accuracy_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onAccuracyPerformance, this, _2));
 	getChild<LLUICtrl>("upload")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onUpload, this));
-	getChild<LLUICtrl>("physics_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPhysicsChanged, this));
+	getChild<LLUICtrl>("switch_to_advanced")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickSwitchToAdvanced, this));
+
+	mRecalculateGeometryBtn = getChild<LLButton>("recalculate_geometry_btn");
+	mRecalculateGeometryBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickRecalculateGeometry, this));
+
+	mRecalculatePhysicsBtn = getChild<LLButton>("recalculate_physics_btn");
+	mRecalculatePhysicsBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickRecalculatePhysics, this));
+
+	mRecalculatingPhysicsBtn = getChild<LLButton>("recalculating_physics_btn");
+
+	mCalculateWeightsBtn = getChild<LLButton>("calculate");
+	mCalculateWeightsBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCalculateUploadFee, this));
+
+	mCalculatingWeightsBtn = getChild<LLButton>("calculating");
+
+	mChooseFilePreviewPanel = getChild<LLView>("choose_file_preview_panel");
+	mOptimizePreviewPanel = getChild<LLView>("optimize_preview_panel");
+	mPhysicsPreviewPanel = getChild<LLView>("physics_preview_panel");
 
 	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
 	
 	enable_registrar.add("Next.OnEnable", boost::bind(&LLFloaterModelWizard::onEnableNext, this));
 	enable_registrar.add("Back.OnEnable", boost::bind(&LLFloaterModelWizard::onEnableBack, this));
-
-
-	mPreviewRect = preview_panel->getRect();
 	
 	mModelPreview = new LLModelPreview(512, 512, this);
 	mModelPreview->setPreviewTarget(16.f);
 	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelWizard::setDetails, this, _1, _2, _3, _4, _5));
 	mModelPreview->setModelLoadedCallback(boost::bind(&LLFloaterModelWizard::modelLoadedCallback, this));
+	mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelWizard::modelChangedCallback, this));
 	mModelPreview->mViewOption["show_textures"] = true;
 
 	center();
@@ -517,6 +673,8 @@ BOOL LLFloaterModelWizard::postBuild()
 
 	initDecompControls();
 
+	requestAgentUploadPermissions();
+
 	return TRUE;
 }
 
@@ -532,22 +690,29 @@ void LLFloaterModelWizard::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F
 			panel->childSetText("dimension_x", llformat("%.1f", x));
 			panel->childSetText("dimension_y", llformat("%.1f", y));
 			panel->childSetText("dimension_z", llformat("%.1f", z));
-			panel->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost));
-			panel->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost));	
 		}
 	}
+
+	childSetTextArg("review_prim_equiv", "[EQUIV]", llformat("%d", mModelPreview->mResourceCost));
 }
 
 void LLFloaterModelWizard::modelLoadedCallback()
 {
 	mLastEnabledState = CHOOSE_FILE;
-	getChild<LLCheckBoxCtrl>("confirm_checkbox")->set(FALSE);
 	updateButtons();
 }
 
-void LLFloaterModelWizard::onPhysicsChanged()
+void LLFloaterModelWizard::modelChangedCallback()
 {
-	mLastEnabledState = PHYSICS;
+	// Don't allow to proceed to the "Review" step if the model has changed
+	// but the new upload fee hasn't been calculated yet.
+	if (mLastEnabledState > PHYSICS)
+	{
+		 mLastEnabledState = PHYSICS;
+	}
+
+	getChildView("upload")->setEnabled(false);
+
 	updateButtons();
 }
 
@@ -556,22 +721,10 @@ void LLFloaterModelWizard::onUpload()
 	mModelPreview->rebuildUploadData();
 	
 	gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, 
-						  true, false, false);
-	
-	setState(UPLOAD);
-	
-}
-
-void LLFloaterModelWizard::onAccuracyPerformance(const LLSD& data)
-{
-	int val = (int) data.asInteger();
-
-	mModelPreview->genLODs(-1, NUM_LOD-val);
-
-	mModelPreview->refresh();
+						  true, false, false, mUploadModelUrl, true,
+						  LLHandle<LLWholeModelFeeObserver>(), getWholeModelUploadObserverHandle());
 }
 
-
 void LLFloaterModelWizard::onPreviewLODCommit(LLUICtrl* ctrl)
 {
 	if (!mModelPreview)
@@ -601,11 +754,6 @@ void LLFloaterModelWizard::refresh()
 		
 		getChildView("next")->setEnabled(model_loaded);
 	}
-	if (mState == REVIEW)
-	{
-		getChildView("upload")->setEnabled(getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean());
-	}
-
 }
 
 void LLFloaterModelWizard::draw()
@@ -613,42 +761,35 @@ void LLFloaterModelWizard::draw()
 	refresh();
 
 	LLFloater::draw();
-	LLRect r = getRect();
-	
-	mModelPreview->update();
 
-	if (mModelPreview)
+	if (mModelPreview && mState < REVIEW)
 	{
+		mModelPreview->update();
+
 		gGL.color3f(1.f, 1.f, 1.f);
 		
 		gGL.getTexUnit(0)->bind(mModelPreview);
 		
-		LLView *view = getChildView(stateNames[mState]+"_panel");
-		LLView* preview_panel = view->getChildView("preview_panel");
-
-		LLRect rect = preview_panel->getRect();
-		if (rect != mPreviewRect)
-		{
-			mModelPreview->refresh();
-			mPreviewRect = preview_panel->getRect();
-		}
-		
-		LLRect item_rect;
-		preview_panel->localRectToOtherView(preview_panel->getLocalRect(), &item_rect, this);
-	
 		gGL.begin( LLRender::QUADS );
 		{
 			gGL.texCoord2f(0.f, 1.f);
-			gGL.vertex2i(item_rect.mLeft, item_rect.mTop-1);
+			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop);
 			gGL.texCoord2f(0.f, 0.f);
-			gGL.vertex2i(item_rect.mLeft, item_rect.mBottom);
+			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom);
 			gGL.texCoord2f(1.f, 0.f);
-			gGL.vertex2i(item_rect.mRight-1, item_rect.mBottom);
+			gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom);
 			gGL.texCoord2f(1.f, 1.f);
-			gGL.vertex2i(item_rect.mRight-1, item_rect.mTop-1);
+			gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop);
 		}
 		gGL.end();
 		
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	}
 }
+
+// static
+void swap_controls(LLUICtrl* first_ctrl, LLUICtrl* second_ctrl, bool first_ctr_visible)
+{
+	first_ctrl->setVisible(first_ctr_visible);
+	second_ctrl->setVisible(!first_ctr_visible);
+}
diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h
index b166d262957cda56ea19b470ccef545516e5fbd1..db9b60577709f2519713a78e9c72850dff383a0a 100644
--- a/indra/newview/llfloatermodelwizard.h
+++ b/indra/newview/llfloatermodelwizard.h
@@ -30,12 +30,13 @@
 #include "llmeshrepository.h"
 #include "llmodel.h"
 #include "llthread.h"
+#include "llfloatermodeluploadbase.h"
 
 
 class LLModelPreview;
 
 
-class LLFloaterModelWizard : public LLFloater
+class LLFloaterModelWizard : public LLFloaterModelUploadBase
 {
 public:
 	
@@ -62,13 +63,29 @@ class LLFloaterModelWizard : public LLFloater
 	BOOL handleMouseDown(S32 x, S32 y, MASK mask);
 	BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 	BOOL handleHover(S32 x, S32 y, MASK mask);
-	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); 
+	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
 
 	void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost);
 	void modelLoadedCallback();
-	void onPhysicsChanged();
+	void modelChangedCallback();
 	void initDecompControls();
 	
+	// shows warning message if agent has no permissions to upload model
+	/*virtual*/ void onPermissionsReceived(const LLSD& result);
+
+	// called when error occurs during permissions request
+	/*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason);
+
+	/*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url);
+
+	/*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason);
+
+	/*virtual*/ void onModelUploadSuccess();
+
+	/*virtual*/ void onModelUploadFailure();
+
+	const LLRect& getPreviewRect() const { return mPreviewRect; }
+
 	LLPhysicsDecomp::decomp_params mDecompParams;
 	std::set<LLPointer<DecompRequest> > mCurRequest;
 	std::string mStatusMessage;
@@ -80,13 +97,16 @@ class LLFloaterModelWizard : public LLFloater
 		CHOOSE_FILE = 0,
 		OPTIMIZE,
 		PHYSICS,
-		PHYSICS2,
 		REVIEW,
 		UPLOAD
 	};
 
 	void setState(int state);
 	void updateButtons();
+	void onClickSwitchToAdvanced();
+	void onClickRecalculateGeometry();
+	void onClickRecalculatePhysics();
+	void onClickCalculateUploadFee();
 	void onClickCancel();
 	void onClickBack();
 	void onClickNext();
@@ -94,7 +114,6 @@ class LLFloaterModelWizard : public LLFloater
 	bool onEnableBack();
 	void loadModel();
 	void onPreviewLODCommit(LLUICtrl*);
-	void onAccuracyPerformance(const LLSD& data);
 	void onUpload();
 
 	LLModelPreview*	mModelPreview;
@@ -106,7 +125,15 @@ class LLFloaterModelWizard : public LLFloater
 
 	U32			    mLastEnabledState;
 
+	LLButton*		mRecalculateGeometryBtn;
+	LLButton*		mRecalculatePhysicsBtn;
+	LLButton*		mRecalculatingPhysicsBtn;
+	LLButton*		mCalculateWeightsBtn;
+	LLButton*		mCalculatingWeightsBtn;
 
+	LLView*		mChooseFilePreviewPanel;
+	LLView*		mOptimizePreviewPanel;
+	LLView*		mPhysicsPreviewPanel;
 };
 
 
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 538c5e3b884de7997f791585408699921773bcc4..9a99417e9389cd23809f31abed4e745c8dd267f7 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -336,7 +336,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
 	LLViewerRegion* region = gAgent.getRegion();
 	BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
 
-	// *TODO: Replace parcing msg with accessing the region info model.
+	// *TODO: Replace parsing msg with accessing the region info model.
 	LLRegionInfoModel& region_info = LLRegionInfoModel::instance();
 
 	// extract message
@@ -368,6 +368,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
 		msg->getSize("RegionInfo2", "ProductName") > 0)
 	{
 		msg->getString("RegionInfo2", "ProductName", sim_type);
+		LLTrans::findString(sim_type, sim_type); // try localizing sim product name
 	}
 
 	// GENERAL PANEL
@@ -2409,11 +2410,7 @@ bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region)
 	}
 	
 	LLTextBox* region_landtype = getChild<LLTextBox>("region_landtype_text");
-	if (region_landtype)
-	{
-		region_landtype->setText(region->getSimProductName());
-	}
-	
+	region_landtype->setText(region->getLocalizedSimProductName());
 	
 	// let the parent class handle the general data collection. 
 	bool rv = LLPanelRegionInfo::refreshFromRegion(region);
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 33b7777d2efbf6b3d9b1102fee5076fbc449c406..84fb8bd9e7fb2d02d9f40ea6b7785fed3a39cd1f 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -36,7 +36,6 @@
 #include "llagentcamera.h"
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
-#include "llcombobox.h"
 #include "lldraghandle.h"
 #include "llerror.h"
 #include "llfloaterbuildoptions.h"
@@ -101,6 +100,7 @@ const std::string PANEL_NAMES[LLFloaterTools::PANEL_COUNT] =
 	std::string("Content"),	// PANEL_CONTENTS,
 };
 
+
 // Local prototypes
 void commit_select_component(void *data);
 void click_show_more(void*);
@@ -116,7 +116,6 @@ void commit_radio_group_focus(LLUICtrl* ctrl);
 void commit_radio_group_move(LLUICtrl* ctrl);
 void commit_radio_group_edit(LLUICtrl* ctrl);
 void commit_radio_group_land(LLUICtrl* ctrl);
-void commit_grid_mode(LLUICtrl *);
 void commit_slider_zoom(LLUICtrl *ctrl);
 
 
@@ -234,7 +233,6 @@ BOOL	LLFloaterTools::postBuild()
 	getChild<LLUICtrl>("checkbox uniform")->setValue((BOOL)gSavedSettings.getBOOL("ScaleUniform"));
 	mCheckStretchTexture	= getChild<LLCheckBoxCtrl>("checkbox stretch textures");
 	getChild<LLUICtrl>("checkbox stretch textures")->setValue((BOOL)gSavedSettings.getBOOL("ScaleStretchTextures"));
-	mComboGridMode			= getChild<LLComboBox>("combobox grid mode");
 	mCheckStretchUniformLabel = getChild<LLTextBox>("checkbox uniform label");
 
 	//
@@ -269,6 +267,8 @@ BOOL	LLFloaterTools::postBuild()
 	// the setting stores the actual force multiplier, but the slider is logarithmic, so we convert here
 	getChild<LLUICtrl>("slider force")->setValue(log10(gSavedSettings.getF32("LandBrushForce")));
 
+	mCostTextBorder = getChild<LLViewBorder>("cost_text_border");
+
 	mTab = getChild<LLTabContainer>("Object Info Tabs");
 	if(mTab)
 	{
@@ -311,7 +311,6 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
 	mCheckSnapToGrid(NULL),
 	mBtnGridOptions(NULL),
 	mTitleMedia(NULL),
-	mComboGridMode(NULL),
 	mCheckStretchUniform(NULL),
 	mCheckStretchTexture(NULL),
 	mCheckStretchUniformLabel(NULL),
@@ -344,6 +343,7 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
 	mPanelFace(NULL),
 	mPanelLandInfo(NULL),
 
+	mCostTextBorder(NULL),
 	mTabLand(NULL),
 	mDirty(TRUE),
 	mNeedMediaTitle(TRUE)
@@ -367,7 +367,6 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
 	mCommitCallbackRegistrar.add("BuildTool.selectComponent",	boost::bind(&commit_select_component, this));
 	mCommitCallbackRegistrar.add("BuildTool.gridOptions",		boost::bind(&LLFloaterTools::onClickGridOptions,this));
 	mCommitCallbackRegistrar.add("BuildTool.applyToSelection",	boost::bind(&click_apply_to_selection, this));
-	mCommitCallbackRegistrar.add("BuildTool.gridMode",			boost::bind(&commit_grid_mode,_1));
 	mCommitCallbackRegistrar.add("BuildTool.commitRadioLand",	boost::bind(&commit_radio_group_land,_1));
 	mCommitCallbackRegistrar.add("BuildTool.LandBrushForce",	boost::bind(&commit_slider_dozer_force,_1));
 	mCommitCallbackRegistrar.add("BuildTool.AddMedia",			boost::bind(&LLFloaterTools::onClickBtnAddMedia,this));
@@ -423,15 +422,15 @@ void LLFloaterTools::refresh()
 
 	// Refresh object and prim count labels
 	LLLocale locale(LLLocale::USER_LOCALE);
-
+#if 0
 	if (!gMeshRepo.meshRezEnabled())
 	{		
 		std::string obj_count_string;
 		LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount());
-		getChild<LLUICtrl>("obj_count")->setTextArg("[COUNT]", obj_count_string);	
+		getChild<LLUICtrl>("selection_count")->setTextArg("[OBJ_COUNT]", obj_count_string);
 		std::string prim_count_string;
 		LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount());
-		getChild<LLUICtrl>("prim_count")->setTextArg("[COUNT]", prim_count_string);
+		getChild<LLUICtrl>("selection_count")->setTextArg("[PRIM_COUNT]", prim_count_string);
 
 		// calculate selection rendering cost
 		if (sShowObjectCost)
@@ -448,56 +447,52 @@ void LLFloaterTools::refresh()
 		getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost);
 	}
 	else
+#endif
 	{
-		// Get the number of objects selected
-		std::string root_object_count_string;
-		std::string object_count_string;
-
-		LLResMgr::getInstance()->getIntegerString(
-			root_object_count_string,
-			LLSelectMgr::getInstance()->getSelection()->getRootObjectCount());
-		LLResMgr::getInstance()->getIntegerString(
-			object_count_string,
-			LLSelectMgr::getInstance()->getSelection()->getObjectCount());
-
-		F32 obj_cost =
-			LLSelectMgr::getInstance()->getSelection()->getSelectedObjectCost();
-		F32 link_cost =
-			LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost();
-		F32 obj_physics_cost =
-			LLSelectMgr::getInstance()->getSelection()->getSelectedPhysicsCost();
-		F32 link_physics_cost =
-			LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetPhysicsCost();
-
-		// Update the text for the counts
-		childSetTextArg(
-			"linked_set_count",
-			"[COUNT]",
-			root_object_count_string);
-		childSetTextArg("object_count", "[COUNT]", object_count_string);
-
-		// Update the text for the resource costs
-		childSetTextArg("linked_set_cost","[COST]",llformat("%.1f", link_cost));
-		childSetTextArg("object_cost", "[COST]", llformat("%.1f", obj_cost));
-		childSetTextArg("linked_set_cost","[PHYSICS]",llformat("%.1f", link_physics_cost));
-		childSetTextArg("object_cost", "[PHYSICS]", llformat("%.1f", obj_physics_cost));
-
-		// Display rendering cost if needed
-		if (sShowObjectCost)
+		F32 link_phys_cost  = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetPhysicsCost();
+		F32 link_cost  = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost();
+		S32 prim_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+		S32 link_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount();
+
+		LLStringUtil::format_map_t selection_args;
+		selection_args["OBJ_COUNT"] = llformat("%.1d", link_count);
+		selection_args["PRIM_COUNT"] = llformat("%.1d", prim_count);
+
+		std::ostringstream selection_info;
+
+		bool show_adv_weight = gSavedSettings.getBOOL("ShowAdvancedBuilderOptions");
+		bool show_mesh_cost = gMeshRepo.meshRezEnabled();
+
+		if (show_mesh_cost)
 		{
-			std::string prim_cost_string;
-			LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost());
-			getChild<LLUICtrl>("RenderingCost")->setTextArg("[COUNT]", prim_cost_string);
+			LLStringUtil::format_map_t prim_equiv_args;
+			prim_equiv_args["SEL_WEIGHT"] = llformat("%.1d", (S32)link_cost);
+			selection_args["PE_STRING"] = getString("status_selectprimequiv", prim_equiv_args);
+		}
+		else
+		{
+			selection_args["PE_STRING"] = "";
 		}
 
+		selection_info << getString("status_selectcount", selection_args);
 
-		// disable the object and prim counts if nothing selected
-		bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty();
-		childSetEnabled("linked_set_count", have_selection);
-		childSetEnabled("object_count", have_selection);
-		childSetEnabled("linked_set_cost", have_selection);
-		childSetEnabled("object_cost", have_selection);
-		getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost);
+		if (show_adv_weight)
+		{
+			selection_info << ",";
+
+			childSetTextArg("selection_weight", "[PHYS_WEIGHT]", llformat("%.1f", link_phys_cost));
+			childSetTextArg("selection_weight", "[DISP_WEIGHT]", llformat("%.1d", calcRenderCost()));
+		}
+		else
+		{
+			selection_info<<".";
+		}
+		getChild<LLTextBox>("selection_count")->setText(selection_info.str());
+
+		bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();
+		childSetVisible("selection_count",  have_selection);
+		childSetVisible("selection_weight", have_selection && show_adv_weight);
+		childSetVisible("selection_empty", !have_selection);
 	}
 
 
@@ -662,33 +657,6 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
 		mRadioGroupEdit->setValue("radio select face");
 	}
 
-	if (mComboGridMode) 
-	{
-		mComboGridMode->setVisible( edit_visible );
-		S32 index = mComboGridMode->getCurrentIndex();
-		mComboGridMode->removeall();
-
-		switch (mObjectSelection->getSelectType())
-		{
-		case SELECT_TYPE_HUD:
-		  mComboGridMode->add(getString("grid_screen_text"));
-		  mComboGridMode->add(getString("grid_local_text"));
-		  //mComboGridMode->add(getString("grid_reference_text"));
-		  break;
-		case SELECT_TYPE_WORLD:
-		  mComboGridMode->add(getString("grid_world_text"));
-		  mComboGridMode->add(getString("grid_local_text"));
-		  mComboGridMode->add(getString("grid_reference_text"));
-		  break;
-		case SELECT_TYPE_ATTACHMENT:
-		  mComboGridMode->add(getString("grid_attachment_text"));
-		  mComboGridMode->add(getString("grid_local_text"));
-		  mComboGridMode->add(getString("grid_reference_text"));
-		  break;
-		}
-
-		mComboGridMode->setCurrentByIndex(index);
-	}
 	// Snap to grid disabled for grab tool - very confusing
 	if (mCheckSnapToGrid) mCheckSnapToGrid->setVisible( edit_visible /* || tool == LLToolGrab::getInstance() */ );
 	if (mBtnGridOptions) mBtnGridOptions->setVisible( edit_visible /* || tool == LLToolGrab::getInstance() */ );
@@ -737,6 +705,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
 	// Land buttons
 	BOOL land_visible = (tool == LLToolBrushLand::getInstance() || tool == LLToolSelectLand::getInstance() );
 
+	mCostTextBorder->setVisible(!land_visible);
+
 	if (mBtnLand)	mBtnLand	->setToggleState( land_visible );
 
 	mRadioGroupLand->setVisible( land_visible );
@@ -789,15 +759,11 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
 		getChildView("Strength:")->setVisible( land_visible);
 	}
 
-	bool show_mesh_cost = gMeshRepo.meshRezEnabled();
+	bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();
 
-	getChildView("obj_count")->setVisible( !land_visible && !show_mesh_cost);
-	getChildView("prim_count")->setVisible( !land_visible && !show_mesh_cost);
-	getChildView("linked_set_count")->setVisible( !land_visible && show_mesh_cost);
-	getChildView("linked_set_cost")->setVisible( !land_visible && show_mesh_cost);
-	getChildView("object_count")->setVisible( !land_visible && show_mesh_cost);
-	getChildView("object_cost")->setVisible( !land_visible && show_mesh_cost);
-	getChildView("RenderingCost")->setVisible( !land_visible && sShowObjectCost);
+	getChildView("selection_count")->setVisible(!land_visible && have_selection);
+	getChildView("selection_weight")->setVisible(!land_visible && have_selection && gSavedSettings.getBOOL("ShowAdvancedBuilderOptions"));
+	getChildView("selection_empty")->setVisible(!land_visible && !have_selection);
 	
 	mTab->setVisible(!land_visible);
 	mPanelLandInfo->setVisible(land_visible);
@@ -1030,13 +996,6 @@ void commit_select_component(void *data)
 	}
 }
 
-void commit_grid_mode(LLUICtrl *ctrl)   
-{   
-	LLComboBox* combo = (LLComboBox*)ctrl;   
-    
-	LLSelectMgr::getInstance()->setGridMode((EGridMode)combo->getCurrentIndex());
-} 
-
 // static 
 void LLFloaterTools::setObjectType( LLPCode pcode )
 {
diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h
index fd81a75397f6e1f71c48deda06c30ce0cb56a53f..69636190fcf1c33558f45ffd38b9b5bc448ec547 100644
--- a/indra/newview/llfloatertools.h
+++ b/indra/newview/llfloatertools.h
@@ -32,7 +32,6 @@
 #include "llparcelselection.h"
 
 class LLButton;
-class LLComboBox;
 class LLCheckBoxCtrl;
 class LLPanelPermissions;
 class LLPanelObject;
@@ -140,7 +139,6 @@ class LLFloaterTools
 
 	LLCheckBoxCtrl*	mCheckSnapToGrid;
 	LLButton*		mBtnGridOptions;
-	LLComboBox*		mComboGridMode;
 	LLCheckBoxCtrl*	mCheckStretchUniform;
 	LLCheckBoxCtrl*	mCheckStretchTexture;
 
@@ -179,6 +177,8 @@ class LLFloaterTools
 	LLPanelFace				*mPanelFace;
 	LLPanelLandInfo			*mPanelLandInfo;
 
+	LLViewBorder*			mCostTextBorder;
+
 	LLTabContainer*			mTabLand;
 
 	LLParcelSelectionHandle	mParcelSelection;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 6e0722bcf99fa46771bbbd90fd2c738c654a6c6a..afed306a28fa343b593453d0b8dc3c1c883b11f4 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -34,9 +34,9 @@
 #include "llagent.h"
 #include "llappviewer.h"
 #include "llbufferstream.h"
+#include "llcallbacklist.h"
 #include "llcurl.h"
 #include "lldatapacker.h"
-#include "llfasttimer.h"
 #include "llfloatermodelpreview.h"
 #include "llfloaterperms.h"
 #include "lleconomy.h"
@@ -49,6 +49,7 @@
 #include "llthread.h"
 #include "llvfile.h"
 #include "llviewercontrol.h"
+#include "llviewerinventory.h"
 #include "llviewermenufile.h"
 #include "llviewerobjectlist.h"
 #include "llviewerregion.h"
@@ -62,6 +63,7 @@
 #include "llinventorymodel.h"
 #include "llfoldertype.h"
 #include "llviewerparcelmgr.h"
+#include "lluploadfloaterobservers.h"
 
 #include "boost/lexical_cast.hpp"
 
@@ -71,13 +73,18 @@
 
 #include <queue>
 
-LLFastTimer::DeclareTimer FTM_MESH_UPDATE("Mesh Update");
-LLFastTimer::DeclareTimer FTM_LOAD_MESH("Load Mesh");
-
 LLMeshRepository gMeshRepo;
 
 const U32 MAX_MESH_REQUESTS_PER_SECOND = 100;
 
+// Maximum mesh version to support.  Three least significant digits are reserved for the minor version, 
+// with major version changes indicating a format change that is not backwards compatible and should not
+// be parsed by viewers that don't specifically support that version. For example, if the integer "1" is 
+// present, the version is 0.001. A viewer that can parse version 0.001 can also parse versions up to 0.999, 
+// but not 1.0 (integer 1000).
+// See wiki at https://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format
+const S32 MAX_MESH_VERSION = 999;
+
 U32 LLMeshRepository::sBytesReceived = 0;
 U32 LLMeshRepository::sHTTPRequestCount = 0;
 U32 LLMeshRepository::sHTTPRetryCount = 0;
@@ -190,196 +197,6 @@ S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
 S32 LLMeshRepoThread::sActiveLODRequests = 0;
 U32	LLMeshRepoThread::sMaxConcurrentRequests = 1;
 
-
-class LLTextureCostResponder : public LLCurl::Responder
-{
-public:
-	LLTextureUploadData mData;
-	LLMeshUploadThread* mThread;
-
-	LLTextureCostResponder(LLTextureUploadData data, LLMeshUploadThread* thread) 
-		: mData(data), mThread(thread)
-	{
-
-	}
-
-	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
-	{
-		mThread->mPendingConfirmations--;
-		if (isGoodStatus(status))
-		{
-			mThread->priceResult(mData, content);	
-		}
-		else
-		{
-			llwarns << status << ": " << reason << llendl;
-
-			if (mData.mRetries < MAX_TEXTURE_UPLOAD_RETRIES)
-			{
-				llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
-			
-				if (status == 499 || status == 500)
-				{
-					mThread->uploadTexture(mData);
-				}
-				else
-				{
-					llerrs << "Unhandled status " << status << llendl;
-				}
-			}
-			else
-			{ 
-				llwarns << "Giving up after " << mData.mRetries << " retries." << llendl;
-			}
-		}
-	}
-};
-
-class LLTextureUploadResponder : public LLCurl::Responder
-{
-public:
-	LLTextureUploadData mData;
-	LLMeshUploadThread* mThread;
-
-	LLTextureUploadResponder(LLTextureUploadData data, LLMeshUploadThread* thread)
-		: mData(data), mThread(thread)
-	{
-	}
-
-	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
-	{
-		mThread->mPendingUploads--;
-		if (isGoodStatus(status))
-		{
-			mData.mUUID = content["new_asset"].asUUID();
-			gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mData.mPostData, content));
-			mThread->onTextureUploaded(mData);
-		}
-		else
-		{
-			llwarns << status << ": " << reason << llendl;
-			llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
-
-			if (status == 404)
-			{
-				mThread->uploadTexture(mData);
-			}
-			else if (status == 499)
-			{
-				mThread->mConfirmedTextureQ.push(mData);
-			}
-			else
-			{
-				llerrs << "Unhandled status " << status << llendl;
-			}
-		}
-	}
-};
-
-class LLMeshCostResponder : public LLCurl::Responder
-{
-public:
-	LLMeshUploadData mData;
-	LLMeshUploadThread* mThread;
-
-	LLMeshCostResponder(LLMeshUploadData data, LLMeshUploadThread* thread) 
-		: mData(data), mThread(thread)
-	{
-
-	}
-
-	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
-	{
-		mThread->mPendingConfirmations--;
-
-		if (isGoodStatus(status))
-		{
-			mThread->priceResult(mData, content);	
-		}
-		else
-		{
-			llwarns << status << ": " << reason << llendl;			
-			
-			if (status == HTTP_INTERNAL_ERROR)
-			{
-				llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
-				mThread->uploadModel(mData);
-			}
-			else if (status == HTTP_BAD_REQUEST)
-			{
-				llwarns << "Status 400 received from server, giving up." << llendl;
-			}
-			else if (status == HTTP_NOT_FOUND)
-			{
-				llwarns <<"Status 404 received, server is disconnected, giving up." << llendl ;
-			}
-			else
-			{
-				llerrs << "Unhandled status " << status << llendl;
-			}
-		}
-	}
-};
-
-class LLMeshUploadResponder : public LLCurl::Responder
-{
-public:
-	LLMeshUploadData mData;
-	LLMeshUploadThread* mThread;
-
-	LLMeshUploadResponder(LLMeshUploadData data, LLMeshUploadThread* thread)
-		: mData(data), mThread(thread)
-	{
-	}
-
-	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
-	{
-		mThread->mPendingUploads--;
-		if (isGoodStatus(status))
-		{
-			mData.mUUID = content["new_asset"].asUUID();
-			if (mData.mUUID.isNull())
-			{
-				LLSD args;
-				std::string message = content["error"]["message"];
-				std::string identifier = content["error"]["identifier"];
-				std::string invalidity_identifier = content["error"]["invalidity_identifier"];
-
-				args["MESSAGE"] = message;
-				args["IDENTIFIER"] = identifier;
-				args["INVALIDITY_IDENTIFIER"] = invalidity_identifier;
-				args["LABEL"] = mData.mBaseModel->mLabel;
-
-				gMeshRepo.uploadError(args);
-			}
-			else
-			{
-				gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mData.mPostData, content));
-				mThread->onModelUploaded(mData);
-			}
-		}
-		else
-		{
-			llwarns << status << ": " << reason << llendl;
-			llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
-
-			if (status == 404)
-			{
-				mThread->uploadModel(mData);
-			}
-			else if (status == 499)
-			{
-				mThread->mConfirmedQ.push(mData);
-			}
-			else if (status != 500)
-			{ //drop internal server errors on the floor, otherwise grab
-				llerrs << "Unhandled status " << status << llendl;
-			}
-		}
-	}
-};
-
-
 class LLMeshHeaderResponder : public LLCurl::Responder
 {
 public:
@@ -518,38 +335,16 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s
 	}
 }
 
-class LLModelObjectUploadResponder: public LLCurl::Responder
-{
-	LLSD mObjectAsset;
-	LLMeshUploadThread* mThread;
-
-public:
-	LLModelObjectUploadResponder(LLMeshUploadThread* thread, const LLSD& object_asset):
-		mThread(thread),
-		mObjectAsset(object_asset)
-	{
-	}
-
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
-	{
-		assert_main_thread();
-		
-		llinfos << "completed" << llendl;
-		mThread->mPendingUploads--;
-		mThread->mFinished = true;
-	}
-};
-
 class LLWholeModelFeeResponder: public LLCurl::Responder
 {
 	LLMeshUploadThread* mThread;
 	LLSD mModelData;
+	LLHandle<LLWholeModelFeeObserver> mObserverHandle;
 public:
-	LLWholeModelFeeResponder(LLMeshUploadThread* thread, LLSD& model_data):
+	LLWholeModelFeeResponder(LLMeshUploadThread* thread, LLSD& model_data, LLHandle<LLWholeModelFeeObserver> observer_handle):
 		mThread(thread),
-		mModelData(model_data)
+		mModelData(model_data),
+		mObserverHandle(observer_handle)
 	{
 	}
 	virtual void completed(U32 status,
@@ -562,20 +357,32 @@ class LLWholeModelFeeResponder: public LLCurl::Responder
 			cc = llsd_from_file("fake_upload_error.xml");
 		}
 			
-		llinfos << "completed" << llendl;
 		mThread->mPendingUploads--;
 		dump_llsd_to_file(cc,make_dump_name("whole_model_fee_response_",dump_num));
+
+		LLWholeModelFeeObserver* observer = mObserverHandle.get();
+
 		if (isGoodStatus(status) &&
 			cc["state"].asString() == "upload")
 		{
-			llinfos << "fee request succeeded" << llendl;
-			mThread->mWholeModelUploadURL = cc["uploader"].asString(); 
+			mThread->mWholeModelUploadURL = cc["uploader"].asString();
+
+			if (observer)
+			{
+				cc["data"]["upload_price"] = cc["upload_price"];
+				observer->onModelPhysicsFeeReceived(cc["data"], mThread->mWholeModelUploadURL);
+			}
 		}
 		else
 		{
 			llwarns << "fee request failed" << llendl;
 			log_upload_error(status,cc,"fee",mModelData["name"]);
 			mThread->mWholeModelUploadURL = "";
+
+			if (observer)
+			{
+				observer->setModelPhysicsFeeErrorStatus(status, reason);
+			}
 		}
 	}
 
@@ -585,11 +392,13 @@ class LLWholeModelUploadResponder: public LLCurl::Responder
 {
 	LLMeshUploadThread* mThread;
 	LLSD mModelData;
+	LLHandle<LLWholeModelUploadObserver> mObserverHandle;
 	
 public:
-	LLWholeModelUploadResponder(LLMeshUploadThread* thread, LLSD& model_data):
+	LLWholeModelUploadResponder(LLMeshUploadThread* thread, LLSD& model_data, LLHandle<LLWholeModelUploadObserver> observer_handle):
 		mThread(thread),
-		mModelData(model_data)
+		mModelData(model_data),
+		mObserverHandle(observer_handle)
 	{
 	}
 	virtual void completed(U32 status,
@@ -605,21 +414,32 @@ class LLWholeModelUploadResponder: public LLCurl::Responder
 		//assert_main_thread();
 		mThread->mPendingUploads--;
 		dump_llsd_to_file(cc,make_dump_name("whole_model_upload_response_",dump_num));
-		llinfos << "LLWholeModelUploadResponder content: " << cc << llendl;
+		
+		LLWholeModelUploadObserver* observer = mObserverHandle.get();
+
 		// requested "mesh" asset type isn't actually the type
 		// of the resultant object, fix it up here.
 		if (isGoodStatus(status) &&
 			cc["state"].asString() == "complete")
 		{
-			llinfos << "upload succeeded" << llendl;
 			mModelData["asset_type"] = "object";
 			gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mModelData,cc));
+
+			if (observer)
+			{
+				doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadSuccess, observer));
+			}
 		}
 		else
 		{
 			llwarns << "upload failed" << llendl;
 			std::string model_name = mModelData["name"].asString();
 			log_upload_error(status,cc,"upload",model_name);
+
+			if (observer)
+			{
+				doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadFailure, observer));
+			}
 		}
 	}
 };
@@ -840,15 +660,16 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
 	}
 
 	U32 header_size = mMeshHeaderSize[mesh_id];
-
+	
 	if (header_size > 0)
 	{
+		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 		S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger();
 		S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger();
 
 		mHeaderMutex->unlock();
 
-		if (offset >= 0 && size > 0)
+		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 		{
 			//check VFS for mesh skin info
 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
@@ -859,7 +680,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
 				U8* buffer = new U8[size];
 				file.read(buffer, size);
 
-				//make sure buffer isn't all 0's (reserved block but not written)
+				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 				bool zero = true;
 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 				{
@@ -915,12 +736,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
 
 	if (header_size > 0)
 	{
+		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 		S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger();
 		S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger();
 
 		mHeaderMutex->unlock();
 
-		if (offset >= 0 && size > 0)
+		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 		{
 			//check VFS for mesh skin info
 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
@@ -931,7 +753,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
 				U8* buffer = new U8[size];
 				file.read(buffer, size);
 
-				//make sure buffer isn't all 0's (reserved block but not written)
+				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 				bool zero = true;
 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 				{
@@ -987,12 +809,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 
 	if (header_size > 0)
 	{
+		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 		S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger();
 		S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger();
 
 		mHeaderMutex->unlock();
 
-		if (offset >= 0 && size > 0)
+		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 		{
 			//check VFS for mesh physics shape info
 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
@@ -1003,7 +826,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 				U8* buffer = new U8[size];
 				file.read(buffer, size);
 
-				//make sure buffer isn't all 0's (reserved block but not written)
+				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 				bool zero = true;
 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 				{
@@ -1060,9 +883,9 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
 		S32 size = file.getSize();
 
 		if (size > 0)
-		{
-			U8 buffer[1024];
-			S32 bytes = llmin(size, 1024);
+		{ //NOTE -- if the header size is ever more than 4KB, this will break
+			U8 buffer[4096];
+			S32 bytes = llmin(size, 4096);
 			LLMeshRepository::sCacheBytesRead += bytes;	
 			file.read(buffer, bytes);
 			if (headerReceived(mesh_params, buffer, bytes))
@@ -1084,6 +907,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
 		retval = true;
 		//grab first 4KB if we're going to bother with a fetch.  Cache will prevent future fetches if a full mesh fits
 		//within the first 4KB
+		//NOTE -- this will break of headers ever exceed 4KB
 		LLMeshRepository::sHTTPRequestCount++;
 		mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params));
 	}
@@ -1103,10 +927,12 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
 
 	if (header_size > 0)
 	{
+		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 		S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger();
 		S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger();
 		mHeaderMutex->unlock();
-		if (offset >= 0 && size > 0)
+				
+		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 		{
 
 			//check VFS for mesh asset
@@ -1118,7 +944,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
 				U8* buffer = new U8[size];
 				file.read(buffer, size);
 
-				//make sure buffer isn't all 0's (reserved block but not written)
+				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 				bool zero = true;
 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 				{
@@ -1204,14 +1030,11 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat
 	}
 
 	{
-		U32 cost = gMeshRepo.calcResourceCost(header);
-
 		LLUUID mesh_id = mesh_params.getSculptID();
 		
 		mHeaderMutex->lock();
 		mMeshHeaderSize[mesh_id] = header_size;
 		mMeshHeader[mesh_id] = header;
-		mMeshResourceCost[mesh_id] = cost;
 		mHeaderMutex->unlock();
 
 		//check for pending requests
@@ -1363,9 +1186,14 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32
 }
 
 LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,
-										bool upload_skin, bool upload_joints)
+										bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
+					   LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
 : LLThread("mesh upload"),
-	mDiscarded(FALSE)
+	mDiscarded(FALSE),
+	mDoUpload(do_upload),
+	mWholeModelUploadURL(upload_url),
+	mFeeObserverHandle(fee_observer),
+	mUploadObserverHandle(upload_observer)
 {
 	mInstanceList = data;
 	mUploadTextures = upload_textures;
@@ -1373,9 +1201,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
 	mUploadJoints = upload_joints;
 	mMutex = new LLMutex(NULL);
 	mCurlRequest = NULL;
-	mPendingConfirmations = 0;
 	mPendingUploads = 0;
-	mPendingCost = 0;
 	mFinished = false;
 	mOrigin = gAgent.getPositionAgent();
 	mHost = gAgent.getRegionHost();
@@ -1383,6 +1209,8 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
 	mWholeModelFeeCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory");
 
 	mOrigin += gAgent.getAtAxis() * scale.magVec();
+
+	mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ;
 }
 
 LLMeshUploadThread::~LLMeshUploadThread()
@@ -1441,7 +1269,14 @@ BOOL LLMeshUploadThread::isDiscarded()
 
 void LLMeshUploadThread::run()
 {
-	doWholeModelUpload();
+	if (mDoUpload)
+	{
+		doWholeModelUpload();
+	}
+	else
+	{
+		requestWholeModelFee();
+	}
 }
 
 void dump_llsd_to_file(const LLSD& content, std::string filename)
@@ -1467,10 +1302,13 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 
 	LLSD res;
 	result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+	result["texture_folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE);
 	result["asset_type"] = "mesh";
 	result["inventory_type"] = "object";
-	result["name"] = "mesh model";
-	result["description"] = "your description here";
+	result["description"] = "(No Description)";
+	result["next_owner_mask"] = LLSD::Integer(LLFloaterPerms::getNextOwnerPerms());
+	result["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms());
+	result["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms());
 
 	res["mesh_list"] = LLSD::emptyArray();
 	res["texture_list"] = LLSD::emptyArray();
@@ -1482,6 +1320,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 	std::map<LLViewerTexture*,S32> texture_index;
 
 	std::map<LLModel*,S32> mesh_index;
+	std::string model_name;
 
 	S32 instance_num = 0;
 	
@@ -1498,10 +1337,9 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 		if (mesh_index.find(data.mBaseModel) == mesh_index.end())
 		{
 			// Have not seen this model before - create a new mesh_list entry for it.
-			std::string model_name = data.mBaseModel->getName();
-			if (!model_name.empty())
+			if (model_name.empty())
 			{
-				result["name"] = model_name;
+				model_name = data.mBaseModel->getName();
 			}
 
 			std::stringstream ostr;
@@ -1556,24 +1394,15 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 			instance_entry["scale"] = ll_sd_from_vector3(scale);
 		
 			instance_entry["material"] = LL_MCODE_WOOD;
-			LLPermissions perm;
-			perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false);
-			perm.setCreator(gAgent.getID());
-		
-			perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base
-						   PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner
-						   LLFloaterPerms::getEveryonePerms(),
-						   LLFloaterPerms::getGroupPerms(),
-						   LLFloaterPerms::getNextOwnerPerms());
-			instance_entry["permissions"] = ll_create_sd_from_permissions(perm);
 			instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
 			instance_entry["mesh"] = mesh_index[data.mBaseModel];
 
 			instance_entry["face_list"] = LLSD::emptyArray();
 
-			for (S32 face_num = 0; face_num < data.mBaseModel->getNumVolumeFaces(); face_num++)
+			S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ;
+			for (S32 face_num = 0; face_num < end; face_num++)
 			{
-				LLImportMaterial& material = instance.mMaterial[face_num];
+				LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
 				LLSD face_entry = LLSD::emptyMap();
 				LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
 				
@@ -1624,75 +1453,66 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 		}
 	}
 
+	if (model_name.empty()) model_name = "mesh model";
+	result["name"] = model_name;
 	result["asset_resources"] = res;
 	dump_llsd_to_file(result,make_dump_name("whole_model_",dump_num));
 
 	dest = result;
 }
 
-void LLMeshUploadThread::doWholeModelUpload()
+void LLMeshUploadThread::generateHulls()
 {
-	dump_num++;
-	
-	mCurlRequest = new LLCurlRequest();	
-
-	// Queue up models for hull generation (viewer-side)
 	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
-	{
-		LLMeshUploadData data;
-		data.mBaseModel = iter->first;
-
-		LLModelInstance& instance = *(iter->second.begin());
-
-		for (S32 i = 0; i < 5; i++)
 		{
-			data.mModel[i] = instance.mLOD[i];
-		}
+			LLMeshUploadData data;
+			data.mBaseModel = iter->first;
 
-		//queue up models for hull generation
-		LLModel* physics = NULL;
+			LLModelInstance& instance = *(iter->second.begin());
 
-		if (data.mModel[LLModel::LOD_PHYSICS].notNull())
-		{
-			physics = data.mModel[LLModel::LOD_PHYSICS];
-		}
-		else if (data.mModel[LLModel::LOD_MEDIUM].notNull())
-		{
-			physics = data.mModel[LLModel::LOD_MEDIUM];
-		}
-		else
-		{
-			physics = data.mModel[LLModel::LOD_HIGH];
-		}
+			for (S32 i = 0; i < 5; i++)
+			{
+				data.mModel[i] = instance.mLOD[i];
+			}
 
-		llassert(physics != NULL);
-		
-		DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this);
-		if(request->isValid())
-		{
-			gMeshRepo.mDecompThread->submitRequest(request);
-		}		
-	}
+			//queue up models for hull generation
+			LLModel* physics = NULL;
 
-	while (!mPhysicsComplete)
-	{
-		apr_sleep(100);
-	}
+			if (data.mModel[LLModel::LOD_PHYSICS].notNull())
+			{
+				physics = data.mModel[LLModel::LOD_PHYSICS];
+			}
+			else if (data.mModel[LLModel::LOD_LOW].notNull())
+			{
+				physics = data.mModel[LLModel::LOD_LOW];
+			}
+			else if (data.mModel[LLModel::LOD_MEDIUM].notNull())
+			{
+				physics = data.mModel[LLModel::LOD_MEDIUM];
+			}
+			else
+			{
+				physics = data.mModel[LLModel::LOD_HIGH];
+			}
 
-	LLSD model_data;
-	wholeModelToLLSD(model_data,false);
-	dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num));
+			llassert(physics != NULL);
 
-	mPendingUploads++;
-	LLCurlRequest::headers_t headers;
-	mCurlRequest->post(mWholeModelFeeCapability, headers, model_data,
-					   new LLWholeModelFeeResponder(this,model_data));
+			DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this);
+			if(request->isValid())
+			{
+				gMeshRepo.mDecompThread->submitRequest(request);
+			}
+		}
 
-	do
-	{
-		mCurlRequest->process();
-	} while (mCurlRequest->getQueued() > 0);
+		while (!mPhysicsComplete)
+		{
+			apr_sleep(100);
+		}
+}
 
+void LLMeshUploadThread::doWholeModelUpload()
+{
+	mCurlRequest = new LLCurlRequest();
 
 	if (mWholeModelUploadURL.empty())
 	{
@@ -1700,15 +1520,20 @@ void LLMeshUploadThread::doWholeModelUpload()
 	}
 	else
 	{
+		generateHulls();
+
 		LLSD full_model_data;
 		wholeModelToLLSD(full_model_data, true);
 		LLSD body = full_model_data["asset_resources"];
 		dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num));
+		LLCurlRequest::headers_t headers;
 		mCurlRequest->post(mWholeModelUploadURL, headers, body,
-						   new LLWholeModelUploadResponder(this, model_data));
+						   new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle), mMeshUploadTimeOut);
 		do
 		{
 			mCurlRequest->process();
+			//sleep for 10ms to prevent eating a whole core
+			apr_sleep(10000);
 		} while (mCurlRequest->getQueued() > 0);
 	}
 
@@ -1719,22 +1544,36 @@ void LLMeshUploadThread::doWholeModelUpload()
 	mFinished = true;
 }
 
-void LLMeshUploadThread::uploadModel(LLMeshUploadData& data)
-{ //called from arbitrary thread
-	{
-		LLMutexLock lock(mMutex);
-		mUploadQ.push(data);
-	}
-}
+void LLMeshUploadThread::requestWholeModelFee()
+{
+	dump_num++;
 
-void LLMeshUploadThread::uploadTexture(LLTextureUploadData& data)
-{ //called from mesh upload thread
-	mTextureQ.push(data);	
-}
+	mCurlRequest = new LLCurlRequest();
+
+	generateHulls();
+
+	LLSD model_data;
+	wholeModelToLLSD(model_data,false);
+	dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num));
 
+	mPendingUploads++;
+	LLCurlRequest::headers_t headers;
+	mCurlRequest->post(mWholeModelFeeCapability, headers, model_data,
+					   new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle), mMeshUploadTimeOut);
 
-static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_LOADED("Notify Loaded");
-static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_UNAVAILABLE("Notify Unavailable");
+	do
+	{
+		mCurlRequest->process();
+		//sleep for 10ms to prevent eating a whole core
+		apr_sleep(10000);
+	} while (mCurlRequest->getQueued() > 0);
+
+	delete mCurlRequest;
+	mCurlRequest = NULL;
+
+	// Currently a no-op.
+	mFinished = true;
+}
 
 void LLMeshRepoThread::notifyLoadedMeshes()
 {
@@ -1799,7 +1638,9 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
 {
 	lod = llclamp(lod, 0, 3);
 
-	if (header.has("404"))
+	S32 version = header["version"];
+
+	if (header.has("404") || version > MAX_MESH_VERSION)
 	{
 		return -1;
 	}
@@ -1832,19 +1673,6 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
 	return -1;
 }
 
-U32 LLMeshRepoThread::getResourceCost(const LLUUID& mesh_id)
-{
-	LLMutexLock lock(mHeaderMutex);
-	
-	std::map<LLUUID, U32>::iterator iter = mMeshResourceCost.find(mesh_id);
-	if (iter != mMeshResourceCost.end())
-	{
-		return iter->second;
-	}
-
-	return 0;
-}
-
 void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
 {
 	mThread->mMeshHeader[data.mUUID] = header;
@@ -2135,54 +1963,54 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 		LLUUID mesh_id = mMeshParams.getSculptID();
 		LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id];
 
-		std::stringstream str;
+		S32 version = header["version"].asInteger();
+
+		if (version <= MAX_MESH_VERSION)
+		{
+			std::stringstream str;
 
-		S32 lod_bytes = 0;
+			S32 lod_bytes = 0;
 
-		for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i)
-		{ //figure out how many bytes we'll need to reserve in the file
-			std::string lod_name = header_lod[i];
-			lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
-		}
+			for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i)
+			{ //figure out how many bytes we'll need to reserve in the file
+				std::string lod_name = header_lod[i];
+				lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
+			}
 		
-		//just in case skin info or decomposition is at the end of the file (which it shouldn't be)
-		lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
-		lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
+			//just in case skin info or decomposition is at the end of the file (which it shouldn't be)
+			lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
+			lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
 
-		S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
-		S32 bytes = lod_bytes + header_bytes; 
+			S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
+			S32 bytes = lod_bytes + header_bytes; 
 
 		
-		//it's possible for the remote asset to have more data than is needed for the local cache
-		//only allocate as much space in the VFS as is needed for the local cache
-		data_size = llmin(data_size, bytes);
+			//it's possible for the remote asset to have more data than is needed for the local cache
+			//only allocate as much space in the VFS as is needed for the local cache
+			data_size = llmin(data_size, bytes);
 
-		LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE);
-		if (file.getMaxSize() >= bytes || file.setMaxSize(bytes))
-		{
-			LLMeshRepository::sCacheBytesWritten += data_size;
+			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE);
+			if (file.getMaxSize() >= bytes || file.setMaxSize(bytes))
+			{
+				LLMeshRepository::sCacheBytesWritten += data_size;
 
-			file.write((const U8*) data, data_size);
+				file.write((const U8*) data, data_size);
 			
-			//zero out the rest of the file 
-			U8 block[4096];
-			memset(block, 0, 4096);
-
-			while (bytes-file.tell() > 4096)
-			{
-				file.write(block, 4096);
-			}
+				//zero out the rest of the file 
+				U8 block[4096];
+				memset(block, 0, 4096);
 
-			S32 remaining = bytes-file.tell();
+				while (bytes-file.tell() > 4096)
+				{
+					file.write(block, 4096);
+				}
 
-			if (remaining < 0 || remaining > 4096)
-			{
-				llerrs << "Bad padding of mesh asset cache entry." << llendl;
-			}
+				S32 remaining = bytes-file.tell();
 
-			if (remaining > 0)
-			{
-				file.write(block, remaining);
+				if (remaining > 0)
+				{
+					file.write(block, remaining);
+				}
 			}
 		}
 	}
@@ -2292,8 +2120,6 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 		return detail;
 	}
 
-	LLFastTimer t(FTM_LOAD_MESH); 
-
 	{
 		LLMutexLock lock(mMeshMutex);
 		//add volume to list of loading meshes
@@ -2369,11 +2195,6 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 	return detail;
 }
 
-static LLFastTimer::DeclareTimer FTM_START_MESH_THREAD("Start Thread");
-static LLFastTimer::DeclareTimer FTM_LOAD_MESH_LOD("Load LOD");
-static LLFastTimer::DeclareTimer FTM_MESH_LOCK1("Lock 1");
-static LLFastTimer::DeclareTimer FTM_MESH_LOCK2("Lock 2");
-
 void LLMeshRepository::notifyLoadedMeshes()
 { //called from main thread
 
@@ -2406,6 +2227,38 @@ void LLMeshRepository::notifyLoadedMeshes()
 			LLAssetType::EType asset_type = LLAssetType::lookup(data.mPostData["asset_type"].asString());
 			LLInventoryType::EType inventory_type = LLInventoryType::lookup(data.mPostData["inventory_type"].asString());
 
+			// Handle addition of texture, if any.
+			if ( data.mResponse.has("new_texture_folder_id") )
+			{
+				const LLUUID& folder_id = data.mResponse["new_texture_folder_id"].asUUID();
+
+				if ( folder_id.notNull() )
+				{
+					LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE);
+
+					std::string name;
+					// Check if the server built a different name for the texture folder
+					if ( data.mResponse.has("new_texture_folder_name") )
+					{
+						name = data.mResponse["new_texture_folder_name"].asString();
+					}
+					else
+					{
+						name = data.mPostData["name"].asString();
+					}
+
+					// Add the category to the internal representation
+					LLPointer<LLViewerInventoryCategory> cat = 
+						new LLViewerInventoryCategory(folder_id, parent_id, 
+							LLFolderType::FT_NONE, name, gAgent.getID());
+					cat->setVersion(LLViewerInventoryCategory::VERSION_UNKNOWN);
+
+					LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
+					gInventory.accountForUpdate(update);
+					gInventory.updateCategory(cat);
+				}
+			}
+
 			on_new_single_inventory_upload_complete(
 				asset_type,
 				inventory_type,
@@ -2414,7 +2267,8 @@ void LLMeshRepository::notifyLoadedMeshes()
 				data.mPostData["name"],
 				data.mPostData["description"],
 				data.mResponse,
-				0);
+				data.mResponse["upload_price"]);
+			//}
 			
 			mInventoryQ.pop();
 		}
@@ -2439,18 +2293,9 @@ void LLMeshRepository::notifyLoadedMeshes()
 		}
 	}
 
-	LLFastTimer t(FTM_MESH_UPDATE);
-
-	{
-		LLFastTimer t(FTM_MESH_LOCK1);
-		mMeshMutex->lock();	
-	}
-
-	{
-		LLFastTimer t(FTM_MESH_LOCK2);
-		mThread->mMutex->lock();
-	}
-	
+	mMeshMutex->lock();	
+	mThread->mMutex->lock();
+		
 	//popup queued error messages from background threads
 	while (!mUploadErrorQ.empty())
 	{
@@ -2502,7 +2347,6 @@ void LLMeshRepository::notifyLoadedMeshes()
 
 		while (!mPendingRequests.empty() && push_count > 0)
 		{
-			LLFastTimer t(FTM_LOAD_MESH_LOD);
 			LLMeshRepoThread::LODRequest& request = mPendingRequests.front();
 			mThread->loadMeshLOD(request.mMeshParams, request.mLOD);
 			mPendingRequests.erase(mPendingRequests.begin());
@@ -2652,25 +2496,6 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
 	return mThread->getActualMeshLOD(mesh_params, lod);
 }
 
-U32 LLMeshRepository::calcResourceCost(LLSD& header)
-{
-	U32 bytes = 0;
-
-	for (U32 i = 0; i < 4; i++)
-	{
-		bytes += header[header_lod[i]]["size"].asInteger();
-	}
-
-	bytes += header["skin"]["size"].asInteger();
-
-	return bytes/4096 + 1;
-}
-
-U32 LLMeshRepository::getResourceCost(const LLUUID& mesh_id)
-{
-	return mThread->getResourceCost(mesh_id);
-}
-
 const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj)
 {
 	if (mesh_id.notNull())
@@ -2809,9 +2634,11 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
 
 
 void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
-									bool upload_skin, bool upload_joints)
+									bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
+								   LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
 {
-	LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints);
+	LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url, 
+														do_upload, fee_observer, upload_observer);
 	mUploadWaitList.push_back(thread);
 }
 
@@ -2839,101 +2666,6 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)
 
 }
 
-
-void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)
-{
-	if(isDiscarded())
-	{
-		return ;
-	}
-
-	if (!data.mRSVP.empty())
-	{
-		std::stringstream ostr;
-
-		LLModel::Decomposition& decomp =
-			data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
-			data.mModel[LLModel::LOD_PHYSICS]->mPhysics : 
-			data.mBaseModel->mPhysics;
-
-		decomp.mBaseHull = mHullMap[data.mBaseModel];
-
-		LLModel::writeModel(
-			ostr,  
-			data.mModel[LLModel::LOD_PHYSICS],
-			data.mModel[LLModel::LOD_HIGH],
-			data.mModel[LLModel::LOD_MEDIUM],
-			data.mModel[LLModel::LOD_LOW],
-			data.mModel[LLModel::LOD_IMPOSTOR], 
-			decomp,
-			mUploadSkin,
-			mUploadJoints);
-
-		data.mAssetData = ostr.str();
-
-		LLCurlRequest::headers_t headers;
-		mPendingUploads++;
-
-		mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLMeshUploadResponder(data, this));
-	}
-}
-
-void LLMeshUploadThread::doUploadTexture(LLTextureUploadData& data)
-{
-	if(isDiscarded())
-	{
-		return ;
-	}
-
-	if (!data.mRSVP.empty())
-	{
-		std::stringstream ostr;
-		
-		if (!data.mTexture->isRawImageValid())
-		{
-			data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel());
-		}
-
-		if(data.mTexture->hasSavedRawImage())
-		{
-			LLPointer<LLImageJ2C> upload_file = LLViewerTextureList::convertToUploadFile(data.mTexture->getSavedRawImage());
-		
-			ostr.write((const char*) upload_file->getData(), upload_file->getDataSize());
-		}
-
-		data.mAssetData = ostr.str();
-
-		LLCurlRequest::headers_t headers;
-		mPendingUploads++;
-
-		mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLTextureUploadResponder(data, this));
-	}
-}
-
-
-void LLMeshUploadThread::onModelUploaded(LLMeshUploadData& data)
-{
-	createObjects(data);
-}
-
-void LLMeshUploadThread::onTextureUploaded(LLTextureUploadData& data)
-{
-	mTextureMap[data.mTexture] = data;
-}
-
-
-void LLMeshUploadThread::createObjects(LLMeshUploadData& data)
-{
-	instance_list& instances = mInstance[data.mBaseModel];
-
-	for (instance_list::iterator iter = instances.begin(); iter != instances.end(); ++iter)
-	{ //create prims that reference given mesh
-		LLModelInstance& instance = *iter;
-		instance.mMeshID = data.mUUID;
-		mInstanceQ.push(instance);
-	}
-}
-
 void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,
 											 LLVector3& result_pos,
 											 LLQuaternion& result_rot,
@@ -2974,147 +2706,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,
 	result_rot = quat_rotation; 
 }
 
-										 
-LLSD LLMeshUploadThread::createObject(LLModelInstance& instance)
-{
-	LLMatrix4 transformation = instance.mTransform;
-
-	llassert(instance.mMeshID.notNull());
-	
-	// check for reflection
-	BOOL reflected = (transformation.determinant() < 0);
-
-	// compute position
-	LLVector3 position = LLVector3(0, 0, 0) * transformation;
-
-	// compute scale
-	LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position;
-	LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position;
-	LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position;
-	F32 x_length = x_transformed.normalize();
-	F32 y_length = y_transformed.normalize();
-	F32 z_length = z_transformed.normalize();
-	LLVector3 scale = LLVector3(x_length, y_length, z_length);
-
-    // adjust for "reflected" geometry
-	LLVector3 x_transformed_reflected = x_transformed;
-	if (reflected)
-	{
-		x_transformed_reflected *= -1.0;
-	}
-	
-	// compute rotation
-	LLMatrix3 rotation_matrix;
-	rotation_matrix.setRows(x_transformed_reflected, y_transformed, z_transformed);
-	LLQuaternion quat_rotation = rotation_matrix.quaternion();
-	quat_rotation.normalize(); // the rotation_matrix might not have been orthoginal.  make it so here.
-	LLVector3 euler_rotation;
-	quat_rotation.getEulerAngles(&euler_rotation.mV[VX], &euler_rotation.mV[VY], &euler_rotation.mV[VZ]);
-
-	//
-	// build parameter block to construct this prim
-	//
-	
-	LLSD object_params;
-
-	// create prim
-
-	// set volume params
-	U8 sculpt_type = LL_SCULPT_TYPE_MESH;
-	if (reflected)
-	{
-		sculpt_type |= LL_SCULPT_FLAG_MIRROR;
-	}
-	LLVolumeParams  volume_params;
-	volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
-	volume_params.setBeginAndEndS( 0.f, 1.f );
-	volume_params.setBeginAndEndT( 0.f, 1.f );
-	volume_params.setRatio  ( 1, 1 );
-	volume_params.setShear  ( 0, 0 );
-	volume_params.setSculptID(instance.mMeshID, sculpt_type);
-	object_params["shape"] = volume_params.asLLSD();
-
-	object_params["material"] = LL_MCODE_WOOD;
-
-	object_params["group-id"] = gAgent.getGroupID();
-	object_params["pos"] = ll_sd_from_vector3(position + mOrigin);
-	object_params["rotation"] = ll_sd_from_quaternion(quat_rotation);
-	object_params["scale"] = ll_sd_from_vector3(scale);
-	object_params["name"] = instance.mLabel;
-
-	// load material from dae file
-	object_params["facelist"] = LLSD::emptyArray();
-	for (S32 i = 0; i < instance.mMaterial.size(); i++)
-	{
-		LLTextureEntry te;
-		LLImportMaterial& mat = instance.mMaterial[i];
-
-		te.setColor(mat.mDiffuseColor);
-
-		LLUUID diffuse_id = mTextureMap[mat.mDiffuseMap].mUUID;
-
-		if (diffuse_id.notNull())
-		{
-			te.setID(diffuse_id);
-		}
-		else
-		{
-			te.setID(LLUUID("5748decc-f629-461c-9a36-a35a221fe21f")); // blank texture
-		}
-
-		te.setFullbright(mat.mFullbright);
-
-		object_params["facelist"][i] = te.asLLSD();
-	}
-
-	// set extra parameters
-	LLSculptParams sculpt_params;
-	sculpt_params.setSculptTexture(instance.mMeshID);
-	sculpt_params.setSculptType(sculpt_type);
-	U8 buffer[MAX_OBJECT_PARAMS_SIZE+1];
-	LLDataPackerBinaryBuffer dp(buffer, MAX_OBJECT_PARAMS_SIZE);
-	sculpt_params.pack(dp);
-	std::vector<U8> v(dp.getCurrentSize());
-	memcpy(&v[0], buffer, dp.getCurrentSize());
-	LLSD extra_parameter;
-	extra_parameter["extra_parameter"] = sculpt_params.mType;
-	extra_parameter["param_data"] = v;
-	object_params["extra_parameters"].append(extra_parameter);
-
-	LLPermissions perm;
-	perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false);
-	perm.setCreator(gAgent.getID());
-
-	perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base
-				   PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner
-				   LLFloaterPerms::getEveryonePerms(),
-				   LLFloaterPerms::getGroupPerms(),
-				   LLFloaterPerms::getNextOwnerPerms());
-		
-	object_params["permissions"] = ll_create_sd_from_permissions(perm);
-
-	object_params["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
-
-	return object_params;
-}
-
-void LLMeshUploadThread::priceResult(LLMeshUploadData& data, const LLSD& content)
-{
-	mPendingCost += content["upload_price"].asInteger();
-	data.mRSVP = content["rsvp"].asString();
-
-	mConfirmedQ.push(data);
-}
-
-void LLMeshUploadThread::priceResult(LLTextureUploadData& data, const LLSD& content)
-{
-	mPendingCost += content["upload_price"].asInteger();
-	data.mRSVP = content["rsvp"].asString();
-
-	mConfirmedTextureQ.push(data);
-}
-
-
 bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
 {
 	if (mDiffuseMap != rhs.mDiffuseMap)
@@ -3137,6 +2728,11 @@ bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
 		return mDiffuseColor < rhs.mDiffuseColor;
 	}
 
+	if (mBinding != rhs.mBinding)
+	{
+		return mBinding < rhs.mBinding;
+	}
+
 	return mFullbright < rhs.mFullbright;
 }
 
@@ -3158,55 +2754,66 @@ void LLMeshRepository::uploadError(LLSD& args)
 //static
 F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod)
 {
-	F32 dlowest = llmin(radius/0.03f, 256.f);
-	F32 dlow = llmin(radius/0.06f, 256.f);
-	F32 dmid = llmin(radius/0.24f, 256.f);
-	
-	F32 bytes_lowest = header["lowest_lod"]["size"].asReal()/1024.f;
-	F32 bytes_low = header["low_lod"]["size"].asReal()/1024.f;
-	F32 bytes_mid = header["medium_lod"]["size"].asReal()/1024.f;
-	F32 bytes_high = header["high_lod"]["size"].asReal()/1024.f;
+	F32 max_distance = 512.f;
 
-	if (bytes)
-	{
-		*bytes = 0;
-		*bytes += header["lowest_lod"]["size"].asInteger();
-		*bytes += header["low_lod"]["size"].asInteger();
-		*bytes += header["medium_lod"]["size"].asInteger();
-		*bytes += header["high_lod"]["size"].asInteger();
-	}
+	F32 dlowest = llmin(radius/0.03f, max_distance);
+	F32 dlow = llmin(radius/0.06f, max_distance);
+	F32 dmid = llmin(radius/0.24f, max_distance);
+	
+	F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount");  //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
+	F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free"
 
+	F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle");
 
-	if (bytes_visible)
-	{
-		lod = LLMeshRepository::getActualMeshLOD(header, lod);
-		if (lod >= 0 && lod <= 3)
-		{
-			*bytes_visible = header[header_lod[lod]]["size"].asInteger();
-		}
-	}
+	S32 bytes_lowest = header["lowest_lod"]["size"].asInteger();
+	S32 bytes_low = header["low_lod"]["size"].asInteger();
+	S32 bytes_mid = header["medium_lod"]["size"].asInteger();
+	S32 bytes_high = header["high_lod"]["size"].asInteger();
 
-	if (bytes_high == 0.f)
+	if (bytes_high == 0)
 	{
 		return 0.f;
 	}
 
-	if (bytes_mid == 0.f)
+	if (bytes_mid == 0)
 	{
 		bytes_mid = bytes_high;
 	}
 
-	if (bytes_low == 0.f)
+	if (bytes_low == 0)
 	{
 		bytes_low = bytes_mid;
 	}
 
-	if (bytes_lowest == 0.f)
+	if (bytes_lowest == 0)
 	{
 		bytes_lowest = bytes_low;
 	}
 
-	F32 max_area = 65536.f;
+	F32 triangles_lowest = llmax((F32) bytes_lowest-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
+	F32 triangles_low = llmax((F32) bytes_low-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
+	F32 triangles_mid = llmax((F32) bytes_mid-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
+	F32 triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
+
+	if (bytes)
+	{
+		*bytes = 0;
+		*bytes += header["lowest_lod"]["size"].asInteger();
+		*bytes += header["low_lod"]["size"].asInteger();
+		*bytes += header["medium_lod"]["size"].asInteger();
+		*bytes += header["high_lod"]["size"].asInteger();
+	}
+
+	if (bytes_visible)
+	{
+		lod = LLMeshRepository::getActualMeshLOD(header, lod);
+		if (lod >= 0 && lod <= 3)
+		{
+			*bytes_visible = header[header_lod[lod]]["size"].asInteger();
+		}
+	}
+
+	F32 max_area = 102932.f; //area of circle that encompasses region
 	F32 min_area = 1.f;
 
 	F32 high_area = llmin(F_PI*dmid*dmid, max_area);
@@ -3229,12 +2836,12 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32
 	low_area /= total_area;
 	lowest_area /= total_area;
 
-	F32 weighted_avg = bytes_high*high_area +
-					   bytes_mid*mid_area +
-					   bytes_low*low_area +
-					  bytes_lowest*lowest_area;
+	F32 weighted_avg = triangles_high*high_area +
+					   triangles_mid*mid_area +
+					   triangles_low*low_area +
+					  triangles_lowest*lowest_area;
 
-	return weighted_avg * gSavedSettings.getF32("MeshStreamingCostScaler");
+	return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*15000.f;
 }
 
 
@@ -3291,24 +2898,27 @@ S32 LLPhysicsDecomp::llcdCallback(const char* status, S32 p1, S32 p2)
 	return 1;
 }
 
-void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh)
+void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based)
 {
 	mesh.mVertexBase = mCurRequest->mPositions[0].mV;
 	mesh.mVertexStrideBytes = 12;
 	mesh.mNumVertices = mCurRequest->mPositions.size();
 
-	mesh.mIndexType = LLCDMeshData::INT_16;
-	mesh.mIndexBase = &(mCurRequest->mIndices[0]);
-	mesh.mIndexStrideBytes = 6;
+	if(!vertex_based)
+	{
+		mesh.mIndexType = LLCDMeshData::INT_16;
+		mesh.mIndexBase = &(mCurRequest->mIndices[0]);
+		mesh.mIndexStrideBytes = 6;
 	
-	mesh.mNumTriangles = mCurRequest->mIndices.size()/3;
+		mesh.mNumTriangles = mCurRequest->mIndices.size()/3;
+	}
 
-	if (mesh.mNumTriangles > 0 && mesh.mNumVertices > 2)
+	if ((vertex_based || mesh.mNumTriangles > 0) && mesh.mNumVertices > 2)
 	{
 		LLCDResult ret = LLCD_OK;
 		if (LLConvexDecomposition::getInstance() != NULL)
 		{
-			ret  = LLConvexDecomposition::getInstance()->setMeshData(&mesh);
+			ret  = LLConvexDecomposition::getInstance()->setMeshData(&mesh, vertex_based);
 		}
 
 		if (ret)
@@ -3332,7 +2942,7 @@ void LLPhysicsDecomp::doDecomposition()
 	//load data intoLLCD
 	if (stage == 0)
 	{
-		setMeshData(mesh);
+		setMeshData(mesh, false);
 	}
 		
 	//build parameter map
@@ -3506,11 +3116,54 @@ void make_box(LLPhysicsDecomp::Request * request)
 
 void LLPhysicsDecomp::doDecompositionSingleHull()
 {
-	LLCDMeshData mesh;
+	LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance();
+
+	if (decomp == NULL)
+	{
+		//stub. do nothing.
+		return;
+	}
 	
-	setMeshData(mesh);
+	LLCDMeshData mesh;	
+
+#if 1
+	setMeshData(mesh, true);
+
+	LLCDResult ret = decomp->buildSingleHull() ;
+	if(ret)
+	{
+		llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl;
+		make_box(mCurRequest);
+	}
+
+	mMutex->lock();
+	mCurRequest->mHull.clear();
+	mCurRequest->mHull.resize(1);
+	mCurRequest->mHullMesh.clear();
+	mMutex->unlock();
+
+	std::vector<LLVector3> p;
+	LLCDHull hull;
+		
+	// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
+	decomp->getSingleHull(&hull);
+
+	const F32* v = hull.mVertexBase;
+
+	for (S32 j = 0; j < hull.mNumVertices; ++j)
+	{
+		LLVector3 vert(v[0], v[1], v[2]); 
+		p.push_back(vert);
+		v = (F32*) (((U8*) v) + hull.mVertexStrideBytes);
+	}
+						
+	mMutex->lock();
+	mCurRequest->mHull[0] = p;
+	mMutex->unlock();	
 			
-	
+#else
+	setMeshData(mesh, false);
+
 	//set all parameters to default
 	std::map<std::string, const LLCDParam*> param_map;
 
@@ -3519,23 +3172,15 @@ void LLPhysicsDecomp::doDecompositionSingleHull()
 
 	if (!params)
 	{
-		param_count = LLConvexDecomposition::getInstance()->getParameters(&params);
+		param_count = decomp->getParameters(&params);
 	}
 	
-	LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance();
-
-	if (decomp == NULL)
-	{
-		//stub. do nothing.
-		return;
-	}
-
 	for (S32 i = 0; i < param_count; ++i)
 	{
 		decomp->setParam(params[i].mName, params[i].mDefault.mIntOrEnumValue);
 	}
 
-	const S32 STAGE_DECOMPOSE = mStageID["Decompose"];
+	const S32 STAGE_DECOMPOSE = mStageID["Decompose"];	
 	const S32 STAGE_SIMPLIFY = mStageID["Simplify"];
 	const S32 DECOMP_PREVIEW = 0;
 	const S32 SIMPLIFY_RETAIN = 0;
@@ -3597,7 +3242,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull()
 			}
 		}
 	}
-
+#endif
 
 	{
 		completeCurrent();
@@ -3760,7 +3405,8 @@ LLModelInstance::LLModelInstance(LLSD& data)
 
 	for (U32 i = 0; i < data["material"].size(); ++i)
 	{
-		mMaterial.push_back(LLImportMaterial(data["material"][i]));
+		LLImportMaterial mat(data["material"][i]);
+		mMaterial[mat.mBinding] = mat;
 	}
 }
 
@@ -3773,9 +3419,10 @@ LLSD LLModelInstance::asLLSD()
 	ret["label"] = mLabel;
 	ret["transform"] = mTransform.getValue();
 	
-	for (U32 i = 0; i < mMaterial.size(); ++i)
+	U32 i = 0;
+	for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter)
 	{
-		ret["material"][i] = mMaterial[i].asLLSD();
+		ret["material"][i++] = iter->second.asLLSD();
 	}
 
 	return ret;
@@ -3787,6 +3434,7 @@ LLImportMaterial::LLImportMaterial(LLSD& data)
 	mDiffuseMapLabel = data["diffuse"]["label"].asString();
 	mDiffuseColor.setValue(data["diffuse"]["color"]);
 	mFullbright = data["fullbright"].asBoolean();
+	mBinding = data["binding"].asString();
 }
 
 
@@ -3798,7 +3446,8 @@ LLSD LLImportMaterial::asLLSD()
 	ret["diffuse"]["label"] = mDiffuseMapLabel;
 	ret["diffuse"]["color"] = mDiffuseColor.getValue();
 	ret["fullbright"] = mFullbright;
-	
+	ret["binding"] = mBinding;
+
 	return ret;
 }
 
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index f237c3a60e6cbdc9ad8134aad4b1c2966ac9b6b6..35a7314cd5709578b3977de2e57494fad7c0866a 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -36,6 +36,7 @@
 #define LLCONVEXDECOMPINTER_STATIC 1
 
 #include "llconvexdecomposition.h"
+#include "lluploadfloaterobservers.h"
 
 class LLVOVolume;
 class LLMeshResponder;
@@ -91,6 +92,7 @@ class LLImportMaterial
 	LLPointer<LLViewerFetchedTexture> mDiffuseMap;
 	std::string mDiffuseMapFilename;
 	std::string mDiffuseMapLabel;
+	std::string mBinding;
 	LLColor4 mDiffuseColor;
 	bool mFullbright;
 
@@ -119,9 +121,9 @@ class LLModelInstance
 	S32 mLocalMeshID;
 
 	LLMatrix4 mTransform;
-	std::vector<LLImportMaterial> mMaterial;
+	std::map<std::string, LLImportMaterial> mMaterial;
 
-	LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::vector<LLImportMaterial>& materials)
+	LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials)
 		: mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
 	{
 		mLocalMeshID = -1;
@@ -189,7 +191,7 @@ class LLPhysicsDecomp : public LLThread
 	static S32 llcdCallback(const char*, S32, S32);
 	void cancel();
 
-	void setMeshData(LLCDMeshData& mesh);
+	void setMeshData(LLCDMeshData& mesh, bool vertex_based);
 	void doDecomposition();
 	void doDecompositionSingleHull();
 
@@ -229,8 +231,7 @@ class LLMeshRepoThread : public LLThread
 	mesh_header_map mMeshHeader;
 	
 	std::map<LLUUID, U32> mMeshHeaderSize;
-	std::map<LLUUID, U32> mMeshResourceCost;
-
+	
 	class HeaderRequest
 	{ 
 	public:
@@ -333,8 +334,7 @@ class LLMeshRepoThread : public LLThread
 
 	void notifyLoadedMeshes();
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
-	U32 getResourceCost(const LLUUID& mesh_params);
-
+	
 	void loadMeshSkinInfo(const LLUUID& mesh_id);
 	void loadMeshDecomposition(const LLUUID& mesh_id);
 	void loadMeshPhysicsShape(const LLUUID& mesh_id);
@@ -356,6 +356,9 @@ class LLMeshRepoThread : public LLThread
 
 class LLMeshUploadThread : public LLThread 
 {
+private:
+	S32 mMeshUploadTimeOut ; //maximum time in seconds to execute an uploading request.
+
 public:
 	class DecompRequest : public LLPhysicsDecomp::Request
 	{
@@ -385,9 +388,7 @@ class LLMeshUploadThread : public LLThread
 
 	LLMutex*					mMutex;
 	LLCurlRequest* mCurlRequest;
-	S32				mPendingConfirmations;
 	S32				mPendingUploads;
-	S32				mPendingCost;
 	LLVector3		mOrigin;
 	bool			mFinished;	
 	bool			mUploadTextures;
@@ -399,38 +400,21 @@ class LLMeshUploadThread : public LLThread
 	std::string		mWholeModelFeeCapability;
 	std::string		mWholeModelUploadURL;
 
-	std::queue<LLMeshUploadData> mUploadQ;
-	std::queue<LLMeshUploadData> mConfirmedQ;
-	std::queue<LLModelInstance> mInstanceQ;
-
-	std::queue<LLTextureUploadData> mTextureQ;
-	std::queue<LLTextureUploadData> mConfirmedTextureQ;
-
-	std::map<LLViewerFetchedTexture*, LLTextureUploadData> mTextureMap;
-
 	LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures,
-			bool upload_skin, bool upload_joints);
+			bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true,
+					   LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()), LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
 	~LLMeshUploadThread();
 
-	void uploadTexture(LLTextureUploadData& data);
-	void doUploadTexture(LLTextureUploadData& data);
-	void priceResult(LLTextureUploadData& data, const LLSD& content);
-	void onTextureUploaded(LLTextureUploadData& data);
-
-	void uploadModel(LLMeshUploadData& data);
-	void doUploadModel(LLMeshUploadData& data);
-	void onModelUploaded(LLMeshUploadData& data);
-	void createObjects(LLMeshUploadData& data);
-	LLSD createObject(LLModelInstance& instance);
-	void priceResult(LLMeshUploadData& data, const LLSD& content);
-
 	bool finished() { return mFinished; }
 	virtual void run();
 	void preStart();
 	void discard() ;
 	BOOL isDiscarded();
 
+	void generateHulls();
+
 	void doWholeModelUpload();
+	void requestWholeModelFee();
 
 	void wholeModelToLLSD(LLSD& dest, bool include_textures);
 
@@ -438,6 +422,15 @@ class LLMeshUploadThread : public LLThread
 							 LLVector3& result_pos,
 							 LLQuaternion& result_rot,
 							 LLVector3& result_scale);
+
+	void setFeeObserverHandle(LLHandle<LLWholeModelFeeObserver> observer_handle) { mFeeObserverHandle = observer_handle; }
+	void setUploadObserverHandle(LLHandle<LLWholeModelUploadObserver> observer_handle) { mUploadObserverHandle = observer_handle; }
+
+private:
+	LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
+	LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;
+
+	bool mDoUpload; // if FALSE only model data will be requested, otherwise the model will be uploaded
 };
 
 class LLMeshRepository
@@ -471,8 +464,6 @@ class LLMeshRepository
 
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
 	static S32 getActualMeshLOD(LLSD& header, S32 lod);
-	U32 calcResourceCost(LLSD& header);
-	U32 getResourceCost(const LLUUID& mesh_params);
 	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj);
 	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
 	void fetchPhysicsShape(const LLUUID& mesh_id);
@@ -488,7 +479,8 @@ class LLMeshRepository
 	LLSD& getMeshHeader(const LLUUID& mesh_id);
 
 	void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
-			bool upload_skin, bool upload_joints);
+			bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true,
+					 LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()), LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
 
 	S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
 
diff --git a/indra/newview/llpanelmarketplaceinbox.cpp b/indra/newview/llpanelmarketplaceinbox.cpp
index 141e29fcece6d52db44779cc8273e5e30dea6e1d..05e45d86b80fb9bfa2e1574408f8c7c8b2bcfe16 100644
--- a/indra/newview/llpanelmarketplaceinbox.cpp
+++ b/indra/newview/llpanelmarketplaceinbox.cpp
@@ -113,7 +113,7 @@ LLInventoryPanel * LLPanelMarketplaceInbox::setupInventoryPanel()
 void LLPanelMarketplaceInbox::onFocusReceived()
 {
 	LLSidepanelInventory * sidepanel_inventory = LLSideTray::getInstance()->getPanel<LLSidepanelInventory>("sidepanel_inventory");
-	
+
 	sidepanel_inventory->clearSelections(true, false, true);
 }
 
diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp
index 1e9ce582373d692c5f5dbe986b327c9a6f7ff611..ce8057eeaddd74746192e9c2130466569081b133 100644
--- a/indra/newview/llpanelplaceprofile.cpp
+++ b/indra/newview/llpanelplaceprofile.cpp
@@ -32,6 +32,7 @@
 #include "llparcel.h"
 #include "message.h"
 
+#include "llexpandabletextbox.h"
 #include "lliconctrl.h"
 #include "lllineeditor.h"
 #include "lltextbox.h"
@@ -227,6 +228,34 @@ void LLPanelPlaceProfile::setInfoType(EInfoType type)
 
 	getChild<LLAccordionCtrl>("advanced_info_accordion")->setVisible(is_info_type_agent);
 
+	// If we came from search we want larger description area, approx. 10 lines (see STORM-1311).
+	// Don't use the maximum available space because that leads to nasty artifacts
+	// in text editor and expandable text box.
+	{
+		const S32 SEARCH_DESC_HEIGHT = 150;
+
+		// Remember original geometry (once).
+		static const S32 sOrigDescVPad = getChildView("parcel_title")->getRect().mBottom - mDescEditor->getRect().mTop;
+		static const S32 sOrigDescHeight = mDescEditor->getRect().getHeight();
+		static const S32 sOrigMRIconVPad = mDescEditor->getRect().mBottom - mMaturityRatingIcon->getRect().mTop;
+		static const S32 sOrigMRTextVPad = mDescEditor->getRect().mBottom - mMaturityRatingText->getRect().mTop;
+
+		// Resize the description.
+		const S32 desc_height = is_info_type_agent ? sOrigDescHeight : SEARCH_DESC_HEIGHT;
+		const S32 desc_top = getChildView("parcel_title")->getRect().mBottom - sOrigDescVPad;
+		LLRect desc_rect = mDescEditor->getRect();
+		desc_rect.setOriginAndSize(desc_rect.mLeft, desc_top - desc_height, desc_rect.getWidth(), desc_height);
+		mDescEditor->reshape(desc_rect.getWidth(), desc_rect.getHeight());
+		mDescEditor->setRect(desc_rect);
+		mDescEditor->updateTextShape();
+
+		// Move the maturity rating icon/text accordingly.
+		const S32 mr_icon_bottom = mDescEditor->getRect().mBottom - sOrigMRIconVPad - mMaturityRatingIcon->getRect().getHeight();
+		const S32 mr_text_bottom = mDescEditor->getRect().mBottom - sOrigMRTextVPad - mMaturityRatingText->getRect().getHeight();
+		mMaturityRatingIcon->setOrigin(mMaturityRatingIcon->getRect().mLeft, mr_icon_bottom);
+		mMaturityRatingText->setOrigin(mMaturityRatingText->getRect().mLeft, mr_text_bottom);
+	}
+
 	switch(type)
 	{
 		case AGENT:
@@ -434,7 +463,7 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
 	}
 
 	mRegionNameText->setText(region->getName());
-	mRegionTypeText->setText(region->getSimProductName());
+	mRegionTypeText->setText(region->getLocalizedSimProductName());
 
 	// Determine parcel owner
 	if (parcel->isPublic())
diff --git a/indra/newview/llpanelvoicedevicesettings.cpp b/indra/newview/llpanelvoicedevicesettings.cpp
index 4a80bbbe5ef7d175193adcaf381eab8b78596ef8..6be2ea6481cc0fa5e8563173fe23c6307c214f79 100644
--- a/indra/newview/llpanelvoicedevicesettings.cpp
+++ b/indra/newview/llpanelvoicedevicesettings.cpp
@@ -41,6 +41,7 @@
 
 
 static LLRegisterPanelClassWrapper<LLPanelVoiceDeviceSettings> t_panel_group_general("panel_voice_device_settings");
+static const std::string DEFAULT_DEVICE("Default");
 
 
 LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()
@@ -68,10 +69,17 @@ BOOL LLPanelVoiceDeviceSettings::postBuild()
 	// set mic volume tuning slider based on last mic volume setting
 	volume_slider->setValue(mMicVolume);
 
-	getChild<LLComboBox>("voice_input_device")->setCommitCallback(
+	mCtrlInputDevices = getChild<LLComboBox>("voice_input_device");
+	mCtrlOutputDevices = getChild<LLComboBox>("voice_output_device");
+
+	mCtrlInputDevices->setCommitCallback(
 		boost::bind(&LLPanelVoiceDeviceSettings::onCommitInputDevice, this));
-	getChild<LLComboBox>("voice_output_device")->setCommitCallback(
+	mCtrlOutputDevices->setCommitCallback(
 		boost::bind(&LLPanelVoiceDeviceSettings::onCommitOutputDevice, this));
+
+	mLocalizedDeviceNames[DEFAULT_DEVICE]				= getString("default_text");
+	mLocalizedDeviceNames["No Device"]					= getString("name_no_device");
+	mLocalizedDeviceNames["Default System Device"]		= getString("name_default_system_device");
 	
 	return TRUE;
 }
@@ -138,14 +146,14 @@ void LLPanelVoiceDeviceSettings::apply()
 	std::string s;
 	if(mCtrlInputDevices)
 	{
-		s = mCtrlInputDevices->getSimple();
+		s = mCtrlInputDevices->getValue().asString();
 		gSavedSettings.setString("VoiceInputAudioDevice", s);
 		mInputDevice = s;
 	}
 
 	if(mCtrlOutputDevices)
 	{
-		s = mCtrlOutputDevices->getSimple();
+		s = mCtrlOutputDevices->getValue().asString();
 		gSavedSettings.setString("VoiceOutputAudioDevice", s);
 		mOutputDevice = s;
 	}
@@ -166,10 +174,10 @@ void LLPanelVoiceDeviceSettings::cancel()
 	gSavedSettings.setString("VoiceOutputAudioDevice", mOutputDevice);
 
 	if(mCtrlInputDevices)
-		mCtrlInputDevices->setSimple(mInputDevice);
+		mCtrlInputDevices->setValue(mInputDevice);
 
 	if(mCtrlOutputDevices)
-		mCtrlOutputDevices->setSimple(mOutputDevice);
+		mCtrlOutputDevices->setValue(mOutputDevice);
 
 	gSavedSettings.setF32("AudioLevelMic", mMicVolume);
 	LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
@@ -188,9 +196,6 @@ void LLPanelVoiceDeviceSettings::refresh()
 	LLVoiceClient::getInstance()->tuningSetMicVolume(current_volume);
 
 	// Fill in popup menus
-	mCtrlInputDevices = getChild<LLComboBox>("voice_input_device");
-	mCtrlOutputDevices = getChild<LLComboBox>("voice_output_device");
-
 	bool device_settings_available = LLVoiceClient::getInstance()->deviceSettingsAvailable();
 
 	if (mCtrlInputDevices)
@@ -212,14 +217,14 @@ void LLPanelVoiceDeviceSettings::refresh()
 		if(mCtrlInputDevices)
 		{
 			mCtrlInputDevices->removeall();
-			mCtrlInputDevices->add( mInputDevice, ADD_BOTTOM );
-			mCtrlInputDevices->setSimple(mInputDevice);
+			mCtrlInputDevices->add(getLocalizedDeviceName(mInputDevice), mInputDevice, ADD_BOTTOM);
+			mCtrlInputDevices->setValue(mInputDevice);
 		}
 		if(mCtrlOutputDevices)
 		{
 			mCtrlOutputDevices->removeall();
-			mCtrlOutputDevices->add( mOutputDevice, ADD_BOTTOM );
-			mCtrlOutputDevices->setSimple(mOutputDevice);
+			mCtrlOutputDevices->add(getLocalizedDeviceName(mOutputDevice), mOutputDevice, ADD_BOTTOM);
+			mCtrlOutputDevices->setValue(mOutputDevice);
 		}
 		mDevicesUpdated = FALSE;
 	}
@@ -230,35 +235,41 @@ void LLPanelVoiceDeviceSettings::refresh()
 		if(mCtrlInputDevices)
 		{
 			mCtrlInputDevices->removeall();
-			mCtrlInputDevices->add( getString("default_text"), ADD_BOTTOM );
+			mCtrlInputDevices->add(getLocalizedDeviceName(DEFAULT_DEVICE), DEFAULT_DEVICE, ADD_BOTTOM);
 
 			for(iter=LLVoiceClient::getInstance()->getCaptureDevices().begin(); 
 				iter != LLVoiceClient::getInstance()->getCaptureDevices().end();
 				iter++)
 			{
-				mCtrlInputDevices->add( *iter, ADD_BOTTOM );
+				mCtrlInputDevices->add(getLocalizedDeviceName(*iter), *iter, ADD_BOTTOM);
 			}
 
-			if(!mCtrlInputDevices->setSimple(mInputDevice))
+			// Fix invalid input audio device preference.
+			if (!mCtrlInputDevices->setSelectedByValue(mInputDevice, TRUE))
 			{
-				mCtrlInputDevices->setSimple(getString("default_text"));
+				mCtrlInputDevices->setValue(DEFAULT_DEVICE);
+				gSavedSettings.setString("VoiceInputAudioDevice", DEFAULT_DEVICE);
+				mInputDevice = DEFAULT_DEVICE;
 			}
 		}
 		
 		if(mCtrlOutputDevices)
 		{
 			mCtrlOutputDevices->removeall();
-			mCtrlOutputDevices->add( getString("default_text"), ADD_BOTTOM );
+			mCtrlOutputDevices->add(getLocalizedDeviceName(DEFAULT_DEVICE), DEFAULT_DEVICE, ADD_BOTTOM);
 
 			for(iter= LLVoiceClient::getInstance()->getRenderDevices().begin(); 
 				iter !=  LLVoiceClient::getInstance()->getRenderDevices().end(); iter++)
 			{
-				mCtrlOutputDevices->add( *iter, ADD_BOTTOM );
+				mCtrlOutputDevices->add(getLocalizedDeviceName(*iter), *iter, ADD_BOTTOM);
 			}
 
-			if(!mCtrlOutputDevices->setSimple(mOutputDevice))
+			// Fix invalid output audio device preference.
+			if (!mCtrlOutputDevices->setSelectedByValue(mOutputDevice, TRUE))
 			{
-				mCtrlOutputDevices->setSimple(getString("default_text"));
+				mCtrlOutputDevices->setValue(DEFAULT_DEVICE);
+				gSavedSettings.setString("VoiceOutputAudioDevice", DEFAULT_DEVICE);
+				mOutputDevice = DEFAULT_DEVICE;
 			}
 		}
 		mDevicesUpdated = TRUE;
@@ -292,12 +303,19 @@ void LLPanelVoiceDeviceSettings::cleanup()
 	}
 }
 
+// returns English name if no translation found
+std::string LLPanelVoiceDeviceSettings::getLocalizedDeviceName(const std::string& en_dev_name)
+{
+	std::map<std::string, std::string>::const_iterator it = mLocalizedDeviceNames.find(en_dev_name);
+	return it != mLocalizedDeviceNames.end() ? it->second : en_dev_name;
+}
+
 void LLPanelVoiceDeviceSettings::onCommitInputDevice()
 {
 	if(LLVoiceClient::getInstance())
 	{
 		LLVoiceClient::getInstance()->setCaptureDevice(
-			getChild<LLComboBox>("voice_input_device")->getValue().asString());
+			mCtrlInputDevices->getValue().asString());
 	}
 }
 
@@ -306,6 +324,6 @@ void LLPanelVoiceDeviceSettings::onCommitOutputDevice()
 	if(LLVoiceClient::getInstance())
 	{
 		LLVoiceClient::getInstance()->setRenderDevice(
-			getChild<LLComboBox>("voice_output_device")->getValue().asString());
+			mCtrlInputDevices->getValue().asString());
 	}
 }
diff --git a/indra/newview/llpanelvoicedevicesettings.h b/indra/newview/llpanelvoicedevicesettings.h
index d09476d469742d94ae3d6c69ccb9b9c17b58269a..ba3bcad0dc2c486af8fbc83840df51b23bd23a8c 100644
--- a/indra/newview/llpanelvoicedevicesettings.h
+++ b/indra/newview/llpanelvoicedevicesettings.h
@@ -49,6 +49,8 @@ class LLPanelVoiceDeviceSettings : public LLPanel
 	void setUseTuningMode(bool use) { mUseTuningMode = use; };
 	
 protected:
+	std::string getLocalizedDeviceName(const std::string& en_dev_name);
+
 	void onCommitInputDevice();
 	void onCommitOutputDevice();
 
@@ -59,6 +61,7 @@ class LLPanelVoiceDeviceSettings : public LLPanel
 	class LLComboBox		*mCtrlOutputDevices;
 	BOOL mDevicesUpdated;
 	bool mUseTuningMode;
+	std::map<std::string, std::string> mLocalizedDeviceNames;
 };
 
 #endif // LL_LLPANELVOICEDEVICESETTINGS_H
diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp
index 8e8fc9dd25958ba55a18bdfe9328763e405f8fcc..09e799e4f741b11f4968aaa58579cb626906162c 100644
--- a/indra/newview/llsceneview.cpp
+++ b/indra/newview/llsceneview.cpp
@@ -83,6 +83,9 @@ void LLSceneView::draw()
 	S32 total_visible_triangles[] = {0, 0};
 	S32 total_triangles[] = {0, 0};
 	
+	S32 total_visible_bytes[] = {0, 0};
+	S32 total_bytes[] = {0, 0};
+
 	//streaming cost
 	std::vector<F32> streaming_cost[2];
 	F32 total_streaming[] = { 0.f, 0.f };
@@ -122,13 +125,19 @@ void LLSceneView::draw()
 				visible_triangles[idx].push_back(visible);
 				triangles[idx].push_back(high_triangles);
 
-				F32 streaming = object->getStreamingCost();
+				S32 bytes = 0;
+				S32 visible_bytes = 0;
+
+				F32 streaming = object->getStreamingCost(&bytes, &visible_bytes);
 				total_streaming[idx] += streaming;
 				streaming_cost[idx].push_back(streaming);
 
 				F32 physics = object->getPhysicsCost();
 				total_physics[idx] += physics;
 				physics_cost[idx].push_back(physics);
+
+				total_bytes[idx] += bytes;
+				total_visible_bytes[idx] += visible_bytes;
 			}
 		}
 	}
@@ -279,8 +288,8 @@ void LLSceneView::draw()
 				total_visible += tri_count;	
 			}
 
-			std::string label = llformat("%s Object Triangle Counts (Ktris) -- [%.2f, %.2f] Mean: %.2f  Median: %.2f  Visible: %.2f/%.2f",
-											category[idx], tri_domain[0]/1024.f, tri_domain[1]/1024.f, (total/count)/1024.f, triangles[idx][count/2]/1024.f, total_visible_triangles[idx]/1024.f, total_triangles[idx]/1024.f);
+			std::string label = llformat("%s Object Triangle Counts (Ktris) -- Visible: %.2f/%.2f (%.2f KB Visible)",
+				category[idx], total_visible_triangles[idx]/1024.f, total_triangles[idx]/1024.f, total_visible_bytes[idx]/1024.f);
 
 			LLFontGL::getFontMonospace()->renderUTF8(label,
 											0 , tri_rect.mLeft, tri_rect.mTop+margin, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 14f1beab03e056aa803a022b7d33b584c3442463..7991233aceb41d51da3fba138240ffca156b6969 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -724,7 +724,7 @@ bool idle_startup()
 		// this startup phase more than once.
 		if (gLoginMenuBarView == NULL)
 		{
-			initialize_edit_menu();
+		initialize_edit_menu();
 			init_menus();
 		}
 
@@ -1237,6 +1237,25 @@ bool idle_startup()
 	//---------------------------------------------------------------------
 	if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
 	{
+		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
+		if (regionp->capabilitiesReceived())
+		{
+			LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
+		}
+		else
+		{
+			U32 num_retries = regionp->getNumSeedCapRetries();
+			if (num_retries > 0)
+			{
+				LLStringUtil::format_map_t args;
+				args["[NUMBER]"] = llformat("%d", num_retries + 1);
+				set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD);
+			}
+			else
+			{
+				set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD);
+			}
+		}
 		return FALSE;
 	}
 
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index bccabe21a8521bc3d317e2f0ebf3446138a8ac9f..66df7dae3ed5332c9ea2f4fcc35542496d5f425c 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -334,6 +334,17 @@ void LLSurface::setOriginGlobal(const LLVector3d &origin_global)
 	}
 }
 
+void LLSurface::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions )
+{
+	S32 i;
+	for (i = 0; i < 8; i++)
+	{
+		if ( mNeighbors[i] != NULL )
+		{
+			uniqueRegions.push_back( mNeighbors[i]->getRegion() );
+		}
+	}	
+}
 
 void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction)
 {
diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h
index 673ee83fe309e637d58e85d1cdb7560a9296485e..a4ef4fe2de61a00e7dfa9d9d2a2a8f288cd2b510 100644
--- a/indra/newview/llsurface.h
+++ b/indra/newview/llsurface.h
@@ -140,6 +140,9 @@ class LLSurface
 
 	friend class LLSurfacePatch;
 	friend std::ostream& operator<<(std::ostream &s, const LLSurface &S);
+	
+	void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions );
+	
 public:
 	// Number of grid points on one side of a region, including +1 buffer for
 	// north and east edge.
diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5a6a17fbca81a7b4b01dfe79100380643ed23372
--- /dev/null
+++ b/indra/newview/lluploadfloaterobservers.cpp
@@ -0,0 +1,56 @@
+/**
+ * @file lluploadfloaterobservers.cpp
+ * @brief LLUploadModelPremissionsResponder definition
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lluploadfloaterobservers.h"
+
+LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer)
+:mObserverHandle(observer)
+{
+}
+
+void LLUploadModelPremissionsResponder::error(U32 status, const std::string& reason)
+{
+	llwarns << "LLUploadModelPremissionsResponder::error("<< status << ": " << reason << ")" << llendl;
+
+	LLUploadPermissionsObserver* observer = mObserverHandle.get();
+
+	if (observer)
+	{
+		observer->setPermissonsErrorStatus(status, reason);
+	}
+}
+
+void LLUploadModelPremissionsResponder::result(const LLSD& content)
+{
+	LLUploadPermissionsObserver* observer = mObserverHandle.get();
+
+	if (observer)
+	{
+		observer->onPermissionsReceived(content);
+	}
+}
diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h
new file mode 100644
index 0000000000000000000000000000000000000000..79aad282d71329e0c1f01414bd2643b980ee439e
--- /dev/null
+++ b/indra/newview/lluploadfloaterobservers.h
@@ -0,0 +1,97 @@
+/**
+ * @file lluploadfloaterobservers.h
+ * @brief LLUploadModelPremissionsResponder declaration
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLUPLOADFLOATEROBSERVERS_H
+#define LL_LLUPLOADFLOATEROBSERVERS_H
+
+#include "llfloater.h"
+#include "llhttpclient.h"
+#include "llhandle.h"
+
+class LLUploadPermissionsObserver
+{
+public:
+
+	LLUploadPermissionsObserver(){mUploadPermObserverHandle.bind(this);}
+	virtual ~LLUploadPermissionsObserver() {}
+
+	virtual void onPermissionsReceived(const LLSD& result) = 0;
+	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0;
+
+	LLHandle<LLUploadPermissionsObserver> getPermObserverHandle() const {return mUploadPermObserverHandle;}
+
+protected:
+	LLRootHandle<LLUploadPermissionsObserver> mUploadPermObserverHandle;
+};
+
+class LLWholeModelFeeObserver
+{
+public:
+	LLWholeModelFeeObserver() { mWholeModelFeeObserverHandle.bind(this); }
+	virtual ~LLWholeModelFeeObserver() {}
+
+	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0;
+	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0;
+
+	LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; }
+
+protected:
+	LLRootHandle<LLWholeModelFeeObserver> mWholeModelFeeObserverHandle;
+};
+
+
+class LLWholeModelUploadObserver
+{
+public:
+	LLWholeModelUploadObserver() { mWholeModelUploadObserverHandle.bind(this); }
+	virtual ~LLWholeModelUploadObserver() {}
+
+	virtual void onModelUploadSuccess() = 0;
+
+	virtual void onModelUploadFailure() = 0;
+
+	LLHandle<LLWholeModelUploadObserver> getWholeModelUploadObserverHandle() const { return mWholeModelUploadObserverHandle; }
+
+protected:
+	LLRootHandle<LLWholeModelUploadObserver> mWholeModelUploadObserverHandle;
+};
+
+
+class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder
+{
+public:
+
+	LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer);
+
+	void error(U32 status, const std::string& reason);
+
+	void result(const LLSD& content);
+
+private:
+	LLHandle<LLUploadPermissionsObserver> mObserverHandle;
+};
+
+#endif /* LL_LLUPLOADFLOATEROBSERVERS_H */
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 77afd0ea225b977443cdb4e6fc80f3f6cea208ae..dd0989d608e9df61902c3be5ab93ab77d78169c8 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -130,12 +130,12 @@
 
 // *NOTE: Please add files in alphabetical order to keep merges easy.
 
-// handle secondlife:///app/floater/{NAME} URLs
+// handle secondlife:///app/openfloater/{NAME} URLs
 class LLFloaterOpenHandler : public LLCommandHandler
 {
 public:
 	// requires trusted browser to trigger
-	LLFloaterOpenHandler() : LLCommandHandler("floater", UNTRUSTED_THROTTLE) { }
+	LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { }
 
 	bool handle(const LLSD& params, const LLSD& query_map,
 				LLMediaCtrl* web)
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 22666cec0d59b9893a13ff46aa06a05eb815e189..c532346e6b1f74f51f84d1740e2e5580d0e6e91e 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -418,6 +418,9 @@ void LLViewerInventoryItem::fetchFromServer(void) const
 BOOL LLViewerInventoryItem::unpackMessage(LLSD item)
 {
 	BOOL rv = LLInventoryItem::fromLLSD(item);
+
+	LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);
+
 	mIsComplete = TRUE;
 	return rv;
 }
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index e5dfa51e7fc2c082aaf3c2a51a26b550d9b4c0cd..ebd7c6c688fc1e2f64d6feb375fec04cfcbd5755 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -62,6 +62,7 @@
 #include "llfloatersnapshot.h"
 #include "llfloatertools.h"
 #include "llfloaterworldmap.h"
+#include "llfloaterbuildoptions.h"
 #include "llavataractions.h"
 #include "lllandmarkactions.h"
 #include "llgroupmgr.h"
@@ -847,17 +848,17 @@ class LLAdvancedToggleFeature : public view_listener_t
 class LLAdvancedCheckFeature : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
-	{
-		U32 feature = feature_from_string( userdata.asString() );
-		bool new_value = false;
-
-		if ( feature != 0 )
-		{
-			new_value = LLPipeline::toggleRenderDebugFeatureControl( (void*)feature );
-		}
+{
+	U32 feature = feature_from_string( userdata.asString() );
+	bool new_value = false;
 
-		return new_value;
+	if ( feature != 0 )
+	{
+		new_value = LLPipeline::toggleRenderDebugFeatureControl( (void*)feature );
 	}
+
+	return new_value;
+}
 };
 
 void toggle_destination_and_avatar_picker(const LLSD& show)
@@ -7165,9 +7166,11 @@ class LLToolsUseSelectionForGrid : public view_listener_t
 		} func;
 		LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func);
 		LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT);
-		if (gFloaterTools)
+
+		LLFloaterBuildOptions* build_options_floater = LLFloaterReg::getTypedInstance<LLFloaterBuildOptions>("build_options");
+		if (build_options_floater && build_options_floater->getVisible())
 		{
-			gFloaterTools->mComboGridMode->setCurrentByIndex((S32)GRID_MODE_REF_OBJECT);
+			build_options_floater->setGridMode(GRID_MODE_REF_OBJECT);
 		}
 		return true;
 	}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 972993202a7c3d3ba035be1627f81cedce2c1f05..b5fdca632baeb48a70cb28b41f7dd89e26231d5a 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -516,7 +516,6 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list)
 	}
 }
 
-
 // This method returns true if the object is over land owned by the
 // agent.
 bool LLViewerObject::isReturnable()
@@ -525,17 +524,108 @@ bool LLViewerObject::isReturnable()
 	{
 		return false;
 	}
+		
 	std::vector<LLBBox> boxes;
 	boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned());
 	for (child_list_t::iterator iter = mChildList.begin();
 		 iter != mChildList.end(); iter++)
 	{
 		LLViewerObject* child = *iter;
-		boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned());
+		boxes.push_back( LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned());
+	}
+
+	bool result = (mRegionp && mRegionp->objectIsReturnable(getPositionRegion(), boxes)) ? 1 : 0;
+	
+	if ( !result )
+	{		
+		//Get list of neighboring regions relative to this vo's region
+		std::vector<LLViewerRegion*> uniqueRegions;
+		mRegionp->getNeighboringRegions( uniqueRegions );
+	
+		//Build aabb's - for root and all children
+		std::vector<PotentialReturnableObject> returnables;
+		typedef std::vector<LLViewerRegion*>::iterator RegionIt;
+		RegionIt regionStart = uniqueRegions.begin();
+		RegionIt regionEnd   = uniqueRegions.end();
+		
+		for (; regionStart != regionEnd; ++regionStart )
+		{
+			LLViewerRegion* pTargetRegion = *regionStart;
+			//Add the root vo as there may be no children and we still want
+			//to test for any edge overlap
+			buildReturnablesForChildrenVO( returnables, this, pTargetRegion );
+			//Add it's children
+			for (child_list_t::iterator iter = mChildList.begin();  iter != mChildList.end(); iter++)
+			{
+				LLViewerObject* pChild = *iter;		
+				buildReturnablesForChildrenVO( returnables, pChild, pTargetRegion );
+			}
+		}	
+	
+		//TBD#Eventually create a region -> box list map 
+		typedef std::vector<PotentialReturnableObject>::iterator ReturnablesIt;
+		ReturnablesIt retCurrentIt = returnables.begin();
+		ReturnablesIt retEndIt = returnables.end();
+	
+		for ( ; retCurrentIt !=retEndIt; ++retCurrentIt )
+		{
+			boxes.clear();
+			LLViewerRegion* pRegion = (*retCurrentIt).pRegion;
+			boxes.push_back( (*retCurrentIt).box );	
+			bool retResult = 	pRegion
+							 && pRegion->childrenObjectReturnable( boxes )
+							 && pRegion->canManageEstate();
+			if ( retResult )
+			{ 
+				result = true;
+				break;
+			}
+		}
+	}
+	return result;
+}
+
+void LLViewerObject::buildReturnablesForChildrenVO( std::vector<PotentialReturnableObject>& returnables, LLViewerObject* pChild, LLViewerRegion* pTargetRegion )
+{
+	if ( !pChild )
+	{
+		llerrs<<"child viewerobject is NULL "<<llendl;
 	}
+	
+	constructAndAddReturnable( returnables, pChild, pTargetRegion );
+	
+	//We want to handle any children VO's as well
+	for (child_list_t::iterator iter = pChild->mChildList.begin();  iter != pChild->mChildList.end(); iter++)
+	{
+		LLViewerObject* pChildofChild = *iter;
+		buildReturnablesForChildrenVO( returnables, pChildofChild, pTargetRegion );
+	}
+}
 
-	return mRegionp
-		&& mRegionp->objectIsReturnable(getPositionRegion(), boxes);
+void LLViewerObject::constructAndAddReturnable( std::vector<PotentialReturnableObject>& returnables, LLViewerObject* pChild, LLViewerRegion* pTargetRegion )
+{
+	
+	LLVector3 targetRegionPos;
+	targetRegionPos.setVec( pChild->getPositionGlobal() );	
+	
+	LLBBox childBBox = LLBBox( targetRegionPos, pChild->getRotationRegion(), pChild->getScale() * -0.5f, 
+							    pChild->getScale() * 0.5f).getAxisAligned();
+	
+	LLVector3 edgeA = targetRegionPos + childBBox.getMinLocal();
+	LLVector3 edgeB = targetRegionPos + childBBox.getMaxLocal();
+	
+	LLVector3d edgeAd, edgeBd;
+	edgeAd.setVec(edgeA);
+	edgeBd.setVec(edgeB);
+	
+	//Only add the box when either of the extents are in a neighboring region
+	if ( pTargetRegion->pointInRegionGlobal( edgeAd ) || pTargetRegion->pointInRegionGlobal( edgeBd ) )
+	{
+		PotentialReturnableObject returnableObj;
+		returnableObj.box		= childBBox;
+		returnableObj.pRegion	= pTargetRegion;
+		returnables.push_back( returnableObj );
+	}
 }
 
 BOOL LLViewerObject::setParent(LLViewerObject* parent)
@@ -4787,6 +4877,10 @@ void LLViewerObject::adjustAudioGain(const F32 gain)
 
 bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp)
 {
+	if (LLNetworkData::PARAMS_MESH == param_type)
+	{
+		param_type = LLNetworkData::PARAMS_SCULPT;
+	}
 	ExtraParameter* param = getExtraParameterEntryCreate(param_type);
 	if (param)
 	{
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 7ebcee7b7447237a2a4e81ec57a12c88a7617b44..1828a649177d9c107d8a4dca68fc404b5ca2e417 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -44,11 +44,11 @@
 #include "v3math.h"
 #include "llvertexbuffer.h"
 #include "llaccountingquota.h"
+#include "llbbox.h"
 
 class LLAgent;			// TODO: Get rid of this.
 class LLAudioSource;
 class LLAudioSourceVO;
-class LLBBox;
 class LLDataPacker;
 class LLColor4;
 class LLFrameTimer;
@@ -112,6 +112,12 @@ struct LLMaterialExportInfo
 	LLColor4	mColor;
 };
 
+struct PotentialReturnableObject
+{
+	LLBBox			box;
+	LLViewerRegion* pRegion;
+};
+
 //============================================================================
 
 class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
@@ -234,6 +240,9 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	// anti-encroachment is enabled
 	bool isReturnable();
 
+	void buildReturnablesForChildrenVO( std::vector<PotentialReturnableObject>& returnables, LLViewerObject* pChild, LLViewerRegion* pTargetRegion );
+	void constructAndAddReturnable( std::vector<PotentialReturnableObject>& returnables, LLViewerObject* pChild, LLViewerRegion* pTargetRegion );
+
 	/*
 	// This method will scan through this object, and then query the
 	// selection manager to see if the local agent probably has the
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 48ccc7d0354d078f902ddfcdd05f7be19f3fd230..db5684665b55b353e7e66ce707ffefbe05cdb11c 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1071,10 +1071,12 @@ void LLViewerObjectList::fetchObjectCosts()
 				LLSD id_list;
 				U32 object_index = 0;
 
+				U32 count = 0;
+
 				for (
 					std::set<LLUUID>::iterator iter = mStaleObjectCost.begin();
 					iter != mStaleObjectCost.end();
-					++iter)
+					)
 				{
 					// Check to see if a request for this object
 					// has already been made.
@@ -1084,13 +1086,15 @@ void LLViewerObjectList::fetchObjectCosts()
 						mPendingObjectCost.insert(*iter);
 						id_list[object_index++] = *iter;
 					}
-				}
 
-				// id_list should now contain all
-				// requests in mStaleObjectCost before, so clear
-				// it now
-				mStaleObjectCost.clear();
+					mStaleObjectCost.erase(iter++);
 
+					if (count++ >= 450)
+					{
+						break;
+					}
+				}
+									
 				if ( id_list.size() > 0 )
 				{
 					LLSD post_data = LLSD::emptyMap();
@@ -1410,6 +1414,10 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp)
 
 void LLViewerObjectList::updateObjectCost(LLViewerObject* object)
 {
+	if (!object->isRoot())
+	{ //always fetch cost for the parent when fetching cost for children
+		mStaleObjectCost.insert(((LLViewerObject*)object->getParent())->getID());
+	}
 	mStaleObjectCost.insert(object->getID());
 }
 
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index 26765bdd01e00e65c49aa017a59bdf0c2ccbeafe..eff16b6a6e42e872e896a924f6a247fc057f66cd 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -173,6 +173,33 @@ bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) co
 	}
 	return false;
 }
+bool LLViewerParcelOverlay::encroachesOnUnowned(const std::vector<LLBBox>& boxes) const
+{
+	// boxes are expected to already be axis aligned
+	for (U32 i = 0; i < boxes.size(); ++i)
+	{
+		LLVector3 min = boxes[i].getMinAgent();
+		LLVector3 max = boxes[i].getMaxAgent();
+		
+		S32 left   = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+		S32 right  = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+		S32 top    = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+		S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+		
+		for (S32 row = top; row <= bottom; row++)
+		{
+			for (S32 column = left; column <= right; column++)
+			{
+				U8 type = ownership(row, column);
+				if ((PARCEL_SELF != type))
+				{
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+}
 
 BOOL LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const
 {
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index c80baedda6c6256d2fe12af5bee53a3476e1e746..3c6794e7d023313a3ce6f2da3b9b8f87eb111721 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -60,6 +60,7 @@ class LLViewerParcelOverlay : public LLGLUpdate
 	// might be in another parcel. for now, we simply test axis aligned 
 	// bounding boxes which isn't perfect, but is close
 	bool encroachesOwned(const std::vector<LLBBox>& boxes) const;
+	bool encroachesOnUnowned(const std::vector<LLBBox>& boxes) const;
 	
 	BOOL			isSoundLocal(const LLVector3& pos) const;
 
diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h
index 252183b6d71ae450b3fbff8b497339db573bab81..12f6a0dd1c663cf2079a469a7733ea4c903dd1bd 100644
--- a/indra/newview/llviewerprecompiledheaders.h
+++ b/indra/newview/llviewerprecompiledheaders.h
@@ -120,8 +120,8 @@
 
 // Library includes from llvfs
 #include "lldir.h"
-
-// Library includes from llmessage project
+
+// Library includes from llmessage project
 #include "llcachename.h"
 
 #endif
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index bb7170e0f73959a5c2271c6ddb522b2cb09429a1..db2dc531db81a71e9500afcafd13a5e1337b3956 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -77,6 +77,13 @@
 
 const F32 WATER_TEXTURE_SCALE = 8.f;			//  Number of times to repeat the water texture across a region
 const S16 MAX_MAP_DIST = 10;
+// The server only keeps our pending agent info for 60 seconds.
+// We want to allow for seed cap retry, but its not useful after that 60 seconds.
+// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up.
+const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3;
+const F32 CAP_REQUEST_TIMEOUT = 18;
+// Even though we gave up on login, keep trying for caps after we are logged in:
+const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;
 
 typedef std::map<std::string, std::string> CapabilityMap;
 
@@ -86,6 +93,10 @@ class LLViewerRegionImpl {
 		:	mHost(host),
 			mCompositionp(NULL),
 			mEventPoll(NULL),
+			mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS),
+			mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN),
+			mSeedCapAttempts(0),
+			mHttpResponderID(0),
 		    // I'd prefer to set the LLCapabilityListener name to match the region
 		    // name -- it's disappointing that's not available at construction time.
 		    // We could instead store an LLCapabilityListener*, making
@@ -100,6 +111,8 @@ class LLViewerRegionImpl {
 	{
 	}
 
+	void buildCapabilityNames(LLSD& capabilityNames);
+
 	// The surfaces and other layers
 	LLSurface*	mLandp;
 
@@ -132,6 +145,12 @@ class LLViewerRegionImpl {
 	
 	LLEventPoll* mEventPoll;
 
+	S32 mSeedCapMaxAttempts;
+	S32 mSeedCapMaxAttemptsBeforeLogin;
+	S32 mSeedCapAttempts;
+
+	S32 mHttpResponderID;
+
 	/// Post an event to this LLCapabilityListener to invoke a capability message on
 	/// this LLViewerRegion's server
 	/// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
@@ -139,8 +158,6 @@ class LLViewerRegionImpl {
 
 	//spatial partitions for objects in this region
 	std::vector<LLSpatialPartition*> mObjectPartition;
-
-	LLHTTPClient::ResponderPtr  mHttpResponderPtr ;
 };
 
 // support for secondlife:///app/region/{REGION} SLapps
@@ -186,54 +203,51 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder
 {
 	LOG_CLASS(BaseCapabilitiesComplete);
 public:
-    BaseCapabilitiesComplete(LLViewerRegion* region)
-		: mRegion(region)
+    BaseCapabilitiesComplete(U64 region_handle, S32 id)
+		: mRegionHandle(region_handle), mID(id)
     { }
 	virtual ~BaseCapabilitiesComplete()
-	{
-		if(mRegion)
-		{
-			mRegion->setHttpResponderPtrNULL() ;
-		}
-	}
-
-	void setRegion(LLViewerRegion* region)
-	{
-		mRegion = region ;
-	}
+	{ }
 
     void error(U32 statusNum, const std::string& reason)
     {
 		LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL;
-		
-		if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
+		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+		if (regionp)
 		{
-			LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
+			regionp->failedSeedCapability();
 		}
     }
 
     void result(const LLSD& content)
     {
-		if(!mRegion || LLHTTPClient::ResponderPtr(this) != mRegion->getHttpResponderPtr()) //region is removed or responder is not created.
+		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+		if(!regionp) //region was removed
+		{
+			LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;
+			return ;
+		}
+		if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder
 		{
+			LL_WARNS2("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL;
 			return ;
 		}
 
 		LLSD::map_const_iterator iter;
 		for(iter = content.beginMap(); iter != content.endMap(); ++iter)
 		{
-			mRegion->setCapability(iter->first, iter->second);
+			regionp->setCapability(iter->first, iter->second);
 			LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " 
 				<< iter->first << LL_ENDL;
 
 			/* HACK we're waiting for the ServerReleaseNotes */
-			if (iter->first == "ServerReleaseNotes" && mRegion->getReleaseNotesRequested())
+			if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested())
 			{
-				mRegion->showReleaseNotes();
+				regionp->showReleaseNotes();
 			}
 		}
 
-		mRegion->setCapabilitiesReceived(true);
+		regionp->setCapabilitiesReceived(true);
 
 		if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
 		{
@@ -241,15 +255,15 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder
 		}
 	}
 
-    static boost::intrusive_ptr<BaseCapabilitiesComplete> build(
-								LLViewerRegion* region)
+    static boost::intrusive_ptr<BaseCapabilitiesComplete> build( U64 region_handle, S32 id )
     {
-		return boost::intrusive_ptr<BaseCapabilitiesComplete>(
-							 new BaseCapabilitiesComplete(region));
+		return boost::intrusive_ptr<BaseCapabilitiesComplete>( 
+				new BaseCapabilitiesComplete(region_handle, id) );
     }
 
 private:
-	LLViewerRegion* mRegion;
+	U64 mRegionHandle;
+	S32 mID;
 };
 
 
@@ -340,11 +354,6 @@ void LLViewerRegion::initStats()
 
 LLViewerRegion::~LLViewerRegion() 
 {
-	if(mImpl->mHttpResponderPtr)
-	{
-		(static_cast<BaseCapabilitiesComplete*>(mImpl->mHttpResponderPtr.get()))->setRegion(NULL) ;
-	}
-
 	gVLManager.cleanupData(this);
 	// Can't do this on destruction, because the neighbor pointers might be invalid.
 	// This should be reference counted...
@@ -558,6 +567,11 @@ const std::string LLViewerRegion::getSimAccessString() const
 	return accessToString(mSimAccess);
 }
 
+std::string LLViewerRegion::getLocalizedSimProductName() const
+{
+	std::string localized_spn;
+	return LLTrans::findString(localized_spn, mProductName) ? localized_spn : mProductName;
+}
 
 // static
 std::string LLViewerRegion::regionFlagsToString(U32 flags)
@@ -891,14 +905,9 @@ U32 LLViewerRegion::getPacketsLost() const
 	}
 }
 
-void LLViewerRegion::setHttpResponderPtrNULL()
+S32 LLViewerRegion::getHttpResponderID() const
 {
-	mImpl->mHttpResponderPtr = NULL;
-}
-
-const LLHTTPClient::ResponderPtr LLViewerRegion::getHttpResponderPtr() const
-{
-	return mImpl->mHttpResponderPtr;
+	return mImpl->mHttpResponderID;
 }
 
 BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const
@@ -1477,22 +1486,9 @@ void LLViewerRegion::unpackRegionHandshake()
 	msg->sendReliable(host);
 }
 
-void LLViewerRegion::setSeedCapability(const std::string& url)
-{
-	if (getCapability("Seed") == url)
-    {
-		// llwarns << "Ignoring duplicate seed capability" << llendl;
-		return;
-    }
-	
-	delete mImpl->mEventPoll;
-	mImpl->mEventPoll = NULL;
-	
-	mImpl->mCapabilities.clear();
-	setCapability("Seed", url);
-
-	LLSD capabilityNames = LLSD::emptyArray();
 	
+void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
+{
 	capabilityNames.append("AccountingParcel");
 	capabilityNames.append("AccountingSelection");
 	capabilityNames.append("AttachmentResources");
@@ -1524,6 +1520,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("LandResources");
 	capabilityNames.append("MapLayer");
 	capabilityNames.append("MapLayerGod");
+	capabilityNames.append("MeshUploadFlag");
 	capabilityNames.append("NewFileAgentInventory");
 	capabilityNames.append("ParcelPropertiesUpdate");
 	capabilityNames.append("ParcelMediaURLFilterList");
@@ -1565,46 +1562,118 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	
 	// Please add new capabilities alphabetically to reduce
 	// merge conflicts.
+}
+
+void LLViewerRegion::setSeedCapability(const std::string& url)
+{
+	if (getCapability("Seed") == url)
+    {
+		// llwarns << "Ignoring duplicate seed capability" << llendl;
+		return;
+    }
+	
+	delete mImpl->mEventPoll;
+	mImpl->mEventPoll = NULL;
+	
+	mImpl->mCapabilities.clear();
+	setCapability("Seed", url);
+
+	LLSD capabilityNames = LLSD::emptyArray();
+	mImpl->buildCapabilityNames(capabilityNames);
 
 	llinfos << "posting to seed " << url << llendl;
 
-	mImpl->mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ;
-	LLHTTPClient::post(url, capabilityNames, mImpl->mHttpResponderPtr);
+	S32 id = ++mImpl->mHttpResponderID;
+	LLHTTPClient::post(url, capabilityNames, 
+						BaseCapabilitiesComplete::build(getHandle(), id),
+						LLSD(), CAP_REQUEST_TIMEOUT);
+}
+
+S32 LLViewerRegion::getNumSeedCapRetries()
+{
+	return mImpl->mSeedCapAttempts;
+}
+
+void LLViewerRegion::failedSeedCapability()
+{
+	// Should we retry asking for caps?
+	mImpl->mSeedCapAttempts++;
+	std::string url = getCapability("Seed");
+	if ( url.empty() )
+	{
+		LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL;
+		return;
+	}
+	// After a few attempts, continue login.  We will keep trying once in-world:
+	if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin &&
+		 STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() )
+	{
+		LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
+	}
+
+	if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts)
+	{
+		LLSD capabilityNames = LLSD::emptyArray();
+		mImpl->buildCapabilityNames(capabilityNames);
+
+		llinfos << "posting to seed " << url << " (retry " 
+				<< mImpl->mSeedCapAttempts << ")" << llendl;
+
+		S32 id = ++mImpl->mHttpResponderID;
+		LLHTTPClient::post(url, capabilityNames, 
+						BaseCapabilitiesComplete::build(getHandle(), id),
+						LLSD(), CAP_REQUEST_TIMEOUT);
+	}
+	else
+	{
+		// *TODO: Give a user pop-up about this error?
+		LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts.  Giving up!" << LL_ENDL;
+	}
 }
 
 class SimulatorFeaturesReceived : public LLHTTPClient::Responder
 {
 	LOG_CLASS(SimulatorFeaturesReceived);
 public:
-    SimulatorFeaturesReceived(LLViewerRegion* region)
-	: mRegion(region)
+    SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, 
+			S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS)
+	: mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts)
     { }
 	
 	
     void error(U32 statusNum, const std::string& reason)
     {
 		LL_WARNS2("AppInit", "SimulatorFeatures") << statusNum << ": " << reason << LL_ENDL;
+		retry();
     }
-	
+
     void result(const LLSD& content)
     {
-		if(!mRegion) //region is removed or responder is not created.
+		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+		if(!regionp) //region is removed or responder is not created.
 		{
+			LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL;
 			return ;
 		}
 		
-		mRegion->setSimulatorFeatures(content);
+		regionp->setSimulatorFeatures(content);
 	}
-	
-    static boost::intrusive_ptr<SimulatorFeaturesReceived> build(
-																 LLViewerRegion* region)
-    {
-		return boost::intrusive_ptr<SimulatorFeaturesReceived>(
-															   new SimulatorFeaturesReceived(region));
-    }
-	
+
 private:
-	LLViewerRegion* mRegion;
+	void retry()
+	{
+		if (mAttempt < mMaxAttempts)
+		{
+			mAttempt++;
+			LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'.  Retry #" << mAttempt << LL_ENDL;
+			LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);
+		}
+	}
+	
+	std::string mRetryURL;
+	U64 mRegionHandle;
+	S32 mAttempt;
+	S32 mMaxAttempts;
 };
 
 
@@ -1623,7 +1692,7 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
 	else if (name == "SimulatorFeatures")
 	{
 		// kick off a request for simulator features
-		LLHTTPClient::get(url, new SimulatorFeaturesReceived(this));
+		LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT);
 	}
 	else
 	{
@@ -1713,6 +1782,18 @@ bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector<
 				&& mParcelOverlay->encroachesOwned(boxes)) );
 }
 
+bool LLViewerRegion::childrenObjectReturnable( const std::vector<LLBBox>& boxes ) const
+{
+	bool result = false;
+	result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0;
+	return result;
+}
+
+void LLViewerRegion::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions )
+{
+	mImpl->mLandp->getNeighboringRegions( uniqueRegions );
+}
+
 void LLViewerRegion::showReleaseNotes()
 {
 	std::string url = this->getCapability("ServerReleaseNotes");
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index f68b51ea658d436eecb9bfb4a9def61cc7c53360..ef1a6d285c2c77fc6c6b7a30f943c2e5db4b5f95 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -192,7 +192,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	S32 getSimCPURatio()                   const { return mCPURatio; }
 	const std::string& getSimColoName()    const { return mColoName; }
 	const std::string& getSimProductSKU()  const { return mProductSKU; }
-	const std::string& getSimProductName() const { return mProductName; }
+	std::string getLocalizedSimProductName() const;
 
 	// Returns "Sandbox", "Expensive", etc.
 	static std::string regionFlagsToString(U32 flags);
@@ -226,11 +226,12 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 
 	U32	getPacketsLost() const;
 
-	void setHttpResponderPtrNULL();
-	const LLHTTPClient::ResponderPtr getHttpResponderPtr() const;
+	S32 getHttpResponderID() const;
 
 	// Get/set named capability URLs for this region.
 	void setSeedCapability(const std::string& url);
+	void failedSeedCapability();
+	S32 getNumSeedCapRetries();
 	void setCapability(const std::string& name, const std::string& url);
 	// implements LLCapabilityProvider
     virtual std::string getCapability(const std::string& name) const;
@@ -320,6 +321,10 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	LLSpatialPartition* getSpatialPartition(U32 type);
 
 	bool objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const;
+	bool childrenObjectReturnable( const std::vector<LLBBox>& boxes ) const;
+
+	void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions );
+	
 public:
 	struct CompareDistance
 	{
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index f04337ca89e569bdc73938c88012a63aec6658d3..8d4f9b346f1a019da2795f89d4850844ad7db742 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -528,8 +528,8 @@ class LLDebugText
 				addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost));
 				ypos += y_inc;
 
-				addText(xpos, ypos, llformat("    %.1f KTris, %.1f/%.1f KB, %d objects",
-										count/1024.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
+				addText(xpos, ypos, llformat("    %.3f KTris, %.1f/%.1f KB, %d objects",
+										count/1000.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
 				ypos += y_inc;
 			
 			}
@@ -726,19 +726,6 @@ class LLDebugText
 			}
 		}				
 
-		if (gSavedSettings.getBOOL("DebugShowUploadCost"))
-		{
-			addText(xpos, ypos, llformat("       Meshes: L$%d", gPipeline.mDebugMeshUploadCost));
-			ypos += y_inc/2;
-			addText(xpos, ypos, llformat("    Sculpties: L$%d", gPipeline.mDebugSculptUploadCost));
-			ypos += y_inc/2;
-			addText(xpos, ypos, llformat("     Textures: L$%d", gPipeline.mDebugTextureUploadCost));
-			ypos += y_inc/2;
-			addText(xpos, ypos, "Upload Cost: ");
-						
-			ypos += y_inc;
-		}
-
 		//temporary hack to give feedback on mesh upload progress
 		if (!gMeshRepo.mUploads.empty())
 		{
@@ -747,10 +734,8 @@ class LLDebugText
 			{
 				LLMeshUploadThread* thread = *iter;
 
-				addText(xpos, ypos, llformat("Mesh Upload -- price quote: %d:%d | upload: %d:%d | create: %d", 
-								thread->mPendingConfirmations, thread->mUploadQ.size()+thread->mTextureQ.size(),
-								thread->mPendingUploads, thread->mConfirmedQ.size()+thread->mConfirmedTextureQ.size(),
-								thread->mInstanceQ.size()));
+				addText(xpos, ypos, llformat("Mesh Uploads: %d", 
+								thread->mPendingUploads));
 				ypos += y_inc;
 			}
 		}
@@ -3161,6 +3146,12 @@ void LLViewerWindow::updateLayout()
 		//gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible());
 	}
 
+	LLFloaterBuildOptions* build_options_floater = LLFloaterReg::getTypedInstance<LLFloaterBuildOptions>("build_options");
+	if (build_options_floater && build_options_floater->getVisible())
+	{
+		build_options_floater->updateGridMode();
+	}
+
 	// Always update console
 	if(gConsole)
 	{
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 3f98df9eb9f40c28b3d07b7096d47bbe2dd5ecd3..b5be3cd552cea7d3400ab9b0ecabc8f1d8974e3d 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1123,14 +1123,20 @@ void LLVOAvatar::initClass()
 	// Process XML data
 
 	// avatar_skeleton.xml
-	llassert(!sAvatarSkeletonInfo);
+	if (sAvatarSkeletonInfo)
+	{ //this can happen if a login attempt failed
+		delete sAvatarSkeletonInfo;
+	}
 	sAvatarSkeletonInfo = new LLVOAvatarSkeletonInfo;
 	if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot()))
 	{
 		llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl;
 	}
 	// parse avatar_lad.xml
-	llassert(!sAvatarXmlInfo);
+	if (sAvatarXmlInfo)
+	{ //this can happen if a login attempt failed
+		deleteAndClear(sAvatarXmlInfo);
+	}
 	sAvatarXmlInfo = new LLVOAvatarXmlInfo;
 	if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
 	{
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 66ba6249d3a135fb2d2b279b01a0cc54e4b3da32..ef21e7373e48a0e51890ef919a12d9a56183182a 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -755,6 +755,11 @@ void LLVOSky::calcSkyColorWLVert(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLCo
 	// project the direction ray onto the sky dome.
 	F32 phi = acos(Pn[1]);
 	F32 sinA = sin(F_PI - phi);
+	if (fabsf(sinA) < 0.01f)
+	{ //avoid division by zero
+		sinA = 0.01f;
+	}
+
 	F32 Plen = dome_radius * sin(F_PI + phi + asin(dome_offset_ratio * sinA)) / sinA;
 
 	Pn *= Plen;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 4c137d339479ef2906916846f5e699777d9d50c9..30216f02dbd4553e6861be5003f1b8000735bf7a 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1017,6 +1017,9 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 	if (is404)
 	{
 		setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI));
+		//render prim proxy when mesh loading attempts give up
+		volume_params.setSculptID(LLUUID::null, LL_SCULPT_TYPE_NONE);
+
 	}
 
 	if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
@@ -3096,7 +3099,7 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
 
 F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
 {
-	F32 radius = getScale().length();
+	F32 radius = getScale().length()*0.5f;
 
 	if (isMesh())
 	{	
diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp
index b5f53232cc2aa397306707bafadd31699bfb11af..2425b96678d1d0d6cdccbdd96f12e104a897c6e6 100644
--- a/indra/newview/llwlhandlers.cpp
+++ b/indra/newview/llwlhandlers.cpp
@@ -2,31 +2,25 @@
  * @file llwlhandlers.cpp
  * @brief Various classes which handle Windlight-related messaging
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * 
- * Copyright (c) 2009, Linden Research, Inc.
- * 
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
  * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h
index 213bc7c7ce55b6f8fee74e8c0cc6486827a4b53d..23558876da73678891775d1ff033be897778007b 100644
--- a/indra/newview/llwlhandlers.h
+++ b/indra/newview/llwlhandlers.h
@@ -2,31 +2,25 @@
  * @file llwlhandlers.h
  * @brief Headers for classes in llwlhandlers.cpp
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * 
- * Copyright (c) 2009, Linden Research, Inc.
- * 
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
  * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index dfcc7396ba6695f83996ca8930712a9a7400f93d..4899df13e5810846d4753f47d0c339502b495992 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3741,52 +3741,55 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 	LLVertexBuffer::unbind();
 	LLGLState::checkStates();
 
-	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
-
-	if (!sReflectionRender)
+	if (!LLPipeline::sImpostorRender)
 	{
-		renderHighlights();
-	}
+		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
 
-	// Contains a list of the faces of objects that are physical or
-	// have touch-handlers.
-	mHighlightFaces.clear();
+		if (!sReflectionRender)
+		{
+			renderHighlights();
+		}
 
-	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
+		// Contains a list of the faces of objects that are physical or
+		// have touch-handlers.
+		mHighlightFaces.clear();
+
+		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
 	
-	renderDebug();
+		renderDebug();
 
-	LLVertexBuffer::unbind();
+		LLVertexBuffer::unbind();
 	
-	if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
-	{
-		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+		if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
 		{
-			// Render debugging beacons.
-			gObjectList.renderObjectBeacons();
-			gObjectList.resetObjectBeacons();
+			if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+			{
+				// Render debugging beacons.
+				gObjectList.renderObjectBeacons();
+				gObjectList.resetObjectBeacons();
+			}
+			else
+			{
+				// Make sure particle effects disappear
+				LLHUDObject::renderAllForTimer();
+			}
 		}
 		else
 		{
 			// Make sure particle effects disappear
 			LLHUDObject::renderAllForTimer();
 		}
-	}
-	else
-	{
-		// Make sure particle effects disappear
-		LLHUDObject::renderAllForTimer();
-	}
 
-	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
+		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
 
-	//HACK: preserve/restore matrices around HUD render
-	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
-	{
-		for (U32 i = 0; i < 16; i++)
+		//HACK: preserve/restore matrices around HUD render
+		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 		{
-			gGLModelView[i] = saved_modelview[i];
-			gGLProjection[i] = saved_projection[i];
+			for (U32 i = 0; i < 16; i++)
+			{
+				gGLModelView[i] = saved_modelview[i];
+				gGLProjection[i] = saved_projection[i];
+			}
 		}
 	}
 
@@ -4220,63 +4223,6 @@ void LLPipeline::renderDebug()
 		}
 	}
 
-	if (gSavedSettings.getBOOL("DebugShowUploadCost"))
-	{
-		std::set<LLUUID> textures;
-		std::set<LLUUID> sculpts;
-		std::set<LLUUID> meshes;
-		
-		BOOL selected = TRUE;
-		if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
-		{
-			selected = FALSE;
-		}
-			
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
-		{
-			LLSpatialGroup* group = *iter;
-			LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
-			for (LLSpatialGroup::OctreeNode::element_iter elem = node->getData().begin(); elem != node->getData().end(); ++elem)
-			{
-				LLDrawable* drawable = *elem;
-				LLVOVolume* volume = drawable->getVOVolume();
-				if (volume && volume->isSelected() == selected)
-				{
-					for (U32 i = 0; i < volume->getNumTEs(); ++i)
-					{
-						LLTextureEntry* te = volume->getTE(i);
-						textures.insert(te->getID());
-					}
-
-					if (volume->isSculpted())
-					{
-						LLUUID sculpt_id = volume->getVolume()->getParams().getSculptID();
-						if (volume->isMesh())
-						{
-							meshes.insert(sculpt_id);
-						}
-						else
-						{
-							sculpts.insert(sculpt_id);
-						}
-					}
-				}
-			}
-		}
-
-		gPipeline.mDebugTextureUploadCost = textures.size() * 10;
-		gPipeline.mDebugSculptUploadCost = sculpts.size()*10;
-		
-		U32 mesh_cost = 0;
-
-		for (std::set<LLUUID>::iterator iter = meshes.begin(); iter != meshes.end(); ++iter)
-		{
-			mesh_cost += gMeshRepo.getResourceCost(*iter)*10;
-		}
-
-		gPipeline.mDebugMeshUploadCost = mesh_cost;
-	}
-
 	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
 	{
 		LLVertexBuffer::unbind();
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index 4c0fbd280b394d26eb33bb1695ca6853d5c6e27b..c3999501eb8852e41d6a9264000b97f6aa3fea2c 100644
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -454,6 +454,7 @@ Købsprisen for dette land er ikke refunderet til ejeren. Hvis en dedikeret parv
 Dediker disse [AREA] m² land til gruppen &apos;[GROUP_NAME]&apos;?
 	</notification>
 	<notification name="ErrorMessage">
+		[ERROR_MESSAGE]
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="AvatarMovedDesired">
diff --git a/indra/newview/skins/default/xui/da/panel_places.xml b/indra/newview/skins/default/xui/da/panel_places.xml
index fe8ca69f344d2f384c2691f3f01a2592448de23f..c555f2fb0943d9d93593694bc552f8bf12962cb9 100644
--- a/indra/newview/skins/default/xui/da/panel_places.xml
+++ b/indra/newview/skins/default/xui/da/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="â–¼" name="overflow_btn" tool_tip="Vis flere valg"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="Profil" name="profile_btn" tool_tip="Vis profil for sted"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/de/panel_outfit_edit.xml b/indra/newview/skins/default/xui/de/panel_outfit_edit.xml
index 632f414747c9570165c465cfdc95c4c59800c7fb..1af0492aa165beedee93b9d37903d6251e66fdd7 100644
--- a/indra/newview/skins/default/xui/de/panel_outfit_edit.xml
+++ b/indra/newview/skins/default/xui/de/panel_outfit_edit.xml
@@ -46,8 +46,8 @@
 	</panel>
 	<panel name="save_revert_button_bar">
 		<layout_stack name="button_bar_ls">
-			<layout_panel name="save_btn_lp">
-				<button label="Speichern" name="save_btn"/>
+			<layout_panel name="save_btn_lp" width="61">
+				<button label="Speichern" name="save_btn" width="60" />
 			</layout_panel>
 			<layout_panel name="revert_btn_lp">
 				<button label="Änderungen rückgängig machen" name="revert_btn" tool_tip="Zur zuletzt gespeicherten Version zurückkehren"/>
diff --git a/indra/newview/skins/default/xui/de/panel_places.xml b/indra/newview/skins/default/xui/de/panel_places.xml
index 36c77d4fe1023747b71a4136b805927e48709187..602ffff94d42763e29ba2decd58b9f0071685fe9 100644
--- a/indra/newview/skins/default/xui/de/panel_places.xml
+++ b/indra/newview/skins/default/xui/de/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="▼" name="overflow_btn" tool_tip="Zusätzliche Optionen anzeigen"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="Profil" name="profile_btn" tool_tip="Ortsprofil anzeigen"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/en/floater_build_options.xml b/indra/newview/skins/default/xui/en/floater_build_options.xml
index 56230e912c26737e23f4791916c38bbe8bceb0d9..c247a12e7a19aaa0c9cca25b62b4722043edac6d 100644
--- a/indra/newview/skins/default/xui/en/floater_build_options.xml
+++ b/indra/newview/skins/default/xui/en/floater_build_options.xml
@@ -2,27 +2,84 @@
 <floater
  legacy_header_height="18"
  follows="right"
- height="170"
+ height="198"
  layout="topleft"
  name="build options floater"
  help_topic="build_options_floater"
  save_rect="true"
  title="GRID OPTIONS"
  width="264">
+ 	<floater.string
+     name="grid_screen_text">
+        Screen
+    </floater.string>
+    <floater.string
+     name="grid_local_text">
+        Local
+    </floater.string>
+    <floater.string
+     name="grid_world_text">
+        World
+    </floater.string>
+    <floater.string
+     name="grid_reference_text">
+        Reference
+    </floater.string>
+    <floater.string
+     name="grid_attachment_text">
+        Attachment
+    </floater.string>
+    <text
+     type="string"
+     length="1"
+     follows="left|top"
+     height="16"
+     layout="topleft"
+     left="10"
+     tool_tip="Grid opacity"
+     name="grid_opacity_label"
+     top_pad="30"
+     width="123">
+        Mode
+    </text>
+    <combo_box
+     height="23"
+     layout="topleft"
+     left_pad="9"
+     follows="left|top"
+     name="combobox grid mode"
+     tool_tip="Choose the type of grid ruler for positioning the object"
+     top_delta="-3"
+     width="108">
+      <combo_box.item
+       label="World grid"
+       name="World"
+       value="World" />
+      <combo_box.item
+       label="Local grid"
+       name="Local"
+       value="Local" />
+      <combo_box.item
+       label="Reference grid"
+       name="Reference"
+       value="Reference" />
+       <combo_box.commit_callback
+      function="GridOptions.gridMode"/>
+    </combo_box>
     <spinner
      control_name="GridResolution"
      follows="left|top"
      height="23"
      initial_value="1"
-     label="Grid Units (meters)"
-     label_width="160"
+     label="Units (meters)"
+     label_width="130"
      layout="topleft"
      left="10"
      max_val="5"
      min_val="0.01"
      name="GridResolution"
-     top="25"
-     width="230" />
+     top_pad="4"
+     width="200" />
     <spinner
      control_name="GridDrawSize"
      decimal_digits="1"
@@ -30,15 +87,15 @@
      height="23"
      increment="0.5"
      initial_value="5"
-     label="Grid Extents (meters)"
-     label_width="160"
+     label="Extents (meters)"
+     label_width="130"
      layout="topleft"
      left_delta="0"
      max_val="50"
      min_val="1"
      name="GridDrawSize"
      top_pad="0"
-     width="230" />
+     width="200" />
     <check_box
      control_name="GridSubUnit"
      height="16"
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index f58595b3c57246ce86a918f1f1b570477b9bc2f3..1d4a1d4827dbcecd94dd0164313f84e51ef80bd3 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater can_close="true" can_drag_on_left="false" can_minimize="false"
      can_resize="true" height="550" min_height="550" min_width="620"
-     name="Model Preview" title="Upload Model" width="620">
+     name="Model Preview" title="Upload Model" width="620"
+      help_topic="upload_model" >
 
   <string name="status_idle">Idle</string>
   <string name="status_parse_error">Dae parsing issue - see log for details.</string>
@@ -23,6 +24,7 @@
   <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
   <string name="decomposing">Analyzing...</string>
   <string name="simplifying">Simplifying...</string>
+  <string name="tbd">TBD</string>
   
 
   <text left="15" bottom="25" follows="top|left" height="15" name="name_label">
@@ -70,43 +72,89 @@
     width="290"
     height="290"
     follows="all"/>
-
-  <text bottom_delta="25" left="25" width="100" follows="bottom|left">Upload Details</text>
-  <panel top_pad="5" border="true" left="15" width="290" height="70" follows="bottom|left"
-          bevel_style="none" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
-    <text left="25" follows="bottom|left" width="140" height="15" name="streaming cost">
-      Resource Cost: [COST]
-    </text>
-    <text left="25" top_pad="5" width="140" follows="bottom|left" height="15" name="physics cost">
-      Physics Cost: [COST]
+    
+    <text
+     font="SansSerif"
+	 bottom_delta="15"
+     left_delta="0"
+     name="warning_title"
+     text_color="Yellow"
+     visible="false">
+     WARNING:
     </text>
-    <text left="25" top_pad="5" follows="bottom|left" height="15" name="upload fee">
-      Upload Fee: N/A
-    </text>
-  </panel>
+    <text
+     text_color="White"
+     height="40"
+	 width="290"
+	 top_delta="15"
+     left_delta="0"
+     name="warning_message"
+     parse_urls="true"
+     wrap="true"
+     visible="false">
+     You will not be able to complete the final upload of this model to the Second Life servers. [[VURL] Find out how] to get enabled for mesh model uploads.</text>
 
-  <check_box
-	height="16"
+  <text
+	height="65"
+	top_delta="45"
 	left_delta="0"
-	name="confirm_checkbox"
-	top_pad="15"
-	follows="bottom|left"
-	width="16" />
+	name="weights_text"
+	width="80"
+	word_wrap="true" 
+	>
+Download:
+Physics:
+Server:
+
+Prim equivs:
+  </text>
 
   <text
-	height="30"
-	width="570"
+	height="65"
+	top_delta="0"
+	left_delta="80"
+	name="weights"
+	width="70"
 	word_wrap="true" 
-	left_delta="25"
-	top_delta="0">I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more]</text>
-  <text left="10" bottom="540" width="290" height="15" follows="bottom|left|right" name="status">[STATUS]</text>
+	>
+[ST]
+[PH]
+[SIM]
 
-  
-  <button bottom="540" left="300"  follows="bottom|right" height="20" label="Defaults"
-	     width="80" name="reset_btn" tool_tip="Reset to defaults"/>
-  <button bottom="540" left="430"  follows="bottom|right" height="20" label="Upload"
-	     width="80" name="ok_btn" tool_tip="Upload to simulator"/>
-  <button left_pad="10" follows="right|bottom" height="20" width="80" label="Cancel" name="cancel_btn"/>
+[EQ]
+  </text>
+
+<!--
+  <text
+	height="65"
+	top_delta="0"
+	left_delta="70"
+	name="price_breakdown_text"
+	width="80"
+	word_wrap="true" 
+	>
+Streaming:
+Physics:
+Instances:
+Textures:
+Model:
+  </text>
+
+  <text
+	height="65"
+	top_delta="0"
+	left_delta="80"
+	name="price_breakdown"
+	width="65"
+	word_wrap="true" 
+	>
+L$ [STREAMING]
+L$ [PHYSICS]
+L$ [INSTANCES]
+L$ [TEXTURES]
+L$ [MODEL]
+  </text>
+    -->
 
   <tab_container
     follows="right|top|bottom"
@@ -122,7 +170,8 @@
     <panel
       border="true"
       label="Level of Detail"
-      name="lod_panel">
+      name="lod_panel"
+      help_topic="upload_model_lod">
 
       <text left="10" width="240" bottom="20" height="15" follows="left|top" name="lod_table_header">
         Select Level of Detail:
@@ -245,7 +294,8 @@
     <panel
       border="true"
       label="Physics"
-      name="physics_panel">
+      name="physics_panel"
+      help_topic="upload_model_physics">
 
       <!-- PHYSICS GEOMETRY-->
       <panel
@@ -386,7 +436,9 @@
     <panel
       border="true"
       label="Modifiers"
-      name="modifiers_panel">
+      name="modifiers_panel"
+      help_topic="upload_model_modifiers">
+
       <text left="10" width="90" bottom="30" follows="top|left" height="15">
         Scale:
       </text>
@@ -416,6 +468,26 @@
 
     </panel>
   </tab_container>
+
+  <text
+	height="16"
+	left_delta="5"
+	bottom_delta="30"
+	name="upload_fee"
+	width="300"
+	follows="bottom|right"
+	word_wrap="true" 
+	>
+	    Upload fee: L$ [FEE]
+  </text>
+  
+  <button bottom="540" left="10"  follows="bottom|left" height="20" label="Set to defaults"
+	     width="100" name="reset_btn" tool_tip="Set to defaults"/>
+  <button left="310"  follows="bottom|right" height="20" label="Calculate weights &amp; fee"
+	     width="150" name="calculate_btn" tool_tip="Calculate weights &amp; fee" top_delta="0"/>
+  <button bottom="540" left="310"  follows="bottom|right" height="20" label="Upload"
+	     width="80" name="ok_btn" tool_tip="Upload to simulator" visible="false"/>
+  <button right="-10" follows="right|bottom" height="20" width="80" label="Cancel" name="cancel_btn" top_delta="0"/>
   
   <!--
   <button bottom_delta="0" left="10" width="120" name="auto fill" label="Generate LOD" tool_tip="Automatically generate levels of detail"/>
diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml
index 8603682e3ab3129124513131c3d4bd0f2621325d..b5a5ff53424b47e87db657f774f46256eba24d27 100644
--- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml
@@ -45,24 +45,6 @@
 		<button.commit_callback
 		function="Wizard.Review"/>
 	</button>
-	<button
-	 top="32"
-	 left="210"
-	 height="32"
-	 name="physics2_btn"
-	 label="3. Physics"
-	 tab_stop="false"
-	 enabled="false"
-	 border="false"
-	 image_unselected="BreadCrumbBtn_Middle_Off"
-	 image_selected="BreadCrumbBtn_Middle_Press"
-	 image_hover_unselected="BreadCrumbBtn_Middle_Over"
-	 image_disabled="BreadCrumbBtn_Middle_Disabled"
-	 image_disabled_selected="BreadCrumbBtn_Middle_Disabled"
-	 width="110">
-		<button.commit_callback
-		function="Wizard.Physics2"/>
-	</button>
 	<button
 	 top="32"
 	 left="210"
@@ -140,41 +122,50 @@
 			 height="10"
 			 font="SansSerifBig"
 			 layout="topleft">
-				Upload Model
+				Choose model file
 			</text>
 		</panel>
-		<text
-		 top_pad="14"
-		 width="460"
-		 height="20"
-		 name="description"
-		 font="SansSerifSmall"
-		 layout="topleft"
-		 word_wrap="true"
-		 left_delta="5">
-			This wizard will help you import mesh models to Second Life.  First specify a file containing the model you wish to import.  Second Life supports COLLADA (.dae) files.
-		</text>
 		<panel
-		 top_delta="40"
+		 top_pad="14"
 		 left="15"
-		 height="270"
+		 height="310"
 		 width="505"
 		 name="content"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
 		 background_opaque="true">
+            <text
+			 height="32"
+			 left="10"
+			 name="advanced_users_text"
+			 text_color="White"
+			 top="15"
+			 width="320"
+			 word_wrap="true">
+				Advanced users: If you are familiar with 3D content creation tools you may wish to use the Advanced Uploader.
+			</text>
+			<button
+			 follows="left|top"
+			 height="20"
+			 label="Switch to Advanced"
+			 layout="topleft"
+			 left_delta="0"
+			 name="switch_to_advanced"
+			 top_pad="5"
+			 width="130">
+			</button>
 			<text
 			 type="string"
 			 length="1"
 			 text_color="White" 
 			 follows="left|top"
-			 top="10"
+			 top_pad="30"
 			 height="10"
 			 layout="topleft"
-			 left_delta="10"
+			 left_delta="0"
 			 name="Cache location"
-			 width="300">
-				Filename:
+			 width="320">
+				Choose model file to upload
 			</text>
 			<line_editor
 			 border_style="line"
@@ -187,7 +178,7 @@
 			 max_length="4096"
 			 name="lod_file"
 			 top_pad="5"
-			 width="220" />
+			 width="230" />
 			<button
 			 follows="left|top"
 			 height="23"
@@ -200,23 +191,27 @@
 			 width="85">
 			</button>
 			<text
-			 top_delta="-15"
-			 width="200"
-			 height="15"
-			 font="SansSerifSmall"
+			 type="string"
+			 length="1"
+			 text_color="White" 
+			 follows="left|top"
+			 top_pad="5"
+			 height="10"
 			 layout="topleft"
-			 text_color="White"
-			 left_pad="19">
-				Model Preview:
+			 left="10"
+			 name="Cache location"
+			 width="320">
+				Second Life supports COLLADA (.dae) files
 			</text>
 			<!-- Placeholder panel for 3D preview render -->
 			<panel
-			 left_delta="0"
-			 top_pad="0"
-			 name="preview_panel"
+			 top="30"
+			 right="-10"
+			 name="choose_file_preview_panel"
 			 bevel_style="none"
 			 highlight_light_color="0.09 0.09 0.09 1"
 			 border="true"
+			 border_style="line"
 			 height="150"
 			 follows="all"
 			 width="150">
@@ -225,7 +220,7 @@
 			 top_pad="10"
 			 width="130"
 			 height="14"
-			 left="340"
+			 left_delta="0"
 			 text_color="White"
 			 word_wrap="true">
 				Dimensions (meters):
@@ -238,15 +233,7 @@
 			 text_color="White"
 			 name="dimensions"
 			 left_delta="0">
-				X:         Y:         Z: 
-			</text>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_dividers"
-			 left_delta="41">
-				 |               |   
+				X         Y         Z 
 			</text>
 			<text
 			 top_delta="0"
@@ -266,23 +253,26 @@
 			 height="15"
 			 name="dimension_z"
 			 left="450"/>
-			<text
-			 top="100"
-			 width="320"
-			 height="15"
-			 left="10"
-			 text_color="White" 
-			 word_wrap="true">
-				Note:
-			</text>
-			<text
-			 top_pad="0"
-			 width="320"
-			 height="40"
-			 left="10"
-			 word_wrap="true">
-Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] .
-			</text>
+            <text
+             height="16"
+             left="10"
+             name="warning_label"
+             text_color="Yellow"
+             top="200"
+             visible="false"
+             width="320">
+                WARNING:
+            </text>
+            <text
+             height="50"
+             left="10"
+             name="warning_text"
+             top_pad="0"
+             visible="false"
+             width="320"
+             word_wrap="true">
+                You will not be able to complete the final step of uploading this model to the Second Life servers. [secondlife:///app/floater/learn_more Find out how] to set up your account for mesh model uploads. 
+            </text>
 		</panel>
 	</panel>
 
@@ -291,7 +281,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		 height="388"
 		 top_delta="0"
 		 name="optimize_panel"
-		 visible="false"
+		 visible="true"
 		 width="535"
 		 left="0">
 		<panel
@@ -312,7 +302,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 			 height="10"
 			 font="SansSerifBig"
 			 layout="topleft">
-				Optimize
+				Optimize model
 			</text>
 		</panel>
 		<text
@@ -324,7 +314,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		 name="description"
 		 word_wrap="true"
 		 left_delta="5">
-			This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue.
+			We have optimized the model for performance. Adjust it further if you wish.
 		</text>
 		<panel
 		 top_delta="40"
@@ -411,116 +401,89 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 				 bg_opaque_color="DkGray2"
 				 background_visible="true"
 				 background_opaque="true">
-			<text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
-				Model Preview:
-			</text>
-			<combo_box left_pad="5" top_delta="-5"  follows="left|top" list_position="below" height="22"
-	     name="preview_lod_combo2" width="90" tool_tip="LOD to view in preview render">
-				<combo_item name="high">
-					High
-				</combo_item>
-				<combo_item name="medium">
-					Medium
-				</combo_item>
-				<combo_item name="low">
-					Low
-				</combo_item>
-				<combo_item name="lowest">
-					Lowest
-				</combo_item>
-			</combo_box>
-			<panel
-				 left="10"
-				 top_pad="5"
-				 name="preview_panel"
-				 bevel_style="none"
-				 highlight_light_color="0.09 0.09 0.09 1"
-				 border_style="line"
-				 border="true"
-				 height="185"
-				 follows="all"
-				 width="185">
-			</panel>
-			<text top="45" left="214" text_color="White" font="SansSerifSmallBold" halign="center" width="110" height="30" wrap="true">Higher Performance</text>
-			<text top="75" left="204" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text>
-			<text top="45" left="378" text_color="White" font="SansSerifSmallBold" halign="center" width="90" height="30" wrap="true">Higher Accuracy</text>
-			<text top="75" left="364" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text>
+			<text top="69" left="10" text_color="White" font="SansSerifSmallBold" width="120" height="16" wrap="true">Performance</text>
+			<text top="85" left="10" width="120" word_wrap="true" font="SansSerifSmall" height="40">Faster rendering
+Less detail
+Lower prim weight</text>
+			<text top="69" left="184" text_color="White" font="SansSerifSmallBold" width="120" height="16" wrap="true">Accuracy</text>
+			<text top="85" left="184" width="120" word_wrap="true" font="SansSerifSmall" height="40">Slower rendering
+More detail
+Higher prim weight</text>
 
-			<slider
+          <slider
 		   follows="left|top"
 		   height="20"
 		   increment="1"
 		   layout="topleft"
-		   left="204"
-		   max_val="3"
-		   initial_value="2"
+		   left="10"
+		   max_val="2"
+		   initial_value="1"
 		   min_val="0"
 		   name="accuracy_slider"
 		   show_text="false"
 		   top="130"
 		   width="290" />
-			<text 
+          <text 
 			font="SansSerifSmall" 
 			top_pad="0"  
-			width="300" 
+			width="5" 
 			left_delta="6" 
 			height="4">'  
-      </text>
-
-
-			<icon
-				 top_pad="14"
-				 left_delta="0"
-				 width="280"
-				 height="2"
-				 image_name="model_wizard\divider_line.png"/>
-	
-			<text top_delta="20" width="200" text_color="White" left_delta="50" name="streaming cost"  height="20">Resource Cost:    [COST]</text>
-			<text
-						 top_pad="15"
-						 width="130"
-						 height="14"
-						 left="10"
-						 text_color="White"
-						 word_wrap="true">
-				Dimensions (meters):
-			</text>
-			<text
-			 top_pad="0"
-			 width="160"
-			 height="15"
-			 font="SansSerifSmallBold"
-			 text_color="White"
-			 name="dimensions"
-			 left_delta="0">
-				X:         Y:         Z:
-			</text>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_dividers"
-			 left_delta="41">
-				|               |
+          </text>
+          <text 
+			font="SansSerifSmall" 
+			top_delta="0"  
+			width="5" 
+			left_delta="137" 
+			height="4">'  
+          </text>
+          <text 
+			font="SansSerifSmall" 
+			top_delta="0"  
+			width="5" 
+			left_delta="137" 
+			height="4">'  
+          </text>
+          <button
+			follows="left|top"
+			height="20"
+			label="Recalculate Geometry"
+			layout="topleft"
+			left="80"
+			name="recalculate_geometry_btn"
+			top_pad="15"
+            width="150">
+          </button>
+			<text top="10" right="-10" width="185" text_color="White" follows="left|top" height="15" name="lod_label">
+				Geometry preview
 			</text>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_x"
-			 left_delta="-25"/>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_y"
-			 left_delta="46"/>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_z"
-			 left_delta="46"/>
+			<panel
+				 right="-10"
+				 top="32"
+				 name="optimize_preview_panel"
+				 bevel_style="none"
+				 highlight_light_color="0.09 0.09 0.09 1"
+				 border_style="line"
+				 border="true"
+				 height="185"
+				 follows="all"
+				 width="185">
+			</panel>
+			<combo_box left_delta="75" top_pad="10"  follows="left|top" list_position="below" height="22"
+	     name="preview_lod_combo" width="110" tool_tip="LOD to view in preview render">
+				<combo_item name="high">
+					High detail
+				</combo_item>
+				<combo_item name="medium">
+					Medium detail
+				</combo_item>
+				<combo_item name="low">
+					Low detail
+				</combo_item>
+				<combo_item name="lowest">
+					Lowest detail
+				</combo_item>
+			</combo_box>
 		</panel>
 	</panel>
 
@@ -549,7 +512,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 			 font="SansSerifBig"
 			 text_color="White" 
 			 layout="topleft">
-				Physics
+				Adjust physics
 			</text>
 		</panel>
 		<text
@@ -561,7 +524,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		 name="description"
 		 word_wrap="true"
 		 left_delta="5">
-			The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used:
+			We will create a shape for the outer hull of the model. Adjust the shape's detail level as needed for the intended purpose of your model.
 		</text>
     <panel
 		 top_delta="44"
@@ -572,172 +535,94 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
 		 background_opaque="true">
-      <text top="15" left="20" text_color="White" font="SansSerifSmallBold" width="110" height="30" wrap="true" halign="center">Higher Performance</text>
-      <text top="45" left="10" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text>
-      <text top="15" left="372" text_color="White" font="SansSerifSmallBold" width="90" height="30" wrap="true" halign="center">Higher Accuracy</text>
-      <text top="45" left="360" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text>
+      <text top="10" left="10" text_color="White" font="SansSerifSmallBold" width="120" halign="right" height="16" wrap="true">Performance</text>
+      <text top="26" left="10" width="120" word_wrap="true" font="SansSerifSmall" halign="right" height="40">Faster rendering
+Less detail
+Lower prim weight</text>
+      <text top="174" left="10" text_color="White" font="SansSerifSmallBold" width="120" halign="right" height="16" wrap="true">Accuracy</text>
+      <text top="190" left="10" width="120" word_wrap="true" font="SansSerifSmall" halign="right" height="40">Slower rendering
+More detail
+Higher prim weight</text>
 
       <slider
 		   follows="left|top"
-		   height="22"
+		   height="190"
 		   increment=".1"
 		   layout="topleft"
-		   left="20"
+		   left="140"
 		   max_val="1"
 		   initial_value="0.5"
 		   min_val="0"
 		   name="physics_slider"
+		   orientation="vertical"
 		   show_text="false"
-		   top="90"
-		   width="440" />
-      <text
-			font="SansSerifSmall"
-			top_pad="0"
-			width="500"
-			left_delta="6"
-			height="4">'             '             '             '             '              '             '             '             '              '             '</text>
-      <text top_pad="10" width="110" halign="center" word_wrap="true" left="25"  height="40">Recommended for solid objects</text>
-      <text top_delta="0" width="110" halign="center" word_wrap="true" left="190"  height="40">Recommended for buildings</text>
-      <text top_delta="0" width="110" halign="center" word_wrap="true" left="350"  height="40">Recommended for vehicles</text>
-
-
-		<icon
-			 top_pad="5"
-			 left="15"
-			 width="470"
-			 height="2"
-			 image_name="model_wizard\divider_line.png"/>
-		
-	<text top_delta="30" width="180" text_color="White" left="160" name="streaming cost"  height="20">Resource Cost:       [COST]</text>
- 
-    </panel>
-	</panel>
-
-	<panel
-		 height="388"
-		 top_delta="0"
-		 name="physics2_panel"
-		 visible="true"
-		 width="535"
-		 left="0">
-		<panel
-		 height="22"
-		 top_pad="15"
-		 name="header_panel"
-		 width="505"
-		 bg_opaque_color="DkGray2"
-		 background_visible="true"
-		 background_opaque="true"
-		 left="15">
-			<text
-			 width="200"
-			 left="10"
-			 name="header_text"
-			 text_color="White"
-			 top="3"
-			 height="10"
-			 font="SansSerifBig"
-			 layout="topleft">
-				Physics
-			</text>
-		</panel>
-		<text
-		 top_pad="14"
-		 width="475"
-		 height="50"
-		 font="SansSerifSmall"
-		 layout="topleft"
-		 name="description"
-		 word_wrap="true"
-		 left_delta="5">
-			Preview the physics shape below then click Next to continue.  To modify the physics shape, click the Back button.
-		</text>
-		<panel
-			 top_delta="40"
-			 left="15"
-			 height="270"
-			 width="505"
-			 name="content"
-			 bg_opaque_color="DkGray2"
-			 background_visible="true"
-			 background_opaque="true">
-			<text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
-				Model Preview:
+		   top="25"
+		   width="22" />
+      <text top="10" width="120" word_wrap="true" left_pad="10" height="50">Examples:
+Moving objects
+Flying objects
+Vehicles</text>
+      <text top="95" width="120" word_wrap="true" left_delta="0" height="50">Examples:
+Small static objects
+Less detailed objects
+Simple furniture</text>
+      <text top="180" width="120" word_wrap="true" left_delta="0" height="50">Examples:
+Static objects
+Detailed objects
+Buildings</text>
+          <button
+			follows="left|top"
+			height="20"
+			label="Recalculate physics"
+			layout="topleft"
+			left="80"
+			name="recalculate_physics_btn"
+			top_pad="10"
+            width="150">
+          </button>
+          <button
+            enabled="false"
+			follows="left|top"
+			height="20"
+			label="Recalculating..."
+			layout="topleft"
+			left_delta="0"
+			name="recalculating_physics_btn"
+			top_delta="0"
+			visible="false"
+            width="150">
+          </button>
+			<text top="10" right="-10" width="185" text_color="White" follows="left|top" height="15" name="lod_label">
+				Physics preview
 			</text>
-			<combo_box left_pad="5" top_delta="-5"  follows="left|top" list_position="below" height="22"
-			   name="preview_lod_combo3" width="90" tool_tip="LOD to view in preview render">
+			<panel
+				 right="-10"
+				 top="32"
+				 name="physics_preview_panel"
+				 bevel_style="none"
+				 highlight_light_color="0.09 0.09 0.09 1"
+				 border_style="line"
+				 border="true"
+				 height="185"
+				 follows="all"
+				 width="185">
+			</panel>
+			<combo_box left_delta="75" top_pad="10"  follows="left|top" list_position="below" height="22"
+	     name="preview_lod_combo2" width="110" tool_tip="LOD to view in preview render">
 				<combo_item name="high">
-					High
+					High detail
 				</combo_item>
 				<combo_item name="medium">
-					Medium
+					Medium detail
 				</combo_item>
 				<combo_item name="low">
-					Low
+					Low detail
 				</combo_item>
 				<combo_item name="lowest">
-					Lowest
+					Lowest detail
 				</combo_item>
 			</combo_box>
-			<panel
-					   left="10"
-					   top_pad="10"
-					   name="preview_panel"
-					   bevel_style="none"
-					   highlight_light_color="0.09 0.09 0.09 1"
-					   border_style="line"
-					   border="true"
-					   height="190"
-					   follows="all"
-					   width="190">
-			</panel>
-			<text
-						 top_pad="8"
-						 width="130"
-						 height="14"
-						 left="10"
-						 text_color="White"
-						 word_wrap="true">
-				Dimensions (meters):
-			</text>
-			<text
-			 top_pad="0"
-			 width="160"
-			 height="15"
-			 font="SansSerifSmallBold"
-			 text_color="White"
-			 name="dimensions"
-			 left_delta="0">
-				X:         Y:         Z:
-			</text>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_dividers"
-			 left_delta="41">
-				|               |
-			</text>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_x"
-			 left_delta="-25"/>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_y"
-			 left_delta="46"/>
-			<text
-			 top_delta="0"
-			 width="160"
-			 height="15"
-			 name="dimension_z"
-			 left_delta="46"/>
-			<text top="60" width="180" text_color="White" left="225" name="streaming cost"  height="20">Resource Cost:       [COST]</text>
-		</panel>
+    </panel>
 	</panel>
 
 	<panel
@@ -768,162 +653,44 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 				Review
 			</text>
 		</panel>
-		<text
+		<panel
 		 top_pad="14"
-		 width="470"
-		 height="24"
-		 font="SansSerifSmall"
-		 layout="topleft"
-		 name="description"
-		 word_wrap="true"
-		 left_delta="5">
-			Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload.
-		</text>
-		<icon
-			 top_pad="10"
-			 left="20"
-			 width="495"
-			 height="2"
-			 image_name="model_wizard\divider_line.png"/>
-    <panel
-		 top_pad="5"
 		 left="15"
-		 height="270"
+		 height="310"
 		 width="505"
-		 name="content">
-      <text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
-        Model Preview:
-      </text>
-      <combo_box left_pad="5" top_delta="-5"  follows="left|top" list_position="below" height="22"
-	     name="preview_lod_combo" width="90" tool_tip="LOD to view in preview render">
-        <combo_item name="high">
-          High
-        </combo_item>
-        <combo_item name="medium">
-          Medium
-        </combo_item>
-        <combo_item name="low">
-          Low
-        </combo_item>
-        <combo_item name="lowest">
-          Lowest
-        </combo_item>
-      </combo_box>
-      <panel
-				 left="10"
-				 top_pad="10"
-				 name="preview_panel"
-				 bevel_style="none"
-				 highlight_light_color="0.09 0.09 0.09 1"
-				 border_style="line"
-				 border="true"
-				 height="190"
-				 follows="all"
-				 width="190">
-			</panel>
-		<text
-					 top_pad="8"
-					 width="130"
-					 height="14"
-					 left="10"
-					 text_color="White"
-					 word_wrap="true">
-			Dimensions (meters):
-		</text>
-		<text
-		 top_pad="0"
-		 width="160"
-		 height="15"
-		 font="SansSerifSmallBold"
-		 text_color="White"
-		 name="dimensions"
-		 left_delta="0">
-			X:         Y:         Z:
-		</text>
-		<text
-		 top_delta="0"
-		 width="160"
-		 height="15"
-		 name="dimension_dividers"
-		 left_delta="41">
-			|               |
-		</text>
-		<text
-		 top_delta="0"
-		 width="160"
-		 height="15"
-		 name="dimension_x"
-		 left_delta="-25"/>
-		<text
-		 top_delta="0"
-		 width="160"
-		 height="15"
-		 name="dimension_y"
-		 left_delta="46"/>
-		<text
-		 top_delta="0"
-		 width="160"
-		 height="15"
-		 name="dimension_z"
-		 left_delta="46"/>
+		 name="content"
+		 bg_opaque_color="DkGray2"
+		 background_visible="true"
+		 background_opaque="true">
+			<text
+			 top="20"
+			 width="485"
+			 font="SansSerifMedium"
+			 text_color="White"
+			 left="10"
+			 name="review_prim_equiv"
+			 height="16">Impact to parcel/region: [EQUIV] prim equivalents
+			</text>
+			<text
+			 top_pad="20"
+			 width="485"
+			 font="SansSerifMedium"
+			 text_color="White"
+			 left="10"
+			 name="review_fee"
+			 height="16">Your account will be charged an upload fee of L$ [FEE].
+			</text>
+			<text 
+			 top_pad="20"
+			 width="485"
+			 font="SansSerifMedium"
+			 text_color="White"
+			 left="10"
+			 name="review_confirmation"
+			 height="32"
+			 word_wrap="true">By clicking the upload button, you confirm that you have the appropriate rights to the material contained in the model.
+			</text>
       </panel>
-    <text
-      width="300"
-      height="12"
-      top="125" 
-	  name="streaming cost" 
-      left="230" 
-      font="SansSerifSmallBold" 
-      text_color="White">Resource Cost:         [COST]</text>
-    <text
-      width="285"
-      height="30"
-      top_pad="0"
-      left_delta="0"
-      word_wrap="true"
-      font="SansSerifItalic">This is the cost to your Region's prim/object limit, at default scale</text>
-	<text
-	 width="300"
-	 height="12"
-	 name="physics cost" 
-	 top_pad="10"
-		 left_delta="0"
-	 font="SansSerifSmallBold"
-	 text_color="White">Physics Cost:        [COST]</text>
-	<text
-	  width="285"
-	  height="30"
-	  top_pad="0"
-		  left_delta="0"
-	  word_wrap="true"
-	  font="SansSerifItalic">This is the cost to your Region's prim/object limit, at default scale</text>
-		<text
-		 width="200"
-		 height="12"
-		 top_pad="10"
-		left_delta="0"
-		 font="SansSerifSmallBold"
-		 text_color="White">Upload Fee:</text>
-		<text
-		  width="285"
-		  height="26"
-		  top_pad="0"
-		  left_delta="0"
-		  word_wrap="true"
-		  font="SansSerifItalic">This is the amount the upload will cost.</text>
-		<check_box
-			height="16"
-			layout="topleft"
-			left_delta="0"
-			name="confirm_checkbox"
-			top_pad="15"
-			width="16" />
-		<text
-		  height="100"
-		  width="240"
-		  word_wrap="true" 
-		  left_delta="25"
-		  top_delta="0">I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more]</text>
 	</panel>
 
 
@@ -954,45 +721,78 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 			 height="10"
 			 font="SansSerifBig"
 			 layout="topleft">
-				Upload Complete!
+				Upload complete
 			</text>
 		</panel>
 		<text
 		 top_pad="14"
-		 width="474"
-		 height="20"
-		 font="SansSerifSmall"
+		 width="495"
+		 height="16"
+		 font="SansSerifMedium"
 		 layout="topleft"
-		 name="description"
+		 name="model_uploaded_text"
+		 text_color="White"
 		 word_wrap="true"
-		 left_delta="5">
-			Congratulations! Your model has been sucessfully uploaded.  You will find the model in the Objects folder in your inventory.
+		 left="25">
+			Your model has been uploaded.
+		</text>
+		<text
+		 top_pad="5"
+		 width="495"
+		 height="16"
+		 font="SansSerifMedium"
+		 layout="topleft"
+		 name="inventory_text"
+		 text_color="White"
+		 word_wrap="true"
+		 left="25">
+			You will find it in the Objects folder in your inventory.
+		</text>
+		<text
+		 top_pad="20"
+		 width="495"
+		 font="SansSerifMedium"
+		 text_color="White"
+		 left="25"
+		 name="charged_fee"
+		 height="16">Your account has been charged L$ [FEE].
 		</text>
-		<icon
-			 top_pad="15"
-			 left_delta="0"
-			 width="495"
-			 height="2"
-			 image_name="model_wizard\divider_line.png"/>
 	</panel>
 
 
 
 	<button
 	 top="440"
-	 right="-245"
+	 right="-285"
 	 width="90"
 	 height="22"
 	 name="back"
 	 label="&lt;&lt; Back" />
 	<button
 	 top_delta="0"
-	 right="-150"
+	 right="-190"
 	 width="90"
 	 height="22"
 	 name="next"
 	 label="Next &gt;&gt; " />
 	<button
+	 top_delta="0"
+	 left_delta="0"
+	 width="160"
+	 height="22"
+	 name="calculate"
+	 label="Calculate weights &amp; fee &gt;&gt; " />
+	<button
+	 enabled="false"
+	 visible="false"
+	 top_delta="0"
+	 left_delta="0"
+	 width="160"
+	 height="22"
+	 name="calculating"
+	 label="Calculating... " />
+	<button
+	 enabled="false"
 	 top_delta="0"
 	 right="-150"
 	 width="90"
diff --git a/indra/newview/skins/default/xui/en/floater_sound_devices.xml b/indra/newview/skins/default/xui/en/floater_sound_devices.xml
index 304987c3d59c1470f7820dc744beee4ee8c506f9..74e01f359c6ce29b80bdab6d0f98cb72ebe7e1fb 100644
--- a/indra/newview/skins/default/xui/en/floater_sound_devices.xml
+++ b/indra/newview/skins/default/xui/en/floater_sound_devices.xml
@@ -15,14 +15,14 @@
  layout="topleft"
  name="floater_sound_devices"
  title="Sound Devices"
- width="315">
+ width="490">
   <panel
     layout="topleft"
     follows="all"
     filename="panel_sound_devices.xml"
     name="device_settings_panel"
     width="400"
-    left="2"
+    left="10"
     top="26"
     class="panel_voice_device_settings"/>
   <text
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 8b8f70b940b2f69cd289ddc0f0ff10530c8849ee..890158379912f762803cf148953f29581d514bd9 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -47,24 +47,12 @@
         Click and drag to select land
     </floater.string>
     <floater.string
-     name="grid_screen_text">
-        Screen
+     name="status_selectcount">
+        [OBJ_COUNT] objects ( [PRIM_COUNT] prims[PE_STRING] ) selected
     </floater.string>
     <floater.string
-     name="grid_local_text">
-        Local
-    </floater.string>
-    <floater.string
-     name="grid_world_text">
-        World
-    </floater.string>
-    <floater.string
-     name="grid_reference_text">
-        Reference
-    </floater.string>
-    <floater.string
-     name="grid_attachment_text">
-        Attachment
+     name="status_selectprimequiv">
+        , [SEL_WEIGHT] prim equivs
     </floater.string>
     <button
      follows="left|top"
@@ -221,7 +209,7 @@
 	<radio_group
      follows="left|top"
 	 left="5"
-	 top="59"
+	 top="55"
 	 height="70"
      layout="topleft"
 	 name="edit_radio_group">
@@ -255,18 +243,18 @@
      label="Edit linked"
      layout="topleft"
      name="checkbox edit linked parts"
-     top_pad="-10">
+     top_pad="-18">
 		  <check_box.commit_callback
 			function="BuildTool.selectComponent"/>
 	</check_box>
 
    <button
      follows="left|top"
-     height="23"
+     height="20"
      label="Link"
-     top_pad="2"
+     top="108"
      layout="topleft"
-     left="5"
+     left="143"
      name="link_btn"
      width="50">
 	  <button.commit_callback
@@ -274,27 +262,15 @@
     </button>
     <button
      follows="left|top"
-     height="23"
+     height="20"
      label="Unlink"
      layout="topleft"
      left_pad="2"
      name="unlink_btn"
-     width="105">
+     width="90">
 	  <button.commit_callback
 	     function="BuildTool.UnlinkObjects"/>
     </button>
-    <text
-	   text_color="LtGray_50"
-	   follows="top|left"
-	   halign="left"
-	   left_pad="3"
-	   name="RenderingCost"
-	   tool_tip="Shows the rendering cost calculated for this object"
-	   top_delta="11"
-	   type="string"
-	   width="100">
-	   þ: [COUNT]
-	   </text>
     <check_box
      control_name="ScaleUniform"
      height="19"
@@ -302,7 +278,7 @@
      layout="topleft"
      left="143"
      name="checkbox uniform"
-     top="50"
+     top="48"
      width="20" />
     <text
      height="19"
@@ -324,53 +300,29 @@
      layout="topleft"
      left="143"
      name="checkbox stretch textures"
-     top_pad="-6"
+     top_pad="-4"
      follows="left|top"
      width="134" />
    <check_box
      control_name="SnapEnabled"
      height="18"
      initial_value="true"
-     label="Snap to grid"
+     label="Snap"
      layout="topleft"
      top_pad="0"
      name="checkbox snap to grid"
      width="134" />
-    <combo_box
-     height="23"
-     layout="topleft"
-     follows="left|top"
-     name="combobox grid mode"
-     tool_tip="Choose the type of grid ruler for positioning the object"
-     top_pad="0"
-     width="108">
-        <combo_box.item
-         label="World grid"
-         name="World"
-         value="World" />
-        <combo_box.item
-         label="Local grid"
-         name="Local"
-         value="Local" />
-        <combo_box.item
-         label="Reference grid"
-         name="Reference"
-         value="Reference" />
-		 <combo_box.commit_callback
-	     function="BuildTool.gridMode"/>
-    </combo_box>
     <button
      left_pad="0"
-     image_selected="ForwardArrow_Press"
-     image_unselected="ForwardArrow_Off"
+     label="Options..."
      layout="topleft"
      follows="top|left"
      name="Options..."
      tool_tip="See more grid options"
-     top_pad="-22"
-     right="-10"
-     width="18"
-     height="23" >
+     top="83"
+     right="-35"
+     width="65"
+     height="21" >
 	 <button.commit_callback
 	     function="BuildTool.gridOptions"/>
 	</button>
@@ -385,7 +337,7 @@
      left="10"
      name="ToolCube"
      tool_tip="Cube"
-     top="51"
+     top="58"
      width="20" />
     <button
      follows="left|top"
@@ -447,10 +399,10 @@
      image_selected="Object_Hemi_Cylinder_Selected"
      image_unselected="Object_Hemi_Cylinder"
      layout="topleft"
-     left_delta="29"
+     left="10"
      name="ToolHemiCylinder"
      tool_tip="Hemicylinder"
-     top_delta="0"
+     top="84"
      width="20" />
     <button
      follows="left|top"
@@ -515,7 +467,7 @@
      left="10"
      name="ToolTorus"
      tool_tip="Torus"
-     top="77"
+     top="109"
      width="20" />
     <button
      follows="left|top"
@@ -575,9 +527,9 @@
      height="19"
      label="Keep Tool selected"
      layout="topleft"
-     left="4"
+     left="155"
      name="checkbox sticky"
-     top="101"
+     top="55"
      width="128" />
     <check_box
      control_name="CreateToolCopySelection"
@@ -596,7 +548,7 @@
      layout="topleft"
      left_delta="18"
      name="checkbox copy centers"
-     top="132"
+     top="85"
      width="134" />
     <check_box
      control_name="CreateToolCopyRotates"
@@ -749,89 +701,49 @@
 	  <button.commit_callback
 	     function="BuildTool.applyToSelection"/>
     </button>
+    <text
+	 text_color="LtGray_50"
+	  type="string"
+	  length="1"
+	  height="16"
+	  follows="left|top"
+	  font="SansSerifSmall"
+	  layout="topleft"
+	  left="10"
+	  name="selection_empty"
+	  top_pad="0"
+	  width="100">
+		Nothing selected.
+	</text>
 	<text
 	 text_color="LtGray_50"
 	  type="string"
 	  length="1"
-	  height="10"
+	  height="16"
 	  follows="left|top"
-	  halign="right"
+	  font="SansSerifSmall"
 	  layout="topleft"
-	  right="-10"
-	  name="obj_count"
-	  top_pad="5"
-	  width="143">
-		Objects: [COUNT]
+	  left="10"
+	  name="selection_count"
+	  top_delta="0"
+	  visible="false"
+	  width="280">
 	</text>
 	<text
-    text_color="LtGray_50"
-     type="string"
-     length="1"
-	height="10" 
-     follows="left|top"
-     halign="right"
-     layout="topleft"
-     right="-10"
-     name="prim_count"
-     width="143">
-		Prims: [COUNT]
+	 text_color="LtGray_50"
+	  type="string"
+	  length="1"
+	  height="16"
+	  follows="left|top"
+	  font="SansSerifSmall"
+	  layout="topleft"
+	  left="10"
+	  name="selection_weight"
+	  top_pad="0"
+	  visible="false"
+	  width="280">
+	  Physics weight [PHYS_WEIGHT], Render Cost [DISP_WEIGHT].
 	</text>
-    <text
-    text_color="LtGray_50"
-     type="string"
-     length="1"
-     height="10"
-     follows="left|top"
-     halign="right"
-     layout="topleft"
-     right="-120"
-     name="linked_set_count"
-     top="144"
-     width="80">
-        Linked Sets: [COUNT]
-    </text>
-    <text
-    text_color="LtGray_50"
-     type="string"
-     length="1"
-     height="10"
-     follows="left|top"
-     halign="right"
-     layout="topleft"
-     top_delta="0"
-     right="-8"
-     name="linked_set_cost"
-     tool_tip="Cost of currently selected linked sets as [prims],[physics complexity]" 
-     width="80">
-        Cost: [COST] / [PHYSICS]
-    </text>
-    <text
-    text_color="LtGray_50"
-     type="string"
-     length="1"
-     follows="left|top"
-     halign="right"
-     layout="topleft"
-     top_pad="5"
-     right="-120"
-     name="object_count"
-     width="80">
-        Objects: [COUNT]
-    </text>
-    <text
-    text_color="LtGray_50"
-     type="string"
-     length="1"
-     follows="left|top"
-     halign="right"
-     layout="topleft"
-	 top_delta="0"
-     right="-8"
-     name="object_cost"
-     tool_tip="Cost of currently selected objects as [prims] / [physics complexity]"
-     width="80">
-        Cost: [COST] / [PHYSICS]
-    </text>
     <!-- <text -->
     <!-- text_color="LtGray_50" -->
     <!--  type="string" -->
@@ -858,6 +770,15 @@
     <!--  width="143"> -->
     <!--     Prims: [COUNT] -->
     <!-- </text> -->
+    <view_border
+    bevel_style="none"
+    follows="top|left"
+    height="0"
+    layout="topleft"
+    left="6"
+    name="cost_text_border"
+    top="135"
+    width="282"/>
     <tab_container
      follows="left|top"
      height="410"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
index e0ccb18c08bcd374fc70aac13709ddc2ca072087..0f42000ae792fa96ce2cb5cb79de7ebc24619c5e 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
@@ -54,18 +54,6 @@
                 <menu_item_call.on_visible
                 function="File.VisibleUploadModel"/>
                 </menu_item_call>
-              <menu_item_call
-                label="Model Wizard..."
-                layout="topleft"
-                name="Upload Model Wizard">
-                <menu_item_call.on_click
-                 function="Floater.Show"
-                 parameter="upload_model_wizard" />
-                <menu_item_call.on_enable
-                 function="File.EnableUploadModel" />
-                <menu_item_call.on_visible
-                function="File.VisibleUploadModel"/>
-	      </menu_item_call>
                 <menu_item_call
                  label="Bulk (L$[COST] per file)..."
                  layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index ab5c5433761e45fd55d60c01438769ec9c425b63..01699955a63e5d19c0071ed00adcaaa3100a3eee 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1083,19 +1083,7 @@
             <menu_item_call.on_visible
             function="File.VisibleUploadModel"/>
             </menu_item_call>
-			<menu_item_call
-           label="Model Wizard..."
-           layout="topleft"
-           name="Upload Model Wizard">
-				<menu_item_call.on_click
-				 function="Floater.Show"
-				 parameter="upload_model_wizard" />
-				<menu_item_call.on_enable
-				 function="File.EnableUploadModel" />
-				<menu_item_call.on_visible
-				function="File.VisibleUploadModel"/>
-			</menu_item_call>
-            <menu_item_call
+	   <menu_item_call
              label="Bulk (L$[COST] per file)..."
              layout="topleft"
              name="Bulk Upload">
@@ -2097,15 +2085,14 @@
             </menu_item_check>
           <menu_item_check
              label="Show Upload Cost"
-             layout="topleft"
              name="Show Upload Cost">
-            <menu_item_check.on_check
+              <menu_item_check.on_check
              function="CheckControl"
              parameter="DebugShowUploadCost" />
             <menu_item_check.on_click
-             function="ToggleControl"
-             parameter="DebugShowUploadCost" />
-          </menu_item_check>
+                 function="ToggleControl"
+                 parameter="DebugShowUploadCost" />
+            </menu_item_check>
             <menu_item_check
              label="Show Render Info"
              name="Show Render Info">
@@ -2116,7 +2103,7 @@
                  function="ToggleControl"
                  parameter="DebugShowRenderInfo" />
             </menu_item_check>
-			<menu_item_check
+			  <menu_item_check
              label="Show Texture Info"
              name="Show Texture Info">
                 <menu_item_check.on_check
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 1bc377126e2b23b51ecd26434b735178aabfedbb..1030c564394e3dea51c1f63afbae84220d459f1e 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6810,6 +6810,20 @@ Select residents to share with.
 See the log file for details.
   </notification>
    
+   <notification
+    name="MeshUploadPermError"
+    icon="alert.tga"
+    type="alert">
+    Error while requesting mesh upload permissons.
+  </notification>
+  
+  <notification
+    name="RegionCapabilityRequestError"
+    icon="alert.tga"
+    type="alert">
+    Could not get region capability &apos;[CAPABILITY]&apos;.
+  </notification>
+   
   <notification
    icon="notifytip.tga"
    name="ShareItemsConfirmation"
diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml
index daf571297f29f9a6bf74a02494c7fc2ff9fe0e85..b6b8a337a121d3df9267b6184012f630a4379c63 100644
--- a/indra/newview/skins/default/xui/en/panel_places.xml
+++ b/indra/newview/skins/default/xui/en/panel_places.xml
@@ -234,7 +234,7 @@ background_visible="true"
 				height="23"
 				layout="topleft"
 				mouse_opaque="false"
-				name="bottom_bar_ls3"
+				name="bottom_bar_profile_ls"
 				left="0"
 				orientation="horizontal"
 				top="0"
diff --git a/indra/newview/skins/default/xui/en/panel_sound_devices.xml b/indra/newview/skins/default/xui/en/panel_sound_devices.xml
index 0a20a4a96569012a13a4ad138e8bda07c91fb3bb..46cbc1e87fdf91c127c8cf898191a5b0a3e0bd1a 100644
--- a/indra/newview/skins/default/xui/en/panel_sound_devices.xml
+++ b/indra/newview/skins/default/xui/en/panel_sound_devices.xml
@@ -11,6 +11,14 @@
       name="default_text">
         Default
     </panel.string>
+    <string
+     name="name_no_device">
+        No Device
+    </string>
+    <string
+     name="name_default_system_device">
+        Default System Device
+    </string>
     <icon
      follows="left|top"
      height="18"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index ee6317f367b676c7e85f06d7870398bae092671f..47e02378fee79d97f3c12b59e470a5c6afacce05 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -44,6 +44,8 @@
 	<string name="LoginInitializingQuicktime">Initializing QuickTime...</string>
 	<string name="LoginQuicktimeNotFound">QuickTime not found - unable to initialize.</string>
 	<string name="LoginQuicktimeOK">QuickTime initialized successfully.</string>
+	<string name="LoginRequestSeedCapGrant">Requesting region capabilities...</string>
+	<string name="LoginRetrySeedCapGrant">Requesting region capabilities, attempt [NUMBER]...</string>
 	<string name="LoginWaitingForRegionHandshake">Waiting for region handshake...</string>
 	<string name="LoginConnectingToRegion">Connecting to region...</string>
 	<string name="LoginDownloadingClothing">Downloading clothing...</string>
diff --git a/indra/newview/skins/default/xui/es/panel_places.xml b/indra/newview/skins/default/xui/es/panel_places.xml
index 4c90a7e6b4636318e1022242dd986045aa28acf6..e9984b45123f5383a2a3e875af002ddcc7e08294 100644
--- a/indra/newview/skins/default/xui/es/panel_places.xml
+++ b/indra/newview/skins/default/xui/es/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="▼" name="overflow_btn" tool_tip="Ver más opciones"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="Perfil" name="profile_btn" tool_tip="Mostrar el perfil del lugar"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_places.xml b/indra/newview/skins/default/xui/fr/panel_places.xml
index e252c224f83a1308ddc85d9419a13be8d5b4fce6..509d167704870a2801adab0d3125c700c3b51736 100644
--- a/indra/newview/skins/default/xui/fr/panel_places.xml
+++ b/indra/newview/skins/default/xui/fr/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="â–¼" name="overflow_btn" tool_tip="Afficher d&apos;autres options"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="Profil" name="profile_btn" tool_tip="Afficher le profil de l&apos;endroit"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/it/panel_places.xml b/indra/newview/skins/default/xui/it/panel_places.xml
index 61830f186f0cd5ae01849984963e8c713c726cf3..69995fb5de29623de0c250d11d51c9bec753d0dc 100644
--- a/indra/newview/skins/default/xui/it/panel_places.xml
+++ b/indra/newview/skins/default/xui/it/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="â–¼" name="overflow_btn" tool_tip="Mostra ulteriori opzioni"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="Profilo" name="profile_btn" tool_tip="Mostra il profilo del luogo"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_places.xml b/indra/newview/skins/default/xui/ja/panel_places.xml
index e19b86e55231ed6e898b227af5d6fd7cd90e8176..9d3925afdcf60c5e5199296a4439adcde659f3d0 100644
--- a/indra/newview/skins/default/xui/ja/panel_places.xml
+++ b/indra/newview/skins/default/xui/ja/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="▼" name="overflow_btn" tool_tip="オプションを表示します"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="プロフィール" name="profile_btn" tool_tip="場所のプロフィールを表示"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_places.xml b/indra/newview/skins/default/xui/pl/panel_places.xml
index 34c105225d0774463d7ccc26782337d1099c44bd..d69d137d235755ea5aaf7a4832f925d4f79c6f72 100644
--- a/indra/newview/skins/default/xui/pl/panel_places.xml
+++ b/indra/newview/skins/default/xui/pl/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="▼" name="overflow_btn" tool_tip="Pokaż opcje dodatkowe"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="Profil" name="profile_btn" tool_tip="Pokaż profil miejsca"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_places.xml b/indra/newview/skins/default/xui/pt/panel_places.xml
index 828ef3e4693dff10adadde315f919478c1cf55ff..69f0baf65f24e6382f9a06294ffbec23eedd4716 100644
--- a/indra/newview/skins/default/xui/pt/panel_places.xml
+++ b/indra/newview/skins/default/xui/pt/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button label="▼" name="overflow_btn" tool_tip="Mostrar opções adicionais"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="Perfil" name="profile_btn" tool_tip="Mostrar perfil do lugar"/>
 					</layout_panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_places.xml b/indra/newview/skins/default/xui/zh/panel_places.xml
index c141201ab2eed953cd1dec9fa5fefb3f8f2d917b..6434a7279c8b5db80501ad7a1ac168e987b13163 100644
--- a/indra/newview/skins/default/xui/zh/panel_places.xml
+++ b/indra/newview/skins/default/xui/zh/panel_places.xml
@@ -24,7 +24,7 @@
 						<menu_button name="overflow_btn" tool_tip="顯示額外選項"/>
 					</layout_panel>
 				</layout_stack>
-				<layout_stack name="bottom_bar_ls3">
+				<layout_stack name="bottom_bar_profile_ls">
 					<layout_panel name="profile_btn_lp">
 						<button label="檔案" name="profile_btn" tool_tip="顯示地點檔案"/>
 					</layout_panel>
diff --git a/indra/newview/skins/minimal/xui/da/panel_people.xml b/indra/newview/skins/minimal/xui/da/panel_people.xml
index 49cd2c71f2194a364f24c199d29ca15b61077f5a..8be4d695bdeda9b7e88bb991eee7225a642c6f1c 100644
--- a/indra/newview/skins/minimal/xui/da/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/da/panel_people.xml
@@ -66,16 +66,16 @@ Leder du efter personer at være sammen med? Prøv destinationsknappen nedenfor.
 			<layout_panel name="view_profile_btn_lp">
 				<button label="Profil" name="view_profile_btn" tool_tip="Vis billeder, grupper og anden beboer information"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="IM" name="im_btn" tool_tip="Ã…ben session med privat besked (IM)"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="Opkald" name="call_btn" tool_tip="Kald til denne beboer"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="share_btn_lp">
 				<button label="Del" name="share_btn" tool_tip="Del en genstand fra beholdning"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="Teleportér" name="teleport_btn" tool_tip="Tilbyd teleport"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/minimal/xui/de/panel_people.xml b/indra/newview/skins/minimal/xui/de/panel_people.xml
index 4f8f70ad17a72468668e1a40041aa9b0fb8514dd..a52557236face330c15ed9297dde6ce736928b84 100644
--- a/indra/newview/skins/minimal/xui/de/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/de/panel_people.xml
@@ -48,13 +48,13 @@
 			<layout_panel name="view_profile_btn_lp">
 				<button label="Profil" name="view_profile_btn" tool_tip="Bilder, Gruppen und andere Einwohner-Informationen anzeigen"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="IM" name="im_btn" tool_tip="Instant Messenger öffnen"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="Anrufen" name="call_btn" tool_tip="Diesen Einwohner anrufen"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="Teleportieren" name="teleport_btn" tool_tip="Teleport anbieten"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/minimal/xui/en/panel_people.xml b/indra/newview/skins/minimal/xui/en/panel_people.xml
index 76baacb0911393eba6703651c5f8f51209637f9e..4739f86e95efd728173335ecf400169275e9f187 100644
--- a/indra/newview/skins/minimal/xui/en/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_people.xml
@@ -428,7 +428,7 @@ Looking for people to hang out with? Try the Destinations button below.
 			height="23"
 			layout="bottomleft"
 			left_pad="3"
-			name="chat_btn_lp"
+			name="im_btn_lp"
 		    user_resize="false" 
 		    auto_resize="true"
 			width="41">
@@ -449,7 +449,7 @@ Looking for people to hang out with? Try the Destinations button below.
 			height="23"
 			layout="bottomleft"
 			left_pad="3"
-			name="chat_btn_lp"
+			name="call_btn_lp"
 		    user_resize="false" 
 		    auto_resize="true"
 			width="52">
@@ -470,7 +470,7 @@ Looking for people to hang out with? Try the Destinations button below.
 			height="23"
 			layout="bottomleft"
 			left_pad="3"
-			name="chat_btn_lp"
+			name="teleport_btn_lp"
 		    user_resize="false" 
 		    auto_resize="true"
 			width="77">
diff --git a/indra/newview/skins/minimal/xui/es/panel_people.xml b/indra/newview/skins/minimal/xui/es/panel_people.xml
index 1e1c3411aeb61c09e0e0b012f918497119c989bd..8d3d14fa895cbf6da24c66d8246c451e3b6458a7 100644
--- a/indra/newview/skins/minimal/xui/es/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/es/panel_people.xml
@@ -49,13 +49,13 @@
 			<layout_panel name="view_profile_btn_lp">
 				<button label="Perfil" name="view_profile_btn" tool_tip="Mostrar imágenes, grupos y otra información del Residente"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="MI" name="im_btn" tool_tip="Abrir una sesión de mensajes instantáneos"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="Llamar" name="call_btn" tool_tip="Llamar a este Residente"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="Teleporte" name="teleport_btn" tool_tip="Ofrecer teleporte"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_people.xml b/indra/newview/skins/minimal/xui/fr/panel_people.xml
index 72fb4d807ff1f490ba96ffdbe8fef5c881072def..4d6e31d9b534118493a6be223e5b20c3ef09fcf6 100644
--- a/indra/newview/skins/minimal/xui/fr/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/fr/panel_people.xml
@@ -49,13 +49,13 @@ Vous recherchez des résidents avec qui passer du temps ? Essayez avec le bouto
 			<layout_panel name="view_profile_btn_lp">
 				<button label="Profil" name="view_profile_btn" tool_tip="Afficher la photo, les groupes et autres infos des résidents"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="IM" name="im_btn" tool_tip="Ouvrir une session IM"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="Appeler" name="call_btn" tool_tip="Appeler ce résident."/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="Téléporter" name="teleport_btn" tool_tip="Proposer une téléportation"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/minimal/xui/it/panel_people.xml b/indra/newview/skins/minimal/xui/it/panel_people.xml
index 068c8bb8082db9f731f67f88d037311509d13b06..81e886acf0d9a393466130d5d78d5b67994ec271 100644
--- a/indra/newview/skins/minimal/xui/it/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/it/panel_people.xml
@@ -66,16 +66,16 @@ Stai cercando persone da frequentare? Prova il pulsante Destinazioni in basso.
 			<layout_panel name="view_profile_btn_lp">
 				<button label="Profilo" name="view_profile_btn" tool_tip="Mostra immagine, gruppi e altre informazioni del residente"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="IM" name="im_btn" tool_tip="Apri una sessione messaggio istantaneo"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="Chiama" name="call_btn" tool_tip="Chiama questo residente"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="share_btn_lp">
 				<button label="Condividi" name="share_btn" tool_tip="Condividi un oggetto dell&apos;inventario"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="Teleport" name="teleport_btn" tool_tip="Offri teleport"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/minimal/xui/ja/panel_people.xml b/indra/newview/skins/minimal/xui/ja/panel_people.xml
index 9eb45d9a806138f61c39769579b63f6a1f51835a..5caeebc151d9a5ba59f22e3888406beec3e607c7 100644
--- a/indra/newview/skins/minimal/xui/ja/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/ja/panel_people.xml
@@ -66,16 +66,16 @@
 			<layout_panel name="view_profile_btn_lp">
 				<button label="プロフィール" name="view_profile_btn" tool_tip="写真、グループ、その他住人情報を表示"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="IM" name="im_btn" tool_tip="インスタントメッセージを開きます"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="コール" name="call_btn" tool_tip="この住人にコールする"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="share_btn_lp">
 				<button label="共有" name="share_btn" tool_tip="「持ち物」のアイテムを共有する"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="テレポート" name="teleport_btn" tool_tip="テレポートを送ります"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/minimal/xui/pl/panel_people.xml b/indra/newview/skins/minimal/xui/pl/panel_people.xml
index dbfee739f4a13e59352379695977f539d22dff99..3b3aaa0987ce7e912470aac45a06230c53a349c2 100644
--- a/indra/newview/skins/minimal/xui/pl/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/pl/panel_people.xml
@@ -66,16 +66,16 @@ Chcesz spotkać ludzi? Skorzystaj z przycisku &quot;Atrakcje turystyczne&quot; p
 			<layout_panel name="view_profile_btn_lp">
 				<button label="Profil" name="view_profile_btn" tool_tip="Pokaż zdjęcie, grupy i inne informacje o Rezydencie"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="IM" name="im_btn" tool_tip="Otwórz wiadomości IM"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="Dzwoń" name="call_btn" tool_tip="Zadzwoń do tego Rezydenta"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="share_btn_lp">
 				<button label="Udostępnij" name="share_btn" tool_tip="Udostępnij obiekt z Szafy"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="Teleportuj" name="teleport_btn" tool_tip="Zaproponuj teleport"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_people.xml b/indra/newview/skins/minimal/xui/pt/panel_people.xml
index d46c440eb966d738d2f86635de8a4c101ade417f..0e98c586c65554a896a78b860f42271d845e4686 100644
--- a/indra/newview/skins/minimal/xui/pt/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/pt/panel_people.xml
@@ -49,13 +49,13 @@ Em busca de alguém para conversar? Confira o botão Destinos abaixo.
 			<layout_panel name="view_profile_btn_lp">
 				<button label="Perfil" name="view_profile_btn" tool_tip="Exibir fotografia, grupos e outras informações dos residentes"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="im_btn_lp">
 				<button label="MI" name="im_btn" tool_tip="Abrir sessão de mensagem instantânea"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="call_btn_lp">
 				<button label="Ligar" name="call_btn" tool_tip="Ligar para este residente"/>
 			</layout_panel>
-			<layout_panel name="chat_btn_lp">
+			<layout_panel name="teleport_btn_lp">
 				<button label="Teletransportar" name="teleport_btn" tool_tip="Oferecer teletransporte"/>
 			</layout_panel>
 		</layout_stack>
diff --git a/indra/newview/tests/lldir_stub.cpp b/indra/newview/tests/lldir_stub.cpp
index 6646860b5e3014dedc9be556caa4f286eee1f1dd..18cf4e7419e02ded99b3ee73d619d6db2ca20533 100644
--- a/indra/newview/tests/lldir_stub.cpp
+++ b/indra/newview/tests/lldir_stub.cpp
@@ -2,8 +2,25 @@
  * @file lldir_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llglslshader_stub.cpp b/indra/newview/tests/llglslshader_stub.cpp
index 5333c8a361331a5e9f6f8cf3973b97d29f442d2a..8947a632c88d59880a50b857dd58936999d7b019 100644
--- a/indra/newview/tests/llglslshader_stub.cpp
+++ b/indra/newview/tests/llglslshader_stub.cpp
@@ -2,8 +2,25 @@
  * @file llglslshader_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llpipeline_stub.cpp b/indra/newview/tests/llpipeline_stub.cpp
index 85bf0ae3fb3540282f4a81188dcda97f56d132ca..ad112cbf6a7b34e80c9de6c7484fa37abe412581 100644
--- a/indra/newview/tests/llpipeline_stub.cpp
+++ b/indra/newview/tests/llpipeline_stub.cpp
@@ -2,8 +2,25 @@
  * @file llpipeline_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llsky_stub.cpp b/indra/newview/tests/llsky_stub.cpp
index 35f4944a950199705c4a330079230a4f9cc4bedc..241d7406359d9a5f87bdc60d382019ab57e200fe 100644
--- a/indra/newview/tests/llsky_stub.cpp
+++ b/indra/newview/tests/llsky_stub.cpp
@@ -2,8 +2,25 @@
  * @file llsky_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llviewershadermgr_stub.cpp b/indra/newview/tests/llviewershadermgr_stub.cpp
index 0dae527035bb05fbf01f6d6895a06eee58532b8d..18eff72f3c07da40a2c81846b19d9b5814d47aca 100644
--- a/indra/newview/tests/llviewershadermgr_stub.cpp
+++ b/indra/newview/tests/llviewershadermgr_stub.cpp
@@ -2,8 +2,25 @@
  * @file llglslshader_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llwlanimator_stub.cpp b/indra/newview/tests/llwlanimator_stub.cpp
index 4d1bb85544a0d1bb7528af3cbc62a11c231834fe..f5e15b2e7b570add808cb3ca79fd4f1c9664a996 100644
--- a/indra/newview/tests/llwlanimator_stub.cpp
+++ b/indra/newview/tests/llwlanimator_stub.cpp
@@ -2,8 +2,25 @@
  * @file llwlanimator_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llwldaycycle_stub.cpp b/indra/newview/tests/llwldaycycle_stub.cpp
index d98c9614b40f9beecad4fb4122d88c2510530ef3..a7bc9a7b83b5da02d06854e88a6828a6543926ec 100644
--- a/indra/newview/tests/llwldaycycle_stub.cpp
+++ b/indra/newview/tests/llwldaycycle_stub.cpp
@@ -2,8 +2,25 @@
  * @file llwldaycycle_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llwlparammanager_test.cpp b/indra/newview/tests/llwlparammanager_test.cpp
index a6c6a2abf47754da61dd0da7f4da24884422e718..be0dc9fd0c2dc85710d2c02809253e140a3567ce 100644
--- a/indra/newview/tests/llwlparammanager_test.cpp
+++ b/indra/newview/tests/llwlparammanager_test.cpp
@@ -2,8 +2,25 @@
  * @file llwlparammanager_test.cpp
  * @brief LLWLParamManager tests
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/indra/newview/tests/llwlparamset_stub.cpp b/indra/newview/tests/llwlparamset_stub.cpp
index 6ce4b5827d71e7a346d85713d8215b294f2a7cfd..ccb99db475b40eb700864ff55db54c7b587de329 100644
--- a/indra/newview/tests/llwlparamset_stub.cpp
+++ b/indra/newview/tests/llwlparamset_stub.cpp
@@ -2,8 +2,25 @@
  * @file llwlparamset_stub.cpp
  * @brief  stub class to allow unit testing
  *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
diff --git a/shining-fixes_rev18977.patch b/shining-fixes_rev18977.patch
deleted file mode 100644
index b711da870a951304979f5d0045253f82d0765185..0000000000000000000000000000000000000000
--- a/shining-fixes_rev18977.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-# HG changeset patch
-# User Dave Parks <davep@lindenlab.com>
-# Date 1308673064 18000
-# Node ID 95c5639a3f80920e8dc54703d894517dd7694edf
-# Parent  6af10678de4736222b2c3f7e010e984fb5b327de
-SH-208 Disable VBO on all intel graphics chips (stability improvement).
-
-diff -r 6af10678de47 -r 95c5639a3f80 indra/newview/featuretable.txt
---- a/indra/newview/featuretable.txt	Mon Jun 20 16:42:31 2011 -0700
-+++ b/indra/newview/featuretable.txt	Tue Jun 21 11:17:44 2011 -0500
-@@ -1,4 +1,4 @@
--version 29
-+version 30
- 
- // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
- // Should be combined into one table
-@@ -297,6 +297,7 @@
- 
- list Intel
- RenderAnisotropic			1	0
-+RenderVBOEnable				1	0
- 
- list GeForce2
- RenderAnisotropic			1	0
-diff -r 6af10678de47 -r 95c5639a3f80 indra/newview/featuretable_xp.txt
---- a/indra/newview/featuretable_xp.txt	Mon Jun 20 16:42:31 2011 -0700
-+++ b/indra/newview/featuretable_xp.txt	Tue Jun 21 11:17:44 2011 -0500
-@@ -1,4 +1,4 @@
--version 29
-+version 30
- 
- // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
- // Should be combined into one table
-@@ -295,6 +295,7 @@
- 
- list Intel
- RenderAnisotropic			1	0
-+RenderVBOEnable				1	0
- 
- list GeForce2
- RenderAnisotropic			1	0