diff --git a/.hgtags b/.hgtags
index 10be7765c40686e85cffb81e745f6525fa722c8f..56dc0c288f20bb370ad5363ed1cf979825516e4a 100644
--- a/.hgtags
+++ b/.hgtags
@@ -84,3 +84,6 @@ f1827b441e05bf37c68e2c15ebc6d09e9b03f527 2.6.0-start
 9283d6d1d7eb71dfe4c330e7c9144857e7356bde 2.6.0-beta1
 9283d6d1d7eb71dfe4c330e7c9144857e7356bde DRTVWR-40_2.6.0-beta1
 c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start
+9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2
+9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2
+56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start
diff --git a/indra/integration_tests/CMakeLists.txt b/indra/integration_tests/CMakeLists.txt
index 67e8fbf1f2c0cd6fbaf6d9d7c9076a8281c6494a..5935f23fe9fe9ad725607b3b1a43f454b161c61b 100644
--- a/indra/integration_tests/CMakeLists.txt
+++ b/indra/integration_tests/CMakeLists.txt
@@ -1,3 +1,4 @@
 # -*- cmake -*-
 
 add_subdirectory(llui_libtest)
+add_subdirectory(llimage_libtest)
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f59440be6bfc1d437f0705f247f223431f44ec22
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt
@@ -0,0 +1,131 @@
+# -*- cmake -*-
+
+# Integration tests of the llimage library (JPEG2000, PNG, jpeg, etc... images reading and writing)
+
+project (llimage_libtest)
+
+include(00-Common)
+include(LLCommon)
+include(Linking)
+include(LLSharedLibs)
+include(LLImage)
+include(LLImageJ2COJ) 
+include(LLKDU)
+include(LLMath)
+include(LLVFS)
+
+include_directories(
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLVFS_INCLUDE_DIRS}
+    ${LLIMAGE_INCLUDE_DIRS}
+    ${LLMATH_INCLUDE_DIRS}
+    )
+
+set(llimage_libtest_SOURCE_FILES
+    llimage_libtest.cpp
+    )
+
+set(llimage_libtest_HEADER_FILES
+    CMakeLists.txt
+    llimage_libtest.h
+    )
+
+set_source_files_properties(${llimage_libtest_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llimage_libtest_SOURCE_FILES ${llimage_libtest_HEADER_FILES})
+
+add_executable(llimage_libtest
+    WIN32
+    MACOSX_BUNDLE
+    ${llimage_libtest_SOURCE_FILES}
+)
+
+set_target_properties(llimage_libtest
+    PROPERTIES
+    WIN32_EXECUTABLE
+    FALSE
+)
+
+# OS-specific libraries
+if (DARWIN)
+  include(CMakeFindFrameworks)
+  find_library(COREFOUNDATION_LIBRARY CoreFoundation)
+  set(OS_LIBRARIES ${COREFOUNDATION_LIBRARY})
+elseif (WINDOWS)
+#  set(OS_LIBRARIES)
+elseif (LINUX)
+#  set(OS_LIBRARIES)
+else (DARWIN)
+  message(FATAL_ERROR "Unknown platform")
+endif (DARWIN)
+
+# Libraries on which this application depends on
+# Sort by high-level to low-level
+target_link_libraries(llimage_libtest
+	${LLCOMMON_LIBRARIES}
+	${LLVFS_LIBRARIES}
+    ${LLIMAGE_LIBRARIES}
+    ${LLKDU_LIBRARIES}
+    ${KDU_LIBRARY}
+    ${LLIMAGEJ2COJ_LIBRARIES}
+    ${OS_LIBRARIES}
+    )
+	
+if (DARWIN)
+  # Path inside the app bundle where we'll need to copy libraries
+  set(LLIMAGE_LIBTEST_DESTINATION_DIR
+    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llimage_libtest.app/Contents/Resources
+  )
+  # Create the Contents/Resources directory
+  add_custom_command(
+    TARGET llimage_libtest POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    ARGS
+      -E
+      make_directory
+      ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+    COMMENT "Creating Resources directory in app bundle."
+  ) 
+else (DARWIN)
+  set(LLIMAGE_LIBTEST_DESTINATION_DIR
+    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+  )
+endif (DARWIN)
+
+get_target_property(BUILT_LLCOMMON llcommon LOCATION)
+add_custom_command(TARGET llimage_libtest POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON}  ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+  DEPENDS ${BUILT_LLCOMMON}
+)
+
+if (DARWIN)
+  # Copy the required libraries to the package app
+  add_custom_command(TARGET llimage_libtest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libapr-1.0.3.7.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libapr-1.0.3.7.dylib
+  )
+ add_custom_command(TARGET llimage_libtest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libaprutil-1.0.3.8.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libaprutil-1.0.3.8.dylib
+  )
+  add_custom_command(TARGET llimage_libtest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexception_handler.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexception_handler.dylib
+  )
+  add_custom_command(TARGET llimage_libtest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexpat.0.5.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexpat.0.5.0.dylib
+  )
+endif (DARWIN)
+
+if (WINDOWS)
+  # Check indra/test_apps/llplugintest/CMakeLists.txt for an example of what to copy over for Windows and how
+endif (WINDOWS)
+
+# Ensure people working on the viewer don't break this library
+# *NOTE: This could be removed, or only built by TeamCity, if the build
+# and link times become too long.
+add_dependencies(viewer llimage_libtest)
+
+ll_deploy_sharedlibs_command(llimage_libtest) 
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..365f5f758cdb9c5547814fb57fa6b151863b043a
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
@@ -0,0 +1,437 @@
+/** 
+ * @file llimage_libtest.cpp
+ * @author Merov Linden
+ * @brief Integration test for the llimage library
+ *
+ * $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 "linden_common.h"
+#include "llpointer.h"
+#include "lltimer.h"
+
+#include "llimage_libtest.h"
+
+// Linden library includes
+#include "llimage.h"
+#include "llimagejpeg.h"
+#include "llimagepng.h"
+#include "llimagebmp.h"
+#include "llimagetga.h"
+#include "llimagej2c.h"
+#include "lldir.h"
+
+// system libraries
+#include <iostream>
+
+// doc string provided when invoking the program with --help 
+static const char USAGE[] = "\n"
+"usage:\tllimage_libtest [options]\n"
+"\n"
+" -h, --help\n"
+"        Print this help\n"
+" -i, --input <file1 .. file2>\n"
+"        List of image files to load and convert. Patterns with wild cards can be used.\n"
+" -o, --output <file1 .. file2> OR <type>\n"
+"        List of image files to create (assumes same order as for input files)\n"
+"        OR 3 letters file type extension to convert each input file into.\n"
+" -log, --logmetrics <metric>\n"
+"        Log performance data for <metric>. Results in <metric>.slp\n"
+"        Note: so far, only ImageCompressionTester has been tested.\n"
+" -r, --analyzeperformance\n"
+"        Create a report comparing <metric>_baseline.slp with current <metric>.slp\n"
+"        Results in <metric>_report.csv"
+" -s, --image-stats\n"
+"        Output stats for each input and output image.\n"
+"\n";
+
+// true when all image loading is done. Used by metric logging thread to know when to stop the thread.
+static bool sAllDone = false;
+
+// Create an empty formatted image instance of the correct type from the filename
+LLPointer<LLImageFormatted> create_image(const std::string &filename)
+{
+	std::string exten = gDirUtilp->getExtension(filename);
+	U32 codec = LLImageBase::getCodecFromExtension(exten);
+	
+	LLPointer<LLImageFormatted> image;
+	switch (codec)
+	{
+		case IMG_CODEC_BMP:
+			image = new LLImageBMP();
+			break;
+		case IMG_CODEC_TGA:
+			image = new LLImageTGA();
+			break;
+		case IMG_CODEC_JPEG:
+			image = new LLImageJPEG();
+			break;
+		case IMG_CODEC_J2C:
+			image = new LLImageJ2C();
+			break;
+		case IMG_CODEC_PNG:
+			image = new LLImagePNG();
+			break;
+		default:
+			return NULL;
+	}
+	
+	return image;
+}
+
+void output_image_stats(LLPointer<LLImageFormatted> image, const std::string &filename)
+{
+	// Print out some statistical data on the image
+	std::cout << "Image stats for : " << filename << ", extension : " << image->getExtension() << std::endl;
+
+	std::cout << "    with : " << (int)(image->getWidth())       << ", height : " << (int)(image->getHeight())       << std::endl;
+	std::cout << "    comp : " << (int)(image->getComponents())  << ", levels : " << (int)(image->getDiscardLevel()) << std::endl;
+	std::cout << "    head : " << (int)(image->calcHeaderSize()) << ",   data : " << (int)(image->getDataSize())     << std::endl;
+
+	return;
+}
+
+// Load an image from file and return a raw (decompressed) instance of its data
+LLPointer<LLImageRaw> load_image(const std::string &src_filename, bool output_stats)
+{
+	LLPointer<LLImageFormatted> image = create_image(src_filename);
+
+	if (!image->load(src_filename))
+	{
+		return NULL;
+	}
+	
+	if(	(image->getComponents() != 3) && (image->getComponents() != 4) )
+	{
+		std::cout << "Image files with less than 3 or more than 4 components are not supported\n";
+		return NULL;
+	}
+	
+	if (output_stats)
+	{
+		output_image_stats(image, src_filename);
+	}
+	
+	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
+	if (!image->decode(raw_image, 0.0f))
+	{
+		return NULL;
+	}
+	
+	return raw_image;
+}
+
+// Save a raw image instance into a file
+bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, bool output_stats)
+{
+	LLPointer<LLImageFormatted> image = create_image(dest_filename);
+	
+	if (!image->encode(raw_image, 0.0f))
+	{
+		return false;
+	}
+	
+	if (output_stats)
+	{
+		output_image_stats(image, dest_filename);
+	}
+
+	return image->save(dest_filename);
+}
+
+void store_input_file(std::list<std::string> &input_filenames, const std::string &path)
+{
+	// Break the incoming path in its components
+	std::string dir = gDirUtilp->getDirName(path);
+	std::string name = gDirUtilp->getBaseFileName(path);
+	std::string exten = gDirUtilp->getExtension(path);
+
+	// std::cout << "store_input_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
+	
+	// If extension is not an image type or "*", exit
+	// Note: we don't support complex patterns for the extension like "j??"
+	// Note: on most shells, the pattern expansion is done by the shell so that pattern matching limitation is actually not a problem
+	if ((exten.compare("*") != 0) && (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID))
+	{
+		return;
+	}
+
+	if ((name.find('*') != -1) || ((name.find('?') != -1)))
+	{
+		// If file name is a pattern, iterate to get each file name and store
+		std::string next_name;
+		while (gDirUtilp->getNextFileInDir(dir,name,next_name))
+		{
+			std::string file_name = dir + gDirUtilp->getDirDelimiter() + next_name;
+			input_filenames.push_back(file_name);
+		}
+	}
+	else
+	{
+		// Verify that the file does exist before storing 
+		if (gDirUtilp->fileExists(path))
+		{
+			input_filenames.push_back(path);
+		}
+		else
+		{
+			std::cout << "store_input_file : the file " << path << " could not be found" << std::endl;
+		}
+	}	
+}
+
+void store_output_file(std::list<std::string> &output_filenames, std::list<std::string> &input_filenames, const std::string &path)
+{
+	// Break the incoming path in its components
+	std::string dir = gDirUtilp->getDirName(path);
+	std::string name = gDirUtilp->getBaseFileName(path);
+	std::string exten = gDirUtilp->getExtension(path);
+	
+	// std::cout << "store_output_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
+	
+	if (dir.empty() && exten.empty())
+	{
+		// If dir and exten are empty, we interpret the name as a file extension type name and will iterate through input list to populate the output list
+		exten = name;
+		// Make sure the extension is an image type
+		if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
+		{
+			return;
+		}
+		std::string delim = gDirUtilp->getDirDelimiter();
+		std::list<std::string>::iterator in_file  = input_filenames.begin();
+		std::list<std::string>::iterator end = input_filenames.end();
+		for (; in_file != end; ++in_file)
+		{
+			dir = gDirUtilp->getDirName(*in_file);
+			name = gDirUtilp->getBaseFileName(*in_file,true);
+			std::string file_name;
+			if (!dir.empty())
+			{
+				file_name = dir + delim + name + "." + exten;
+			}
+			else
+			{
+				file_name = name + "." + exten;
+			}
+			output_filenames.push_back(file_name);
+		}
+	}
+	else
+	{
+		// Make sure the extension is an image type
+		if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
+		{
+			return;
+		}
+		// Store the path
+		output_filenames.push_back(path);
+	}
+}
+
+// Holds the metric gathering output in a thread safe way
+class LogThread : public LLThread
+{
+public:
+	std::string mFile;
+
+	LogThread(std::string& test_name) : LLThread("llimage_libtest log")
+	{
+		std::string file_name = test_name + std::string(".slp");
+		mFile = file_name;
+	}
+		
+	void run()
+	{
+		std::ofstream os(mFile.c_str());
+			
+		while (!sAllDone)
+		{
+			LLFastTimer::writeLog(os);
+			os.flush();
+			ms_sleep(32);
+		}
+		LLFastTimer::writeLog(os);
+		os.flush();
+		os.close();
+	}		
+};
+
+int main(int argc, char** argv)
+{
+	// List of input and output files
+	std::list<std::string> input_filenames;
+	std::list<std::string> output_filenames;
+	bool analyze_performance = false;
+	bool image_stats = false;
+
+	// Init whatever is necessary
+	ll_init_apr();
+	LLImage::initClass();
+	LogThread* fast_timer_log_thread = NULL;	// For performance and metric gathering
+
+	// Analyze command line arguments
+	for (int arg = 1; arg < argc; ++arg)
+	{
+		if (!strcmp(argv[arg], "--help") || !strcmp(argv[arg], "-h"))
+		{
+            // Send the usage to standard out
+            std::cout << USAGE << std::endl;
+			return 0;
+		}
+		else if ((!strcmp(argv[arg], "--input") || !strcmp(argv[arg], "-i")) && arg < argc-1)
+		{
+			std::string file_name = argv[arg+1];
+			while (file_name[0] != '-')		// if arg starts with '-', we consider it's not a file name but some other argument
+			{
+				// std::cout << "input file name : " << file_name << std::endl;				
+				store_input_file(input_filenames, file_name);
+				arg += 1;					// Skip that arg now we know it's a file name
+				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list
+					break;
+				file_name = argv[arg+1];	// Next argument and loop over
+			}
+		}
+		else if ((!strcmp(argv[arg], "--output") || !strcmp(argv[arg], "-o")) && arg < argc-1)
+		{
+			std::string file_name = argv[arg+1];
+			while (file_name[0] != '-')		// if arg starts with '-', we consider it's not a file name but some other argument
+			{
+				// std::cout << "output file name : " << file_name << std::endl;				
+				store_output_file(output_filenames, input_filenames, file_name);
+				arg += 1;					// Skip that arg now we know it's a file name
+				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list
+					break;
+				file_name = argv[arg+1];	// Next argument and loop over
+			}
+		}
+		else if (!strcmp(argv[arg], "--logmetrics") || !strcmp(argv[arg], "-log"))
+		{
+			// '--logmetrics' needs to be specified with a named test metric argument
+			// Note: for the moment, only ImageCompressionTester has been tested
+			std::string test_name;
+			if ((arg + 1) < argc)
+			{
+				test_name = argv[arg+1];
+			}
+			if (((arg + 1) >= argc) || (test_name[0] == '-'))
+			{
+				// We don't have an argument left in the arg list or the next argument is another option
+				std::cout << "No --logmetrics argument given, no perf data will be gathered" << std::endl;
+			}
+			else
+			{
+				LLFastTimer::sMetricLog = TRUE;
+				LLFastTimer::sLogName = test_name;
+				arg += 1;					// Skip that arg now we know it's a valid test name
+				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list
+					break;
+			}
+		}
+		else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-r"))
+		{
+			analyze_performance = true;
+		}
+		else if (!strcmp(argv[arg], "--image-stats") || !strcmp(argv[arg], "-s"))
+		{
+			image_stats = true;
+		}
+	}
+		
+	// Check arguments consistency. Exit with proper message if inconsistent.
+	if (input_filenames.size() == 0)
+	{
+		std::cout << "No input file, nothing to do -> exit" << std::endl;
+		return 0;
+	}
+	if (analyze_performance && !LLFastTimer::sMetricLog)
+	{
+		std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -r) -> exit" << std::endl;
+		return 0;
+	}
+	
+
+	// Create the logging thread if required
+	if (LLFastTimer::sMetricLog)
+	{
+		LLFastTimer::sLogLock = new LLMutex(NULL);
+		fast_timer_log_thread = new LogThread(LLFastTimer::sLogName);
+		fast_timer_log_thread->start();
+	}
+	
+	// Perform action on each input file
+	std::list<std::string>::iterator in_file  = input_filenames.begin();
+	std::list<std::string>::iterator out_file = output_filenames.begin();
+	std::list<std::string>::iterator in_end = input_filenames.end();
+	std::list<std::string>::iterator out_end = output_filenames.end();
+	for (; in_file != in_end; ++in_file)
+	{
+		// Load file
+		LLPointer<LLImageRaw> raw_image = load_image(*in_file, image_stats);
+		if (!raw_image)
+		{
+			std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
+			continue;
+		}
+	
+		// Save file
+		if (out_file != out_end)
+		{
+			if (!save_image(*out_file, raw_image, image_stats))
+			{
+				std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl;
+			}
+			else
+			{
+				std::cout << *in_file << " -> " << *out_file << std::endl;
+			}
+			++out_file;
+		}
+	}
+
+	// Stop the perf gathering system if needed
+	if (LLFastTimer::sMetricLog)
+	{
+		LLMetricPerformanceTesterBasic::deleteTester(LLFastTimer::sLogName);
+		sAllDone = true;
+	}
+	
+	// Output perf data if requested by user
+	if (analyze_performance)
+	{
+		std::cout << "Analyzing performance" << std::endl;
+		
+		std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
+		std::string current_name  = LLFastTimer::sLogName + ".slp"; 
+		std::string report_name   = LLFastTimer::sLogName + "_report.csv";
+		
+		LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline_name, current_name, report_name);
+	}
+	
+	// Cleanup and exit
+	LLImage::cleanupClass();
+	if (fast_timer_log_thread)
+	{
+		fast_timer_log_thread->shutdown();
+	}
+	
+	return 0;
+}
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.h b/indra/integration_tests/llimage_libtest/llimage_libtest.h
new file mode 100644
index 0000000000000000000000000000000000000000..63f3d46b50b4710c3dc006789b35e6f065075182
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.h
@@ -0,0 +1,29 @@
+/** 
+ * @file llimage_libtest.h
+ *
+ * $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 LLIMAGE_LIBTEST_H
+#define LLIMAGE_LIBTEST_H
+
+
+#endif
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index 5fa3a5ea070bfaeea313ba1a11d948d36dcc0f09..41d3eb0bf369881da267876ef9224e7bcfaf9446 100644
--- a/indra/llcommon/llmetricperformancetester.cpp
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -63,7 +63,18 @@ BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* t
 	sTesterMap.insert(std::make_pair(name, tester));
 	return TRUE;
 }
-	
+
+/*static*/ 
+void LLMetricPerformanceTesterBasic::deleteTester(std::string name)
+{
+	name_tester_map_t::iterator tester = sTesterMap.find(name);
+	if (tester != sTesterMap.end())
+	{
+		delete tester->second;
+		sTesterMap.erase(tester);
+	}
+}
+
 /*static*/ 
 LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name) 
 {
@@ -83,7 +94,78 @@ BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name)
 	return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME)));
 }
 
+/*static*/ 
+LLSD LLMetricPerformanceTesterBasic::analyzeMetricPerformanceLog(std::istream& is)
+{
+	LLSD ret;
+	LLSD cur;
+	
+	while (!is.eof() && LLSDSerialize::fromXML(cur, is))
+	{
+		for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
+		{
+			std::string label = iter->first;
+			
+			LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ;
+			if(tester)
+			{
+				ret[label]["Name"] = iter->second["Name"] ;
+				
+				S32 num_of_metrics = tester->getNumberOfMetrics() ;
+				for(S32 index = 0 ; index < num_of_metrics ; index++)
+				{
+					ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ;
+				}
+			}
+		}
+	}
+	
+	return ret;
+}
+
+/*static*/ 
+void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std::string target, std::string output)
+{
+	if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters())
+	{
+		return ;
+	}
+	
+	// Open baseline and current target, exit if one is inexistent
+	std::ifstream base_is(baseline.c_str());
+	std::ifstream target_is(target.c_str());
+	if (!base_is.is_open() || !target_is.is_open())
+	{
+		llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl;
+		base_is.close();
+		target_is.close();
+		return;
+	}
 	
+	//analyze baseline
+	LLSD base = analyzeMetricPerformanceLog(base_is);
+	base_is.close();
+	
+	//analyze current
+	LLSD current = analyzeMetricPerformanceLog(target_is);
+	target_is.close();
+	
+	//output comparision
+	std::ofstream os(output.c_str());
+	
+	os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; 
+	for(LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin() ; 
+		iter != LLMetricPerformanceTesterBasic::sTesterMap.end() ; ++iter)
+	{
+		LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second) ;	
+		tester->analyzePerformance(&os, &base, &current) ;
+	}
+	
+	os.flush();
+	os.close();
+}
+
+
 //----------------------------------------------------------------------------------------------
 // LLMetricPerformanceTesterBasic : Tester instance methods
 //----------------------------------------------------------------------------------------------
diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h
index 1372f48dcfec7da703e21ce1412137b09c9890b4..1a18cdf36fbf3a55e31f6c7c6cf5bd6a422332ab 100644
--- a/indra/llcommon/llmetricperformancetester.h
+++ b/indra/llcommon/llmetricperformancetester.h
@@ -62,6 +62,8 @@ class LL_COMMON_API LLMetricPerformanceTesterBasic
 	 */
 	virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
 
+	static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ;
+
 	/**
 	 * @return Returns the number of the test metrics in this tester instance.
 	 */
@@ -116,6 +118,7 @@ class LL_COMMON_API LLMetricPerformanceTesterBasic
 private:
 	void preOutputTestResults(LLSD* sd) ;
 	void postOutputTestResults(LLSD* sd) ;
+	static LLSD analyzeMetricPerformanceLog(std::istream& is) ;
 
 	std::string mName ;							// Name of this tester instance
 	S32 mCount ;								// Current record count
@@ -134,6 +137,12 @@ class LL_COMMON_API LLMetricPerformanceTesterBasic
 	 */
 	static LLMetricPerformanceTesterBasic* getTester(std::string name) ;
 	
+	/**
+	 * @return Delete the named tester from the list 
+	 * @param[in] name - Name of the tester instance to delete.
+	 */
+	static void deleteTester(std::string name);
+
 	/**
 	 * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged
 	 * @param[in] name - Name of the tester queried.
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index d22c879243b4ac1bb718495ee33baad5fe44e6c1..488ec5b239476bbe8420eda14eab2e914a4e342c 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 = 6;
-const S32 LL_VERSION_PATCH = 2;
+const S32 LL_VERSION_PATCH = 3;
 const S32 LL_VERSION_BUILD = 0;
 
 const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 825b9aab1a49cefd54b092e05d869d00b15a32b7..18444f393415b572c4e20140409ea8bf753b8eb9 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -266,13 +266,13 @@ class LLImageFormatted : public LLImageBase
 	// subclasses must return a prefered file extension (lowercase without a leading dot)
 	virtual std::string getExtension() = 0;
 	// calcHeaderSize() returns the maximum size of header;
-	//   0 indicates we don't know have a header and have to lead the entire file
+	//   0 indicates we don't have a header and have to read the entire file
 	virtual S32 calcHeaderSize() { return 0; };
 	// calcDataSize() returns how many bytes to read to load discard_level (including header)
 	virtual S32 calcDataSize(S32 discard_level);
 	// calcDiscardLevelBytes() returns the smallest valid discard level based on the number of input bytes
 	virtual S32 calcDiscardLevelBytes(S32 bytes);
-	// getRawDiscardLevel()by default returns mDiscardLevel, but may be overridden (LLImageJ2C)
+	// getRawDiscardLevel() by default returns mDiscardLevel, but may be overridden (LLImageJ2C)
 	virtual S8  getRawDiscardLevel() { return mDiscardLevel; }
 	
 	BOOL load(const std::string& filename);
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index cb2a85fa917afa683954f342d45c488a3e284ec4..80fec7f8a04b571b8f172a1ef3e616eee9a5d1e5 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -474,6 +474,7 @@ LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTester
 
 LLImageCompressionTester::~LLImageCompressionTester()
 {
+	outputTestResults();
 	LLImageJ2C::sTesterp = NULL;
 }
 
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 7a2f06da8facdb86770ccd82ac8178d325ed388d..dc360818d69b5cf3a964eb9e14ad36f233d51cbb 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2143,56 +2143,6 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
 	return retval;
 }
 
-BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
-{
-	std::ifstream is;
-	
-	is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
-
-	BOOL success = createVolumeFacesFromStream(is);
-	
-	is.close();
-
-	return success;
-}
-
-BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
-{
-	mSculptLevel = -1;  // default is an error occured
-
-	LLSD header;
-	{
-		if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
-		{
-			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
-			return FALSE;
-		}
-	}
-	
-	std::string nm[] = 
-	{
-		"lowest_lod",
-		"low_lod",
-		"medium_lod",
-		"high_lod",
-		"physics_shape",
-	};
-
-	const S32 MODEL_LODS = 5;
-
-	S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
-
-	if (header[nm[lod]]["offset"].asInteger() == -1 || 
-		header[nm[lod]]["size"].asInteger() == 0 )
-	{ //cannot load requested LOD
-		return FALSE;
-	}
-
-	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
-
-	return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
-}
-
 bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 {
 	//input stream is now pointing at a zlib compressed block of LLSD
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 60b64b1285426f6921b37a7f2221490882dbda94..01bfbd858be72fd6badd82b8e0e335f68b682eba 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -1048,8 +1048,6 @@ class LLVolume : public LLRefCount
 	BOOL generate();
 	void createVolumeFaces();
 public:
-	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
-	virtual BOOL createVolumeFacesFromStream(std::istream& is);
 	virtual bool unpackVolumeFaces(std::istream& is, S32 size);
 
 	virtual void makeTetrahedron();
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 3669fef0dc8a1af039f06e64afa19ee3d99cb819..595f9aa30719f087112d5a5299587073f2f5534e 100755
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -775,43 +775,6 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
 	return FALSE;
 }
 
-
-BOOL LLModel::createVolumeFacesFromFile(const std::string& file_name)
-{
-	DAE dae;
-	domCOLLADA* dom = dae.open(file_name);
-	if (dom)
-	{
-		daeDatabase* db = dae.getDatabase();
-
-		daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
-		
-		mVolumeFaces.clear();
-		mMaterialList.clear();
-
-		for (daeInt idx = 0; idx < count; ++idx)
-		{
-			domMesh* mesh = NULL;
-
-			db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
-			
-			if (mesh)
-			{
-				addVolumeFacesFromDomMesh(mesh);
-			}
-		}
-
-		if (getNumVolumeFaces() > 0)
-		{
-			optimizeVolumeFaces();
-			normalizeVolumeFaces();
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
 void LLModel::offsetMesh( const LLVector3& pivotPoint )
 {
 	LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] );
@@ -1351,16 +1314,6 @@ std::string LLModel::getElementLabel(daeElement *element)
 	return std::string("object");
 }
 
-//static 
-LLModel* LLModel::loadModelFromDae(std::string filename)
-{
-	LLVolumeParams volume_params;
-	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-	LLModel* ret = new LLModel(volume_params, 0.f); 
-	ret->createVolumeFacesFromFile(filename);
-	return ret;
-}
-
 //static 
 LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh)
 {
@@ -1473,49 +1426,7 @@ LLSD LLModel::writeModel(
 
 	if (skinning)
 	{ //write skinning block
-		if (high->mJointList.size() != high->mInvBindMatrix.size())
-		{
-			llerrs << "WTF?" << llendl;
-		}
-
-		for (U32 i = 0; i < high->mJointList.size(); ++i)
-		{
-			mdl["skin"]["joint_names"][i] = high->mJointList[i];
-
-			for (U32 j = 0; j < 4; j++)
-			{
-				for (U32 k = 0; k < 4; k++)
-				{
-					mdl["skin"]["inverse_bind_matrix"][i][j*4+k] = high->mInvBindMatrix[i].mMatrix[j][k]; 
-				}
-			}
-		}
-
-		for (U32 i = 0; i < 4; i++)
-		{
-			for (U32 j = 0; j < 4; j++)
-			{
-				mdl["skin"]["bind_shape_matrix"][i*4+j] = high->mBindShapeMatrix.mMatrix[i][j];
-			}
-		}
-		
-		
-		if ( upload_joints && high->mAlternateBindMatrix.size() > 0 )
-		{
-			for (U32 i = 0; i < high->mJointList.size(); ++i)
-			{
-				for (U32 j = 0; j < 4; j++)
-				{
-					for (U32 k = 0; k < 4; k++)
-					{
-						mdl["skin"]["alt_inverse_bind_matrix"][i][j*4+k] = high->mAlternateBindMatrix[i].mMatrix[j][k]; 
-					}
-				}
-			}
-
-			mdl["skin"]["pelvis_offset"] = high->mPelvisOffset;
-		}
-		
+		mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints);
 	}
 
 	if (!decomp.empty() || !base_hull.empty())
@@ -1897,12 +1808,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
 	return header;
 }
 
-//static 
-LLModel* LLModel::loadModelFromAsset(std::string filename, S32 lod)
-{
-	return NULL;
-}
-
 LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
 {
 	weight_map::iterator iter = mSkinWeights.find(pos);
@@ -1976,27 +1881,380 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
 void LLModel::setConvexHullDecomposition(
 	const LLModel::convex_hull_decomposition& decomp)
 {
-	mConvexHullDecomp = decomp;
+	mPhysics.mHull = decomp;
+	mPhysics.mMesh.clear();
+	updateHullCenters();
+}
 
-	mHullCenter.resize(mConvexHullDecomp.size());
+void LLModel::updateHullCenters()
+{
+	mHullCenter.resize(mPhysics.mHull.size());
 	mHullPoints = 0;
 	mCenterOfHullCenters.clear();
 
-	for (U32 i = 0; i < decomp.size(); ++i)
+	for (U32 i = 0; i < mPhysics.mHull.size(); ++i)
 	{
 		LLVector3 cur_center;
 
-		for (U32 j = 0; j < decomp[i].size(); ++j)
+		for (U32 j = 0; j < mPhysics.mHull[i].size(); ++j)
 		{
-			cur_center += decomp[i][j];
+			cur_center += mPhysics.mHull[i][j];
 		}
 		mCenterOfHullCenters += cur_center;
-		cur_center *= 1.f/decomp[i].size();
+		cur_center *= 1.f/mPhysics.mHull[i].size();
 		mHullCenter[i] = cur_center;
-		mHullPoints += decomp[i].size();
+		mHullPoints += mPhysics.mHull[i].size();
 	}
 
 	mCenterOfHullCenters *= 1.f / mHullPoints;
 }
 
+bool LLModel::loadModel(std::istream& is)
+{
+	mSculptLevel = -1;  // default is an error occured
+
+	LLSD header;
+	{
+		if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
+		{
+			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
+			return false;
+		}
+	}
+	
+	std::string nm[] = 
+	{
+		"lowest_lod",
+		"low_lod",
+		"medium_lod",
+		"high_lod",
+		"physics_shape",
+	};
+
+	const S32 MODEL_LODS = 5;
+
+	S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
+
+	if (header[nm[lod]]["offset"].asInteger() == -1 || 
+		header[nm[lod]]["size"].asInteger() == 0 )
+	{ //cannot load requested LOD
+		return false;
+	}
+
+	bool has_skin = header["skin"]["offset"].asInteger() >=0 &&
+					header["skin"]["size"].asInteger() > 0;
+
+	if (lod == LLModel::LOD_HIGH)
+	{ //try to load skin info and decomp info
+		std::ios::pos_type cur_pos = is.tellg();
+		loadSkinInfo(header, is);
+		is.seekg(cur_pos);
+	}
+
+	if (lod == LLModel::LOD_PHYSICS)
+	{
+		std::ios::pos_type cur_pos = is.tellg();
+		loadDecomposition(header, is);
+		is.seekg(cur_pos);
+	}
+
+	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+	if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()))
+	{
+		if (has_skin)
+		{ 
+			//build out mSkinWeight from face info
+			for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+			{
+				const LLVolumeFace& face = getVolumeFace(i);
+
+				if (face.mWeights)
+				{
+					for (S32 j = 0; j < face.mNumVertices; ++j)
+					{
+						LLVector4a& w = face.mWeights[j];
+
+						std::vector<JointWeight> wght;
+
+						for (S32 k = 0; k < 4; ++k)
+						{
+							S32 idx = (S32) w[k];
+							F32 f = w[k] - idx;
+							if (f > 0.f)
+							{
+								wght.push_back(JointWeight(idx, f));
+							}
+						}
+
+						if (!wght.empty())
+						{
+							LLVector3 pos(face.mPositions[j].getF32ptr());
+							mSkinWeights[pos] = wght;
+						}
+					}
+				}
+			}
+		}
+		return true;
+	}
+
+	return false;
+
+}
+
+
+bool LLModel::loadSkinInfo(LLSD& header, std::istream &is)
+{
+	S32 offset = header["skin"]["offset"].asInteger();
+	S32 size = header["skin"]["size"].asInteger();
+
+	if (offset >= 0 && size > 0)
+	{
+		is.seekg(offset, std::ios_base::cur);
+
+		LLSD skin_data;
+
+		if (unzip_llsd(skin_data, is, size))
+		{
+			mSkinInfo.fromLLSD(skin_data);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool LLModel::loadDecomposition(LLSD& header, std::istream& is)
+{
+	S32 offset = header["decomposition"]["offset"].asInteger();
+	S32 size = header["decomposition"]["size"].asInteger();
+
+	if (offset >= 0 && size > 0)
+	{
+		is.seekg(offset, std::ios_base::cur);
+
+		LLSD data;
+
+		if (unzip_llsd(data, is, size))
+		{
+			mPhysics.fromLLSD(data);
+			updateHullCenters();
+		}
+	}
+
+	return true;
+}
+
+
+LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin)
+{
+	fromLLSD(skin);
+}
+
+void LLMeshSkinInfo::fromLLSD(LLSD& skin)
+{
+	if (skin.has("joint_names"))
+	{
+		for (U32 i = 0; i < skin["joint_names"].size(); ++i)
+		{
+			mJointNames.push_back(skin["joint_names"][i]);
+		}
+	}
+
+	if (skin.has("inverse_bind_matrix"))
+	{
+		for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i)
+		{
+			LLMatrix4 mat;
+			for (U32 j = 0; j < 4; j++)
+			{
+				for (U32 k = 0; k < 4; k++)
+				{
+					mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal();
+				}
+			}
+
+			mInvBindMatrix.push_back(mat);
+		}
+	}
+
+	if (skin.has("bind_shape_matrix"))
+	{
+		for (U32 j = 0; j < 4; j++)
+		{
+			for (U32 k = 0; k < 4; k++)
+			{
+				mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal();
+			}
+		}
+	}
+
+	if (skin.has("alt_inverse_bind_matrix"))
+	{
+		for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i)
+		{
+			LLMatrix4 mat;
+			for (U32 j = 0; j < 4; j++)
+			{
+				for (U32 k = 0; k < 4; k++)
+				{
+					mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal();
+				}
+			}
+			
+			mAlternateBindMatrix.push_back(mat);
+		}
+	}
+
+	if (skin.has("pelvis_offset"))
+	{
+		mPelvisOffset = skin["pelvis_offset"].asReal();
+	}
+}
+
+LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const
+{
+	LLSD ret;
+
+	for (U32 i = 0; i < mJointNames.size(); ++i)
+	{
+		ret["joint_names"][i] = mJointNames[i];
+
+		for (U32 j = 0; j < 4; j++)
+		{
+			for (U32 k = 0; k < 4; k++)
+			{
+				ret["inverse_bind_matrix"][i][j*4+k] = mInvBindMatrix[i].mMatrix[j][k]; 
+			}
+		}
+	}
+
+	for (U32 i = 0; i < 4; i++)
+	{
+		for (U32 j = 0; j < 4; j++)
+		{
+			ret["bind_shape_matrix"][i*4+j] = mBindShapeMatrix.mMatrix[i][j];
+		}
+	}
+		
+	if ( include_joints && mAlternateBindMatrix.size() > 0 )
+	{
+		for (U32 i = 0; i < mJointNames.size(); ++i)
+		{
+			for (U32 j = 0; j < 4; j++)
+			{
+				for (U32 k = 0; k < 4; k++)
+				{
+					ret["alt_inverse_bind_matrix"][i][j*4+k] = mAlternateBindMatrix[i].mMatrix[j][k]; 
+				}
+			}
+		}
+
+		ret["pelvis_offset"] = mPelvisOffset;
+	}
+
+	return ret;
+}
+
+LLModel::Decomposition::Decomposition(LLSD& data)
+{
+	fromLLSD(data);
+}
+
+void LLModel::Decomposition::fromLLSD(LLSD& decomp)
+{
+	if (decomp.has("HullList"))
+	{
+		// updated for const-correctness. gcc is picky about this type of thing - Nyx
+		const LLSD::Binary& hulls = decomp["HullList"].asBinary();
+		const LLSD::Binary& position = decomp["Position"].asBinary();
+
+		U16* p = (U16*) &position[0];
+
+		mHull.resize(hulls.size());
+
+		LLVector3 min;
+		LLVector3 max;
+		LLVector3 range;
+
+		min.setValue(decomp["Min"]);
+		max.setValue(decomp["Max"]);
+		range = max-min;
+
+		for (U32 i = 0; i < hulls.size(); ++i)
+		{
+			U16 count = (hulls[i] == 0) ? 256 : hulls[i];
+			
+			for (U32 j = 0; j < count; ++j)
+			{
+				mHull[i].push_back(LLVector3(
+					(F32) p[0]/65535.f*range.mV[0]+min.mV[0],
+					(F32) p[1]/65535.f*range.mV[1]+min.mV[1],
+					(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
+				p += 3;
+			}		 
+
+		}
+	}
+
+	if (decomp.has("Hull"))
+	{
+		const LLSD::Binary& position = decomp["Hull"].asBinary();
+
+		U16* p = (U16*) &position[0];
+
+		LLVector3 min;
+		LLVector3 max;
+		LLVector3 range;
+
+		min.setValue(decomp["Min"]);
+		max.setValue(decomp["Max"]);
+		range = max-min;
+
+		U16 count = position.size()/6;
+		
+		for (U32 j = 0; j < count; ++j)
+		{
+			mBaseHull.push_back(LLVector3(
+				(F32) p[0]/65535.f*range.mV[0]+min.mV[0],
+				(F32) p[1]/65535.f*range.mV[1]+min.mV[1],
+				(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
+			p += 3;
+		}		 
+	}
+	else
+	{
+		//empty base hull mesh to indicate decomposition has been loaded
+		//but contains no base hull
+		mBaseHullMesh.clear();;
+	}
+
+}
+
+void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)
+{
+	if (!rhs)
+	{
+		return;
+	}
+
+	if (mMeshID != rhs->mMeshID)
+	{
+		llerrs << "Attempted to merge with decomposition of some other mesh." << llendl;
+	}
+
+	if (mBaseHull.empty())
+	{ //take base hull and decomposition from rhs
+		mHull = rhs->mHull;
+		mBaseHull = rhs->mBaseHull;
+		mMesh = rhs->mMesh;
+		mBaseHullMesh = rhs->mBaseHullMesh;
+	}
+
+	if (mPhysicsShapeMesh.empty())
+	{ //take physics shape mesh from rhs
+		mPhysicsShapeMesh = rhs->mPhysicsShapeMesh;
+	}
+}
 
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index addf527d8df5c965f03505c624f69f9d9e525868..e9450d29678da12c3b7e3cec1788a9ff74e3bf19 100755
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -27,6 +27,7 @@
 #ifndef LL_LLMODEL_H
 #define LL_LLMODEL_H
 
+#include "llpointer.h"
 #include "llvolume.h"
 #include "v4math.h"
 #include "m4math.h"
@@ -36,6 +37,24 @@ class domMesh;
 
 #define MAX_MODEL_FACES 8
 
+
+class LLMeshSkinInfo 
+{
+public:
+	LLUUID mMeshID;
+	std::vector<std::string> mJointNames;
+	std::vector<LLMatrix4> mInvBindMatrix;
+	std::vector<LLMatrix4> mAlternateBindMatrix;
+	std::map<std::string, U32> mJointMap;
+
+	LLMeshSkinInfo() { }
+	LLMeshSkinInfo(LLSD& data);
+	void fromLLSD(LLSD& data);
+	LLSD asLLSD(bool include_joints) const;
+	LLMatrix4 mBindShapeMatrix;
+	float mPelvisOffset;
+};
+
 class LLModel : public LLVolume
 {
 public:
@@ -58,6 +77,9 @@ class LLModel : public LLVolume
 	LLModel(LLVolumeParams& params, F32 detail);
 	~LLModel();
 
+	bool loadModel(std::istream& is);
+	bool loadSkinInfo(LLSD& header, std::istream& is);
+	bool loadDecomposition(LLSD& header, std::istream& is);
 	static LLSD writeModel(
 		std::string filename,
 		LLModel* physics,
@@ -98,8 +120,6 @@ class LLModel : public LLVolume
 		LLSD& mdl,
 		BOOL nowrite = FALSE);
 
-	static LLModel* loadModelFromAsset(std::string filename, S32 lod);
-	static LLModel* loadModelFromDae(std::string filename);
 	static LLModel* loadModelFromDomMesh(domMesh* mesh);
 	static std::string getElementLabel(daeElement* element);
 	std::string getName() const;
@@ -177,17 +197,8 @@ class LLModel : public LLVolume
 	//get list of weight influences closest to given position
 	weight_list& getJointInfluences(const LLVector3& pos);
 
-	//should always be true that mJointList[mJointMap["foo"]] == "foo"
-
-	//map of joint names to joint index
-	std::map<std::string, U32> mJointMap;
-
-	//list of joint names
-	std::vector<std::string> mJointList;
-
-	LLMatrix4 mBindShapeMatrix;
-	std::vector<LLMatrix4> mInvBindMatrix;
-	std::vector<LLMatrix4> mAlternateBindMatrix;
+	LLMeshSkinInfo mSkinInfo;
+	
 	std::string mRequestedLabel; // name requested in UI, if any.
 	std::string mLabel; // name computed from dae.
 
@@ -197,9 +208,10 @@ class LLModel : public LLVolume
 	float	mPelvisOffset;
 	// convex hull decomposition
 	S32 mDecompID;
-	convex_hull_decomposition mConvexHullDecomp;
+	
 	void setConvexHullDecomposition(
 		const convex_hull_decomposition& decomp);
+	void updateHullCenters();
 
 	LLVector3 mCenterOfHullCenters;
 	std::vector<LLVector3> mHullCenter;
@@ -208,9 +220,46 @@ class LLModel : public LLVolume
 	//ID for storing this model in a .slm file
 	S32 mLocalID;
 
+	class PhysicsMesh
+	{
+	public:
+		std::vector<LLVector3> mPositions;
+		std::vector<LLVector3> mNormals;
+
+		void clear()
+		{
+			mPositions.clear();
+			mNormals.clear();
+		}
+
+		bool empty() const
+		{
+			return mPositions.empty();
+		}
+	};
+
+	class Decomposition
+	{
+	public:
+		Decomposition() { }
+		Decomposition(LLSD& data);
+		void fromLLSD(LLSD& data);
+		
+		void merge(const Decomposition* rhs);
+
+		LLUUID mMeshID;
+		LLModel::convex_hull_decomposition mHull;
+		LLModel::hull mBaseHull;
+
+		std::vector<LLModel::PhysicsMesh> mMesh;
+		LLModel::PhysicsMesh mBaseHullMesh;
+		LLModel::PhysicsMesh mPhysicsShapeMesh;
+	};
+
+	Decomposition mPhysics;
+
 protected:
 	void addVolumeFacesFromDomMesh(domMesh* mesh);
-	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
 	virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
 };
 
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 0d3f5b81bcc3b698012e5d1f3e5b8d231f362aff..73efbfc9998ea399056523caca5ac5555e589cc0 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -236,6 +236,22 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 	}
 }
 
+//static
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
+{
+	U32 count = pos.size();
+	llassert(norm.size() >= pos.size());
+
+	unbind();
+	
+	setupClientArrays(MAP_VERTEX | MAP_NORMAL);
+
+	glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+	glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+
+	glDrawArrays(sGLMode[mode], 0, count);
+}
+
 void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
 {
 	if (start >= (U32) mRequestedNumVerts ||
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 2bbc17fb12a67ed16ad7a5d9be06b736b4124edc..6c0895512ea1e6347c9c9cebc5cde3f8ba9eb4ed 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -97,6 +97,8 @@ class LLVertexBuffer : public LLRefCount
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
 	static void setupClientArrays(U32 data_mask);
+	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
+
  	static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
 	static void unbind(); //unbind any bound vertex buffer
 
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index d4ec377e03ddb3e606966734d30c489859ffecb3..c0c9ea145164b27d65ee4a0d0e201043e78d80d9 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -793,21 +793,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 			if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
 			{
 				// for object IMs, create a secondlife:///app/objectim SLapp
-				std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString();
-				url += "?name=" + chat.mFromName;
-				url += "&owner=" + chat.mOwnerID.asString();
-
-				std::string slurl = args["slurl"].asString();
-				if (slurl.empty())
-				{
-				    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
-				    if(region)
-				      {
-					LLSLURL region_slurl(region->getName(), chat.mPosAgent);
-					slurl = region_slurl.getLocationString();
-				      }
-				}
-				url += "&slurl=" + LLURI::escape(slurl);
+				std::string url = LLViewerChat::getSenderSLURL(chat, args);
 
 				// set the link for the object name to be the objectim SLapp
 				// (don't let object names with hyperlinks override our objectim Url)
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index 899e0431e7c29634dd37c8e7ddd7c759151b8eca..8584885bc974e842e63d916ead326abf9e76db4d 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -213,17 +213,6 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
 		{
 			LLStyle::Params style_params_name;
 
-			std::string href;
-
-			if (mSourceType == CHAT_SOURCE_AGENT)
-			{
-				href = LLSLURL("agent", mFromID, "about").getSLURLString();
-			}
-			else
-			{
-				href = LLSLURL("object", mFromID, "inspect").getSLURLString();
-			}
-
 			LLColor4 user_name_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
 			style_params_name.color(user_name_color);
 
@@ -232,7 +221,7 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
 			style_params_name.font.name(font_name);
 			style_params_name.font.size(font_style_size);
 
-			style_params_name.link_href = href;
+			style_params_name.link_href = notification["sender_slurl"].asString();
 			style_params_name.is_link = true;
 
 			msg_text->appendText(str_sender, FALSE, style_params_name);
diff --git a/indra/newview/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp
index 54968841ab1521461002482ad0631f39aecfa46f..ed1d7e860a0cfa672fe78857a6b8861059c5169f 100644
--- a/indra/newview/llexternaleditor.cpp
+++ b/indra/newview/llexternaleditor.cpp
@@ -27,6 +27,7 @@
 #include "llviewerprecompiledheaders.h"
 #include "llexternaleditor.h"
 
+#include "lltrans.h"
 #include "llui.h"
 
 // static
@@ -35,13 +36,13 @@ const std::string LLExternalEditor::sFilenameMarker = "%s";
 // static
 const std::string LLExternalEditor::sSetting = "ExternalEditor";
 
-bool LLExternalEditor::setCommand(const std::string& env_var, const std::string& override)
+LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env_var, const std::string& override)
 {
 	std::string cmd = findCommand(env_var, override);
 	if (cmd.empty())
 	{
-		llwarns << "Empty editor command" << llendl;
-		return false;
+		llwarns << "Editor command is empty or not set" << llendl;
+		return EC_NOT_SPECIFIED;
 	}
 
 	// Add the filename marker if missing.
@@ -55,7 +56,7 @@ bool LLExternalEditor::setCommand(const std::string& env_var, const std::string&
 	if (tokenize(tokens, cmd) < 2) // 2 = bin + at least one arg (%s)
 	{
 		llwarns << "Error parsing editor command" << llendl;
-		return false;
+		return EC_PARSE_ERROR;
 	}
 
 	// Check executable for existence.
@@ -63,7 +64,7 @@ bool LLExternalEditor::setCommand(const std::string& env_var, const std::string&
 	if (!LLFile::isfile(bin_path))
 	{
 		llwarns << "Editor binary [" << bin_path << "] not found" << llendl;
-		return false;
+		return EC_BINARY_NOT_FOUND;
 	}
 
 	// Save command.
@@ -76,16 +77,16 @@ bool LLExternalEditor::setCommand(const std::string& env_var, const std::string&
 	}
 	llinfos << "Setting command [" << bin_path << " " << mArgs << "]" << llendl;
 
-	return true;
+	return EC_SUCCESS;
 }
 
-bool LLExternalEditor::run(const std::string& file_path)
+LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path)
 {
 	std::string args = mArgs;
 	if (mProcess.getExecutable().empty() || args.empty())
 	{
 		llwarns << "Editor command not set" << llendl;
-		return false;
+		return EC_NOT_SPECIFIED;
 	}
 
 	// Substitute the filename marker in the command with the actual passed file name.
@@ -111,7 +112,22 @@ bool LLExternalEditor::run(const std::string& file_path)
 		mProcess.orphan();
 	}
 
-	return result == 0;
+	return result == 0 ? EC_SUCCESS : EC_FAILED_TO_RUN;
+}
+
+// static
+std::string LLExternalEditor::getErrorMessage(EErrorCode code)
+{
+	switch (code)
+	{
+	case EC_SUCCESS: 			return LLTrans::getString("ok");
+	case EC_NOT_SPECIFIED: 		return LLTrans::getString("ExternalEditorNotSet");
+	case EC_PARSE_ERROR:		return LLTrans::getString("ExternalEditorCommandParseError");
+	case EC_BINARY_NOT_FOUND:	return LLTrans::getString("ExternalEditorNotFound");
+	case EC_FAILED_TO_RUN:		return LLTrans::getString("ExternalEditorFailedToRun");
+	}
+
+	return LLTrans::getString("Unknown");
 }
 
 // static
diff --git a/indra/newview/llexternaleditor.h b/indra/newview/llexternaleditor.h
index 6ea210d5e222d69dfc81ed3d4d9ab23758ad520b..ef5db56c6ee056e6ed1ee560c20ae2e1abe51e92 100644
--- a/indra/newview/llexternaleditor.h
+++ b/indra/newview/llexternaleditor.h
@@ -42,6 +42,14 @@ class LLExternalEditor
 
 public:
 
+	typedef enum e_error_code {
+		EC_SUCCESS,				/// No error.
+		EC_NOT_SPECIFIED,		/// Editor path not specified.
+		EC_PARSE_ERROR,			/// Editor command parsing error.
+		EC_BINARY_NOT_FOUND,	/// Could find the editor binary (missing or not quoted).
+		EC_FAILED_TO_RUN,		/// Could not execute the editor binary.
+	} EErrorCode;
+
 	/**
 	 * Set editor command.
 	 *
@@ -51,19 +59,25 @@ class LLExternalEditor
 	 * First tries the override, then a predefined setting (sSetting),
 	 * then the environment variable.
 	 *
-	 * @return Command if found, empty string otherwise.
+	 * @return EC_SUCCESS if command is valid and refers to an existing executable,
+	 *         EC_NOT_SPECIFIED or EC_FAILED_TO_RUNan on error.
 	 *
 	 * @see sSetting
 	 */
-	bool setCommand(const std::string& env_var, const std::string& override = LLStringUtil::null);
+	EErrorCode setCommand(const std::string& env_var, const std::string& override = LLStringUtil::null);
 
 	/**
 	 * Run the editor with the given file.
 	 *
 	 * @param file_path File to edit.
-	 * @return true on success, false on error.
+	 * @return EC_SUCCESS on success, error code on error.
+	 */
+	EErrorCode run(const std::string& file_path);
+
+	/**
+	 * Get a meaningful error message for the given status code.
 	 */
-	bool run(const std::string& file_path);
+	static std::string getErrorMessage(EErrorCode code);
 
 private:
 
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 2bafb9a4a7dda1cb9ca79f9108452ef9307c7beb..6e78ea6bbea2f414784bc8ff12a59881d323858e 100755
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -1538,36 +1538,6 @@ void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target
 	os.close();
 }
 
-//-------------------------
-//static
-LLSD LLFastTimerView::analyzeMetricPerformanceLog(std::istream& is)
-{
-	LLSD ret;
-	LLSD cur;
-
-	while (!is.eof() && LLSDSerialize::fromXML(cur, is))
-	{
-		for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
-		{
-			std::string label = iter->first;
-
-			LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ;
-			if(tester)
-			{
-				ret[label]["Name"] = iter->second["Name"] ;
-
-				S32 num_of_metrics = tester->getNumberOfMetrics() ;
-				for(S32 index = 0 ; index < num_of_metrics ; index++)
-				{
-					ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ;
-				}
-			}
-		}
-	}
-		
-	return ret;
-}
-
 //static
 void LLFastTimerView::outputAllMetrics()
 {
@@ -1582,48 +1552,6 @@ void LLFastTimerView::outputAllMetrics()
 	}
 }
 
-//static
-void LLFastTimerView::doAnalysisMetrics(std::string baseline, std::string target, std::string output)
-{
-	if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters())
-	{
-		return ;
-	}
-
-	// Open baseline and current target, exit if one is inexistent
-	std::ifstream base_is(baseline.c_str());
-	std::ifstream target_is(target.c_str());
-	if (!base_is.is_open() || !target_is.is_open())
-	{
-		llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl;
-		base_is.close();
-		target_is.close();
-		return;
-	}
-
-	//analyze baseline
-	LLSD base = analyzeMetricPerformanceLog(base_is);
-	base_is.close();
-
-	//analyze current
-	LLSD current = analyzeMetricPerformanceLog(target_is);
-	target_is.close();
-
-	//output comparision
-	std::ofstream os(output.c_str());
-	
-	os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; 
-	for(LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin() ; 
-		iter != LLMetricPerformanceTesterBasic::sTesterMap.end() ; ++iter)
-	{
-		LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second) ;	
-		tester->analyzePerformance(&os, &base, &current) ;
-	}
-	
-	os.flush();
-	os.close();
-}
-
 //static
 void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::string output)
 {
@@ -1635,7 +1563,7 @@ void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::
 
 	if(LLFastTimer::sMetricLog)
 	{
-		doAnalysisMetrics(baseline, target, output) ;
+		LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline, target, output) ;
 		return ;
 	}
 }
diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h
index c409445d864be4abcb6929978d4cd891f8b41679..ea8251191b29e6a4fd50ca3d16d505aa1364a8e9 100644
--- a/indra/newview/llfasttimerview.h
+++ b/indra/newview/llfasttimerview.h
@@ -42,8 +42,6 @@ class LLFastTimerView : public LLFloater
 
 private:
 	static void doAnalysisDefault(std::string baseline, std::string target, std::string output) ;
-	static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ;
-	static LLSD analyzeMetricPerformanceLog(std::istream& is) ;
 	static LLSD analyzePerformanceLogDefault(std::istream& is) ;
 	static void exportCharts(const std::string& base, const std::string& target);
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 10f53dab019d8797d2f116fd2bc36fb972708390..4d7c079a6ff4c3d1b314d466f61ab125360333c1 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -322,8 +322,6 @@ BOOL LLFloaterModelPreview::postBuild()
 	childDisable("upload_skin");
 	childDisable("upload_joints");
 
-	childDisable("pelvis_offset");
-
 	childDisable("ok_btn");
 
 	mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn");
@@ -391,7 +389,11 @@ LLFloaterModelPreview::~LLFloaterModelPreview()
 		gAgentAvatarp->resetJointPositions();
 	}
 
+	
+	if ( mModelPreview )
+	{
 	delete mModelPreview;
+	}
 
 	if (mGLName)
 	{
@@ -1328,17 +1330,19 @@ bool LLModelLoader::doLoadModel()
 						{ //get bind shape matrix
 							domFloat4x4& dom_value = bind_mat->getValue();
 							
+							LLMeshSkinInfo& skin_info = model->mSkinInfo;
+
 							for (int i = 0; i < 4; i++)
 							{
 								for(int j = 0; j < 4; j++)
 								{
-									model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
+									skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
 								}
 							}
 							
 							LLMatrix4 trans = normalized_transformation;
-							trans *= model->mBindShapeMatrix;
-							model->mBindShapeMatrix = trans;
+							trans *= skin_info.mBindShapeMatrix;
+							skin_info.mBindShapeMatrix = trans;
 							
 						}
 						
@@ -1477,7 +1481,7 @@ bool LLModelLoader::doLoadModel()
 							xsNMTOKEN semantic = input->getSemantic();
 							
 							if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
-							{ //found joint source, fill model->mJointMap and model->mJointList
+							{ //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
 								daeElement* elem = input->getSource().getElement();
 								
 								domSource* source = daeSafeCast<domSource>(elem);
@@ -1498,8 +1502,8 @@ bool LLModelLoader::doLoadModel()
 											{
 												name = mJointMap[name];
 											}
-											model->mJointList.push_back(name);
-											model->mJointMap[name] = j;
+											model->mSkinInfo.mJointNames.push_back(name);
+											model->mSkinInfo.mJointMap[name] = j;
 										}
 									}
 									else
@@ -1516,8 +1520,8 @@ bool LLModelLoader::doLoadModel()
 												{
 													name = mJointMap[name];
 												}
-												model->mJointList.push_back(name);
-												model->mJointMap[name] = j;
+												model->mSkinInfo.mJointNames.push_back(name);
+												model->mSkinInfo.mJointMap[name] = j;
 											}
 										}
 									}
@@ -1546,7 +1550,7 @@ bool LLModelLoader::doLoadModel()
 												}
 											}
 											
-											model->mInvBindMatrix.push_back(mat);
+											model->mSkinInfo.mInvBindMatrix.push_back(mat);
 										}
 									}
 								}
@@ -1557,8 +1561,8 @@ bool LLModelLoader::doLoadModel()
 						//(which means we have all the joints that are required for an avatar versus
 						//a skinned asset attached to a node in a file that contains an entire skeleton,
 						//but does not use the skeleton).
-						mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) );
-							if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) 
+						mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mSkinInfo.mJointNames ) );
+						if ( !skeletonWithNoRootNode && !model->mSkinInfo.mJointNames.empty() && mPreview->isRigValid() ) 
 						{
 							mResetJoints = true;
 						}
@@ -1598,8 +1602,8 @@ bool LLModelLoader::doLoadModel()
 						//in the same order as they were stored in the joint buffer. The joints associated
 						//with the skeleton are not stored in the same order as they are in the exported joint buffer.
 						//This remaps the skeletal joints to be in the same order as the joints stored in the model.
-						std::vector<std::string> :: const_iterator jointIt  = model->mJointList.begin();
-						const int jointCnt = model->mJointList.size();
+						std::vector<std::string> :: const_iterator jointIt  = model->mSkinInfo.mJointNames.begin();
+						const int jointCnt = model->mSkinInfo.mJointNames.size();
 						for ( int i=0; i<jointCnt; ++i, ++jointIt )
 						{
 							std::string lookingForJoint = (*jointIt).c_str();
@@ -1608,9 +1612,9 @@ bool LLModelLoader::doLoadModel()
 							if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() )
 							{
 								LLMatrix4 jointTransform = jointTransforms[lookingForJoint];
-								LLMatrix4 newInverse = model->mInvBindMatrix[i];
+								LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
 								newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() );
-								model->mAlternateBindMatrix.push_back( newInverse );
+								model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
 							}
 							else
 							{
@@ -1815,10 +1819,15 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
 		{
 			std::stringstream str(mesh[i].asString());
 			LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
-			if (loaded_model->createVolumeFacesFromStream(str))
+			if (loaded_model->loadModel(str))
 			{
 				loaded_model->mLocalID = i;
 				model[lod].push_back(loaded_model);
+
+				if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty())
+				{ //check to see if rig is valid
+					mPreview->setRigValid( doesJointArrayContainACompleteRig( loaded_model->mSkinInfo.mJointNames ) );
+				}
 			}
 			else
 			{
@@ -1873,16 +1882,13 @@ void LLModelLoader::loadModelCallback()
 {
 	if (mPreview)
 	{
-		mPreview->loadModelCallback(mLod);
-		mPreview->mModelLoader = NULL;
+		mPreview->loadModelCallback(mLod);	
 	}
 
 	while (!isStopped())
 	{ //wait until this thread is stopped before deleting self
 		apr_sleep(100);
 	}
-
-	delete this;
 }
 
 void LLModelLoader::handlePivotPoint( daeElement* pRoot )
@@ -2458,6 +2464,7 @@ LLModelPreview::~LLModelPreview()
 {
 	if (mModelLoader)
 	{
+		delete mModelLoader;
 		mModelLoader->mPreview = NULL;
 	}
 	//*HACK : *TODO : turn this back on when we understand why this crashes
@@ -2494,8 +2501,13 @@ U32 LLModelPreview::calcResourceCost()
 	U32 num_hulls = 0;
 
 	F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f;
-	mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 32.0f;
+	mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f;
 	
+	if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() )
+	{
+		gAgentAvatarp->setPelvisOffset( mPelvisZOffset );
+	}
+
 	F32 streaming_cost = 0.f;
 	F32 physics_cost = 0.f;
 	for (U32 i = 0; i < mUploadData.size(); ++i)
@@ -2508,8 +2520,8 @@ U32 LLModelPreview::calcResourceCost()
 
 			LLModel::convex_hull_decomposition& decomp =
 			instance.mLOD[LLModel::LOD_PHYSICS] ?
-			instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp :
-			instance.mModel->mConvexHullDecomp;
+			instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull :
+			instance.mModel->mPhysics.mHull;
 
 			LLSD ret = LLModel::writeModel(
 										   "",
@@ -2732,8 +2744,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
 
 			LLModel::convex_hull_decomposition& decomp =
 				instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? 
-				instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : 
-				instance.mModel->mConvexHullDecomp;
+				instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
+				instance.mModel->mPhysics.mHull;
 
 			LLModel::writeModel(str, 
 				instance.mLOD[LLModel::LOD_PHYSICS], 
@@ -2904,6 +2916,9 @@ void LLModelPreview::loadModelCallback(S32 lod)
 		mBaseModel.clear();
 		mBaseScene.clear();
 
+		bool skin_weights = false;
+		bool joint_positions = false;
+
 		for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
 		{ //for each LoD
 
@@ -2937,11 +2952,39 @@ void LLModelPreview::loadModelCallback(S32 lod)
 						}
 
 						mModel[lod][idx] = list_iter->mModel;	
+						if (!list_iter->mModel->mSkinWeights.empty())
+						{
+							skin_weights = true;
+
+							if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty())
+							{
+								joint_positions = true;
+							}
+						}
 					}
 				}
 			}
 		}
 
+		if (mFMP)
+		{
+			LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP;
+
+			if (skin_weights)
+			{ //enable uploading/previewing of skin weights if present in .slm file
+				fmp->enableViewOption("show_skin_weight");
+				mViewOption["show_skin_weight"] = true;
+				fmp->childSetValue("upload_skin", true);
+			}
+
+			if (joint_positions)
+			{ 
+				fmp->enableViewOption("show_joint_positions");
+				mViewOption["show_joint_positions"] = true;
+				fmp->childSetValue("upload_joints", true);
+			}
+		}
+
 		//copy high lod to base scene for LoD generation
 		mBaseScene = mScene[LLModel::LOD_HIGH];
 		mBaseModel = mModel[LLModel::LOD_HIGH];
@@ -2955,14 +2998,8 @@ void LLModelPreview::loadModelCallback(S32 lod)
 		mScene[lod] = mModelLoader->mScene;
 		mVertexBuffer[lod].clear();
 
-		if (lod == LLModel::LOD_PHYSICS)
-		{
-			mPhysicsMesh.clear();
-		}
-
 		setPreviewLOD(lod);
 
-
 		if (lod == LLModel::LOD_HIGH)
 		{ //save a copy of the highest LOD for automatic LOD manipulation
 			if (mBaseModel.empty())
@@ -2995,8 +3032,12 @@ void LLModelPreview::loadModelCallback(S32 lod)
 
 void LLModelPreview::resetPreviewTarget()
 {
-	mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f;
-	mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f;
+	if ( mModelLoader )
+	{
+		mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f;
+		mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f;
+	}
+
 	setPreviewTarget(mPreviewScale.magVec()*2.f);
 }
 
@@ -3081,11 +3122,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 		return;
 	}
 
-	if (which_lod == LLModel::LOD_PHYSICS)
-	{ //clear physics mesh map
-		mPhysicsMesh.clear();
-	}
-
 	LLVertexBuffer::unbind();
 
 	stop_gloderror();
@@ -3414,11 +3450,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 			//of an open problem).
 			target_model->mPosition = base->mPosition;
 			target_model->mSkinWeights = base->mSkinWeights;
-			target_model->mJointMap = base->mJointMap;
-			target_model->mJointList = base->mJointList;
-			target_model->mInvBindMatrix = base->mInvBindMatrix;
-			target_model->mBindShapeMatrix = base->mBindShapeMatrix;
-			target_model->mAlternateBindMatrix = base->mAlternateBindMatrix;
+			target_model->mSkinInfo = base->mSkinInfo;
 			//copy material list
 			target_model->mMaterialList = base->mMaterialList;
 
@@ -3638,7 +3670,7 @@ void LLModelPreview::updateStatusMessages()
 		LLModel* model = mModel[LLModel::LOD_PHYSICS][i];
 		S32 cur_submeshes = model->getNumVolumeFaces();
 
-		LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp;
+		LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull;
 
 		if (!decomp.empty())
 		{
@@ -4217,9 +4249,9 @@ BOOL LLModelPreview::render()
 						glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
 						if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull())
 						{
-							gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true);
 							if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1)
 							{
+								gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true);
 								mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get());
 							}
 						}
@@ -4275,12 +4307,17 @@ BOOL LLModelPreview::render()
 					{
 						LLMutexLock(decomp->mMutex);
 
-						std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > >::iterator iter =
-							mPhysicsMesh.find(model);
-						if (iter != mPhysicsMesh.end())
+						LLModel::Decomposition& physics = model->mPhysics;
+
+						if (physics.mMesh.empty())
+						{ //build vertex buffer for physics mesh
+							gMeshRepo.buildPhysicsMesh(physics);
+						}
+							
+						if (!physics.mMesh.empty())
 						{ //render hull instead of mesh
 							render_mesh = false;
-							for (U32 i = 0; i < iter->second.size(); ++i)
+							for (U32 i = 0; i < physics.mMesh.size(); ++i)
 							{
 								if (explode > 0.f)
 								{
@@ -4299,14 +4336,8 @@ BOOL LLModelPreview::render()
 									hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255));
 								}
 
-								LLVertexBuffer* buff = iter->second[i];
-								if (buff)
-								{
-									buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL);
-
 									glColor4ubv(hull_colors[i].mV);
-									buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-								}
+								LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
 
 								if (explode > 0.f)
 								{
@@ -4390,12 +4421,12 @@ BOOL LLModelPreview::render()
 
 							//build matrix palette
 							LLMatrix4 mat[64];
-							for (U32 j = 0; j < model->mJointList.size(); ++j)
+							for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j)
 							{
-								LLJoint* joint = avatar->getJoint(model->mJointList[j]);
+								LLJoint* joint = avatar->getJoint(model->mSkinInfo.mJointNames[j]);
 								if (joint)
 								{
-									mat[j] = model->mInvBindMatrix[j];
+									mat[j] = model->mSkinInfo.mInvBindMatrix[j];
 									mat[j] *= joint->getWorldMatrix();
 								}
 							}
@@ -4436,7 +4467,7 @@ BOOL LLModelPreview::render()
 								//VECTORIZE THIS
 								LLVector3 v(face.mPositions[j].getF32ptr());
 
-								v = v * model->mBindShapeMatrix;
+								v = v * model->mSkinInfo.mBindShapeMatrix;
 								v = v * final_mat;
 
 								position[j] = v;
@@ -4515,9 +4546,12 @@ void LLModelPreview::setPreviewLOD(S32 lod)
 		mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD]));
 		mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]);
 
-		// the wizard has two lod drop downs
+		// the wizard has three lod drop downs
 		LLComboBox* combo_box2 = mFMP->getChild<LLComboBox>("preview_lod_combo2");
 		combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
+		
+		LLComboBox* combo_box3 = mFMP->getChild<LLComboBox>("preview_lod_combo3");
+		combo_box3->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
 
 		LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor");
 		LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor");
@@ -4683,7 +4717,6 @@ void LLFloaterModelPreview::DecompRequest::completed()
 			{
 				if (sInstance->mModelPreview)
 				{
-					sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;
 					sInstance->mModelPreview->mDirty = true;
 					LLFloaterModelPreview::sInstance->mModelPreview->refresh();
 				}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 68fa0fa4c11dc172a0e677d494c54eee56766bf3..6542ed4fbe85d87f001c85db6740a3d921b66b2d 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -358,8 +358,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 	U32 mGroup;
 	std::map<LLPointer<LLModel>, U32> mObject;
 	U32 mMaxTriangleLimit;
-	std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > > mPhysicsMesh;
-
+	
 	LLMeshUploadThread::instance_list mUploadData;
 	std::set<LLViewerFetchedTexture* > mTextureSet;
 
diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp
index eafea1fe03cf7019f1ab5586de075a008cda0dda..532c6789bb4b6987666100b0878ce5abc0a6ca0e 100644
--- a/indra/newview/llfloatermodelwizard.cpp
+++ b/indra/newview/llfloatermodelwizard.cpp
@@ -46,6 +46,7 @@ static	const std::string stateNames[]={
 	"choose_file",
 	"optimize",
 	"physics",
+	"physics2",
 	"review",
 	"upload"};
 
@@ -58,6 +59,7 @@ 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));
 }
@@ -125,15 +127,29 @@ void LLFloaterModelWizard::setState(int state)
 		getChildView("cancel")->setVisible(true);
 	}
 
-	if (state == REVIEW)
+	if (state == PHYSICS2)
 	{
 		if (mLastEnabledState < state)
 		{
 			executePhysicsStage("Decompose");
 		}
-		
+
 		mModelPreview->mViewOption["show_physics"] = true;
 
+		getChildView("next")->setVisible(true);
+		getChildView("next")->setEnabled(true);
+		getChildView("upload")->setVisible(false);
+		getChildView("close")->setVisible(false);
+		getChildView("back")->setVisible(true);
+		getChildView("back")->setEnabled(true);
+		getChildView("cancel")->setVisible(true);
+	}
+
+	if (state == REVIEW)
+	{
+		
+		mModelPreview->mViewOption["show_physics"] = false;
+
 		getChildView("close")->setVisible(false);
 		getChildView("next")->setVisible(false);
 		getChildView("back")->setVisible(true);
@@ -182,6 +198,18 @@ void LLFloaterModelWizard::updateButtons()
 			button->setEnabled(FALSE);
 		}
 	}
+
+	LLButton *physics_button = getChild<LLButton>(stateNames[PHYSICS]+"_btn");
+	
+	if (mState == PHYSICS2)
+	{
+		physics_button->setVisible(false);
+	}
+	else
+	{
+		physics_button->setVisible(true);
+	}
+
 }
 
 void LLFloaterModelWizard::loadModel()
@@ -457,7 +485,6 @@ void LLFloaterModelWizard::DecompRequest::completed()
 	{
 		if (sInstance->mModelPreview)
 		{
-			sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;
 			sInstance->mModelPreview->mDirty = true;
 			LLFloaterModelWizard::sInstance->mModelPreview->refresh();
 		}
@@ -486,6 +513,7 @@ 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));
@@ -502,6 +530,7 @@ BOOL LLFloaterModelWizard::postBuild()
 	mModelPreview->setPreviewTarget(16.f);
 	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelWizard::setDetails, this, _1, _2, _3, _4, _5));
 	mModelPreview->setModelLoadedCallback(boost::bind(&LLFloaterModelWizard::modelLoadedCallback, this));
+	mModelPreview->mViewOption["show_textures"] = true;
 
 	center();
 
diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h
index 50e4ab1a96ae48cf29b0a2f3766b8986db282cac..b166d262957cda56ea19b470ccef545516e5fbd1 100644
--- a/indra/newview/llfloatermodelwizard.h
+++ b/indra/newview/llfloatermodelwizard.h
@@ -80,6 +80,7 @@ class LLFloaterModelWizard : public LLFloater
 		CHOOSE_FILE = 0,
 		OPTIMIZE,
 		PHYSICS,
+		PHYSICS2,
 		REVIEW,
 		UPLOAD
 	};
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 257970aaaf7d700b38d1687bc7d4f887a8a8cec5..73c1f99fa04df5f167f70e598e2440589fd596a8 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -787,7 +787,9 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
 		getChildView("Strength:")->setVisible( land_visible);
 	}
 
-	bool show_mesh_cost = !gAgent.getRegion()->getCapability("GetMesh").empty() && gSavedSettings.getBOOL("MeshEnabled");
+	bool show_mesh_cost = gAgent.getRegion() && 
+		                  !gAgent.getRegion()->getCapability("GetMesh").empty() && 
+						  gSavedSettings.getBOOL("MeshEnabled");
 
 	getChildView("obj_count")->setVisible( !land_visible && !show_mesh_cost);
 	getChildView("prim_count")->setVisible( !land_visible && !show_mesh_cost);
diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp
index 2aaf403d5f76348bcf4fcf37af4a2013c14e4a66..19f6038b56b6f434bd0d33765d0ada3ed7955e83 100644
--- a/indra/newview/llfloatertopobjects.cpp
+++ b/indra/newview/llfloatertopobjects.cpp
@@ -185,7 +185,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
 			have_extended_data = true;
 			msg->getU32("DataExtended", "TimeStamp", time_stamp, block);
 			msg->getF32("DataExtended", "MonoScore", mono_score, block);
-			msg->getS32(_PREHASH_ReportData,"PublicURLs",public_urls,block);
+			msg->getS32("DataExtended", "PublicURLs", public_urls, block);
 		}
 
 		LLSD element;
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 11b3379814a52d3de44e343675abd7196417e5e9..0d8601410a1413677a645d24a3143315722f41d0 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -1037,18 +1037,29 @@ void LLFloaterUIPreview::onClickEditFloater()
 			cmd_override = bin + " " + args;
 		}
 	}
-	if (!mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override))
+
+	LLExternalEditor::EErrorCode status = mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override);
+	if (status != LLExternalEditor::EC_SUCCESS)
 	{
-		std::string warning = "Select an editor by setting the environment variable LL_XUI_EDITOR "
-			"or the ExternalEditor setting or specifying its path in the \"Editor Path\" field.";
+		std::string warning;
+
+		if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error.
+		{
+			warning = getString("ExternalEditorNotSet");
+		}
+		else
+		{
+			warning = LLExternalEditor::getErrorMessage(status);
+		}
+
 		popupAndPrintWarning(warning);
 		return;
 	}
 
 	// Run the editor.
-	if (!mExternalEditor.run(file_path))
+	if (mExternalEditor.run(file_path) != LLExternalEditor::EC_SUCCESS)
 	{
-		popupAndPrintWarning("Failed to run editor");
+		popupAndPrintWarning(LLExternalEditor::getErrorMessage(status));
 		return;
 	}
 }
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 53835f0166ebed6a4cb51644243d84661d3f8527..4cf2e723ec6df3088ccbcc0bd737c98f6f1a81a6 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -631,6 +631,12 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item)
 		return mask;
 	}
 
+	// We're hiding mesh types
+	if (item->getType() == LLAssetType::AT_MESH)
+	{
+		return mask;
+	}
+
 	LLViewerInventoryItem* old_item = getItem(item->getUUID());
 	LLPointer<LLViewerInventoryItem> new_item;
 	if(old_item)
@@ -1272,6 +1278,12 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)
 	//llinfos << "LLInventoryModel::addCategory()" << llendl;
 	if(category)
 	{
+		// We aren't displaying the Meshes folder
+		if (category->mPreferredType == LLFolderType::FT_MESH)
+		{
+			return;
+		}
+
 		// try to localize default names first. See EXT-8319, EXT-7051.
 		category->localizeName();
 
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index a227627bc100fea4507be3d898e343466d8ed9fa..752e4c87442efc1439e809111e5a4f4ead46aa1a 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -28,7 +28,7 @@
 
 #include "apr_pools.h"
 #include "apr_dso.h"
-
+#include "llhttpstatuscodes.h"
 #include "llmeshrepository.h"
 
 #include "llagent.h"
@@ -108,19 +108,13 @@ U32 get_volume_memory_size(const LLVolume* volume)
 	return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces();
 }
 
-LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)
+void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, F32 scale = 1.f)
 {
-	LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0);
-	buff->allocateBuffer(mesh.mNumTriangles*3, 0, true);
-
-	LLStrider<LLVector3> pos;
-	LLStrider<LLVector3> norm;
+	res.mPositions.clear();
+	res.mNormals.clear();
 	
-	buff->getVertexStrider(pos);
-	buff->getNormalStrider(norm);
-
 	const F32* v = mesh.mVertexBase;
-	
+
 	if (mesh.mIndexType == LLCDMeshData::INT_16)
 	{
 		U16* idx = (U16*) mesh.mIndexBase;
@@ -139,13 +133,13 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)
 			LLVector3 n = (v1-v0)%(v2-v0);
 			n.normalize();
 
-			*pos++ = v0*scale;
-			*pos++ = v1*scale;
-			*pos++ = v2*scale;
+			res.mPositions.push_back(v0*scale);
+			res.mPositions.push_back(v1*scale);
+			res.mPositions.push_back(v2*scale);
 
-			*norm++ = n;
-			*norm++ = n;
-			*norm++ = n;			
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);			
 		}
 	}
 	else
@@ -166,17 +160,15 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)
 			LLVector3 n = (v1-v0)%(v2-v0);
 			n.normalize();
 
-			*(pos++) = v0*scale;
-			*(pos++) = v1*scale;
-			*(pos++) = v2*scale;
+			res.mPositions.push_back(v0*scale);
+			res.mPositions.push_back(v1*scale);
+			res.mPositions.push_back(v2*scale);
 
-			*(norm++) = n;
-			*(norm++) = n;
-			*(norm++) = n;			
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);			
 		}
 	}
-
-	return buff;
 }
 
 S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
@@ -291,17 +283,21 @@ class LLMeshCostResponder : public LLCurl::Responder
 		}
 		else
 		{
-			llwarns << status << ": " << reason << llendl;
-			llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
+			llwarns << status << ": " << reason << llendl;			
 			
-			if (status == 499)
+			if (status == HTTP_INTERNAL_ERROR)
 			{
+				llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
 				mThread->uploadModel(mData);
 			}
-			else if (status == 400)
+			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;
@@ -1107,66 +1103,9 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
 	}
 	
 	{
-		LLMeshSkinInfo info;
+		LLMeshSkinInfo info(skin);
 		info.mMeshID = mesh_id;
 
-		if (skin.has("joint_names"))
-		{
-			for (U32 i = 0; i < skin["joint_names"].size(); ++i)
-			{
-				info.mJointNames.push_back(skin["joint_names"][i]);
-			}
-		}
-
-		if (skin.has("inverse_bind_matrix"))
-		{
-			for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i)
-			{
-				LLMatrix4 mat;
-				for (U32 j = 0; j < 4; j++)
-				{
-					for (U32 k = 0; k < 4; k++)
-					{
-						mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal();
-					}
-				}
-
-				info.mInvBindMatrix.push_back(mat);
-			}
-		}
-
-		if (skin.has("bind_shape_matrix"))
-		{
-			for (U32 j = 0; j < 4; j++)
-			{
-				for (U32 k = 0; k < 4; k++)
-				{
-					info.mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal();
-				}
-			}
-		}
-
-		if (skin.has("alt_inverse_bind_matrix"))
-		{
-			for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i)
-			{
-				LLMatrix4 mat;
-				for (U32 j = 0; j < 4; j++)
-				{
-					for (U32 k = 0; k < 4; k++)
-					{
-						mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal();
-					}
-				}
-				
-				info.mAlternateBindMatrix.push_back(mat);
-			}
-		}
-
-		if (skin.has("pelvis_offset"))
-		{
-			info.mPelvisOffset = skin["pelvis_offset"].asReal();
-		}
 		//llinfos<<"info pelvis offset"<<info.mPelvisOffset<<llendl;
 		mSkinInfoQ.push(info);
 	}
@@ -1179,7 +1118,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3
 	LLSD decomp;
 
 	if (data_size > 0)
-	{
+	{ 
 		std::string res_str((char*) data, data_size);
 
 		std::istringstream stream(res_str);
@@ -1192,119 +1131,8 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3
 	}
 	
 	{
-		LLMeshDecomposition* d = new LLMeshDecomposition();
+		LLModel::Decomposition* d = new LLModel::Decomposition(decomp);
 		d->mMeshID = mesh_id;
-
-		if (decomp.has("HullList"))
-		{
-			// updated for const-correctness. gcc is picky about this type of thing - Nyx
-			const LLSD::Binary& hulls = decomp["HullList"].asBinary();
-			const LLSD::Binary& position = decomp["Position"].asBinary();
-
-			U16* p = (U16*) &position[0];
-
-			d->mHull.resize(hulls.size());
-
-			LLVector3 min;
-			LLVector3 max;
-			LLVector3 range;
-
-			min.setValue(decomp["Min"]);
-			max.setValue(decomp["Max"]);
-			range = max-min;
-
-			for (U32 i = 0; i < hulls.size(); ++i)
-			{
-				U16 count = (hulls[i] == 0) ? 256 : hulls[i];
-				
-				for (U32 j = 0; j < count; ++j)
-				{
-					d->mHull[i].push_back(LLVector3(
-						(F32) p[0]/65535.f*range.mV[0]+min.mV[0],
-						(F32) p[1]/65535.f*range.mV[1]+min.mV[1],
-						(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
-					p += 3;
-				}		 
-
-			}
-				
-			//get mesh for decomposition
-			for (U32 i = 0; i < d->mHull.size(); ++i)
-			{
-				LLCDHull hull;
-				hull.mNumVertices = d->mHull[i].size();
-				hull.mVertexBase = d->mHull[i][0].mV;
-				hull.mVertexStrideBytes = 12;
-
-				LLCDMeshData mesh;
-				LLCDResult res = LLCD_OK;
-				if (LLConvexDecomposition::getInstance() != NULL)
-				{
-					res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
-				}
-				if (res != LLCD_OK)
-				{
-					llwarns << "could not get mesh from hull from convex decomposition lib." << llendl;
-					return false;
-				}
-
-
-				d->mMesh.push_back(get_vertex_buffer_from_mesh(mesh));
-			}	
-		}
-
-		if (decomp.has("Hull"))
-		{
-			const LLSD::Binary& position = decomp["Hull"].asBinary();
-
-			U16* p = (U16*) &position[0];
-
-			LLVector3 min;
-			LLVector3 max;
-			LLVector3 range;
-
-			min.setValue(decomp["Min"]);
-			max.setValue(decomp["Max"]);
-			range = max-min;
-
-			U16 count = position.size()/6;
-			
-			for (U32 j = 0; j < count; ++j)
-			{
-				d->mBaseHull.push_back(LLVector3(
-					(F32) p[0]/65535.f*range.mV[0]+min.mV[0],
-					(F32) p[1]/65535.f*range.mV[1]+min.mV[1],
-					(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
-				p += 3;
-			}		 
-				
-			//get mesh for decomposition
-			LLCDHull hull;
-			hull.mNumVertices = d->mBaseHull.size();
-			hull.mVertexBase = d->mBaseHull[0].mV;
-			hull.mVertexStrideBytes = 12;
-
-			LLCDMeshData mesh;
-			LLCDResult res = LLCD_OK;
-			if (LLConvexDecomposition::getInstance() != NULL)
-			{
-				res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
-			}
-			if (res != LLCD_OK)
-			{
-				llwarns << "could not get mesh from hull from convex decomposition lib." << llendl;
-				return false;
-			}
-
-			d->mBaseHullMesh = get_vertex_buffer_from_mesh(mesh);
-		}
-		else
-		{
-			//empty vertex buffer to indicate decomposition has been fetched
-			//but contains no base hull
-			d->mBaseHullMesh = new LLVertexBuffer(0, 0);
-		}
-
 		mDecompositionQ.push(d);
 	}
 
@@ -1315,12 +1143,12 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32
 {
 	LLSD physics_shape;
 
-	LLMeshDecomposition* d = new LLMeshDecomposition();
+	LLModel::Decomposition* d = new LLModel::Decomposition();
 	d->mMeshID = mesh_id;
 
 	if (data == NULL)
 	{ //no data, no physics shape exists
-		d->mPhysicsShapeMesh = new LLVertexBuffer(0,0);
+		d->mPhysicsShapeMesh.clear();
 	}
 	else
 	{
@@ -1344,33 +1172,22 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32
 				index_count += face.mNumIndices;
 			}
 
-			d->mPhysicsShapeMesh = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
-
-			d->mPhysicsShapeMesh->allocateBuffer(vertex_count, index_count, true);
-
-			LLStrider<LLVector3> pos;
-			LLStrider<U16> idx;
+			d->mPhysicsShapeMesh.clear();
 
-			d->mPhysicsShapeMesh->getVertexStrider(pos);
-			d->mPhysicsShapeMesh->getIndexStrider(idx);
+			std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions;
+			std::vector<LLVector3>& norm = d->mPhysicsShapeMesh.mNormals;
 
-			S32 idx_offset = 0;
 			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 			{
 				const LLVolumeFace& face = volume->getVolumeFace(i);
-				if (idx_offset + face.mNumIndices > 65535)
-				{ //avoid 16-bit index overflow
-					continue;
-				}
-
-				LLVector4a::memcpyNonAliased16(pos[idx_offset].mV, face.mPositions[0].getF32ptr(), face.mNumVertices*sizeof(LLVector4a));
 			
 				for (S32 i = 0; i < face.mNumIndices; ++i)
 				{
-					*idx++ = face.mIndices[i] + idx_offset;
-				}
+					U16 idx = face.mIndices[i];
 
-				idx_offset += face.mNumVertices;
+					pos.push_back(LLVector3(face.mPositions[idx].getF32ptr()));
+					norm.push_back(LLVector3(face.mNormals[idx].getF32ptr()));				
+				}			
 			}
 		}
 	}
@@ -1381,7 +1198,8 @@ 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)
-: LLThread("mesh upload")
+: LLThread("mesh upload"),
+	mDiscarded(FALSE)
 {
 	mInstanceList = data;
 	mUploadTextures = upload_textures;
@@ -1475,8 +1293,26 @@ void LLMeshUploadThread::preStart()
 	}
 }
 
+void LLMeshUploadThread::discard()
+{
+	LLMutexLock lock(mMutex) ;
+	mDiscarded = TRUE ;
+}
+
+BOOL LLMeshUploadThread::isDiscarded()
+{
+	LLMutexLock lock(mMutex) ;
+	return mDiscarded ;
+}
+
 void LLMeshUploadThread::run()
 {
+	if(isDiscarded())
+	{
+		mFinished = true;
+		return ;
+	}
+	
 	mCurlRequest = new LLCurlRequest();	
 
 	std::set<LLViewerTexture* > textures;
@@ -1605,7 +1441,7 @@ void LLMeshUploadThread::run()
 	
 		tcount = llmin(count+PUSH_PER_PROCESS, 100);
 
-		while (!mInstanceQ.empty() && count < tcount)
+		while (!mInstanceQ.empty() && count < tcount && !isDiscarded())
 		{ //create any objects waiting for upload
 			count++;
 			object_asset["objects"].append(createObject(mInstanceQ.front()));
@@ -1614,7 +1450,7 @@ void LLMeshUploadThread::run()
 			
 		mCurlRequest->process();
 			
-		done = mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty();
+		done = isDiscarded() || (mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty());
 	}
 	while (!done || mCurlRequest->getQueued() > 0);
 
@@ -1629,7 +1465,10 @@ void LLMeshUploadThread::run()
 		object_asset["permissions"] = object_asset["objects"][0]["permissions"];
 	}
 
-	LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder());
+	if(!isDiscarded())
+	{
+		LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder());
+	}
 
 	mFinished = true;
 }
@@ -2132,6 +1971,12 @@ void LLMeshRepository::shutdown()
 {
 	llinfos << "Shutting down mesh repository." << llendl;
 
+	for (U32 i = 0; i < mUploads.size(); ++i)
+	{
+		llinfos << "Discard the pending mesh uploads " << llendl;
+		mUploads[i]->discard() ; //discard the uploading requests.
+	}
+
 	mThread->mSignal->signal();
 	
 	while (!mThread->isStopped())
@@ -2453,33 +2298,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
 	mLoadingSkins.erase(info.mMeshID);
 }
 
-void LLMeshDecomposition::merge(const LLMeshDecomposition* rhs)
-{
-	if (!rhs)
-	{
-		return;
-	}
-
-	if (mMeshID != rhs->mMeshID)
-	{
-		llerrs << "Attempted to merge with decomposition of some other mesh." << llendl;
-	}
-
-	if (mBaseHull.empty())
-	{ //take base hull and decomposition from rhs
-		mHull = rhs->mHull;
-		mBaseHull = rhs->mBaseHull;
-		mMesh = rhs->mMesh;
-		mBaseHullMesh = rhs->mBaseHullMesh;
-	}
-
-	if (mPhysicsShapeMesh.isNull())
-	{ //take physics shape mesh from rhs
-		mPhysicsShapeMesh = rhs->mPhysicsShapeMesh;
-	}
-}
-
-void LLMeshRepository::notifyDecompositionReceived(LLMeshDecomposition* decomp)
+void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp)
 {
 	decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID);
 	if (iter == mDecompositionMap.end())
@@ -2621,7 +2440,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 {
 	if (mesh_id.notNull())
 	{
-		LLMeshDecomposition* decomp = NULL;
+		LLModel::Decomposition* decomp = NULL;
 		decomposition_map::iterator iter = mDecompositionMap.find(mesh_id);
 		if (iter != mDecompositionMap.end())
 		{
@@ -2629,7 +2448,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 		}
 		
 		//decomposition block hasn't been fetched yet
-		if (!decomp || decomp->mPhysicsShapeMesh.isNull())
+		if (!decomp || decomp->mPhysicsShapeMesh.empty())
 		{
 			LLMutexLock lock(mMeshMutex);
 			//add volume to list of loading meshes
@@ -2644,9 +2463,9 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 
 }
 
-const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
+LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
 {
-	LLMeshDecomposition* ret = NULL;
+	LLModel::Decomposition* ret = NULL;
 
 	if (mesh_id.notNull())
 	{
@@ -2657,7 +2476,7 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh
 		}
 		
 		//decomposition block hasn't been fetched yet
-		if (!ret || ret->mBaseHullMesh.isNull())
+		if (!ret || ret->mBaseHullMesh.empty())
 		{
 			LLMutexLock lock(mMeshMutex);
 			//add volume to list of loading meshes
@@ -2750,13 +2569,18 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)
 
 void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)
 {
+	if(isDiscarded())
+	{
+		return ;
+	}
+
 	//write model file to memory buffer
 	std::stringstream ostr;
 
 	LLModel::convex_hull_decomposition& decomp =
 		data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
-		data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : 
-		data.mBaseModel->mConvexHullDecomp;
+		data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
+		data.mBaseModel->mPhysics.mHull;
 
 	LLModel::hull dummy_hull;
 
@@ -2808,6 +2632,11 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)
 
 void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data)
 {
+	if(isDiscarded())
+	{
+		return ;
+	}
+
 	if (data.mTexture && data.mTexture->getDiscardLevel() >= 0)
 	{
 		LLSD asset_resources = LLSD::emptyMap();
@@ -2840,14 +2669,19 @@ void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data)
 
 void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)
 {
+	if(isDiscarded())
+	{
+		return ;
+	}
+
 	if (!data.mRSVP.empty())
 	{
 		std::stringstream ostr;
 
 		LLModel::convex_hull_decomposition& decomp =
 			data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
-			data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : 
-			data.mBaseModel->mConvexHullDecomp;
+			data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
+			data.mBaseModel->mPhysics.mHull;
 
 		LLModel::writeModel(
 			ostr,  
@@ -2872,6 +2706,11 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)
 
 void LLMeshUploadThread::doUploadTexture(LLTextureUploadData& data)
 {
+	if(isDiscarded())
+	{
+		return ;
+	}
+
 	if (!data.mRSVP.empty())
 	{
 		std::stringstream ostr;
@@ -3360,7 +3199,7 @@ void LLPhysicsDecomp::doDecomposition()
 			// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
 			LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh);
 
-			mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh);
+			get_vertex_buffer_from_mesh(mesh, mCurRequest->mHullMesh[i]);
 			
 			mMutex->lock();
 			mCurRequest->mHull[i] = p;
@@ -3633,3 +3472,46 @@ LLSD LLImportMaterial::asLLSD()
 	
 	return ret;
 }
+
+void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)
+{
+	decomp.mMesh.resize(decomp.mHull.size());
+
+	for (U32 i = 0; i < decomp.mHull.size(); ++i)
+	{
+		LLCDHull hull;
+		hull.mNumVertices = decomp.mHull[i].size();
+		hull.mVertexBase = decomp.mHull[i][0].mV;
+		hull.mVertexStrideBytes = 12;
+
+		LLCDMeshData mesh;
+		LLCDResult res = LLCD_OK;
+		if (LLConvexDecomposition::getInstance() != NULL)
+		{
+			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
+		}
+		if (res == LLCD_OK)
+		{
+			get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]);
+		}
+	}
+
+	if (!decomp.mBaseHull.empty() && decomp.mBaseHullMesh.empty())
+	{ //get mesh for base hull
+		LLCDHull hull;
+		hull.mNumVertices = decomp.mBaseHull.size();
+		hull.mVertexBase = decomp.mBaseHull[0].mV;
+		hull.mVertexStrideBytes = 12;
+
+		LLCDMeshData mesh;
+		LLCDResult res = LLCD_OK;
+		if (LLConvexDecomposition::getInstance() != NULL)
+		{
+			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
+		}
+		if (res == LLCD_OK)
+		{
+			get_vertex_buffer_from_mesh(mesh, decomp.mBaseHullMesh);
+		}
+	}
+}
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index f0c0f308d5f931d3c305be4bcf88fdc3be969136..31c2049c323128e901ca734408747fd00f0bf10d 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -132,34 +132,6 @@ class LLModelInstance
 	LLSD asLLSD();
 };
 
-class LLMeshSkinInfo 
-{
-public:
-	LLUUID mMeshID;
-	std::vector<std::string> mJointNames;
-	std::vector<LLMatrix4> mInvBindMatrix;
-	std::vector<LLMatrix4> mAlternateBindMatrix;
-	
-	LLMatrix4 mBindShapeMatrix;
-	float mPelvisOffset;
-};
-
-class LLMeshDecomposition
-{
-public:
-	LLMeshDecomposition() { }
-
-	void merge(const LLMeshDecomposition* rhs);
-
-	LLUUID mMeshID;
-	LLModel::convex_hull_decomposition mHull;
-	LLModel::hull mBaseHull;
-
-	std::vector<LLPointer<LLVertexBuffer> > mMesh;
-	LLPointer<LLVertexBuffer> mBaseHullMesh;
-	LLPointer<LLVertexBuffer> mPhysicsShapeMesh;
-};
-
 class LLPhysicsDecomp : public LLThread
 {
 public:
@@ -178,7 +150,7 @@ class LLPhysicsDecomp : public LLThread
 				
 		//output state
 		std::string mStatusMessage;
-		std::vector<LLPointer<LLVertexBuffer> > mHullMesh;
+		std::vector<LLModel::PhysicsMesh> mHullMesh;
 		LLModel::convex_hull_decomposition mHull;
 		
 		//status message callback, called from decomposition thread
@@ -313,7 +285,7 @@ class LLMeshRepoThread : public LLThread
 	std::set<LLUUID> mPhysicsShapeRequests;
 
 	//queue of completed Decomposition info requests
-	std::queue<LLMeshDecomposition*> mDecompositionQ;
+	std::queue<LLModel::Decomposition*> mDecompositionQ;
 
 	//queue of requested headers
 	std::queue<HeaderRequest> mHeaderReqQ;
@@ -405,11 +377,12 @@ class LLMeshUploadThread : public LLThread
 	S32				mPendingConfirmations;
 	S32				mPendingUploads;
 	S32				mPendingCost;
-	bool			mFinished;
 	LLVector3		mOrigin;
+	bool			mFinished;	
 	bool			mUploadTextures;
 	bool			mUploadSkin;
 	bool			mUploadJoints;
+	BOOL            mDiscarded ;
 
 	LLHost			mHost;
 	std::string		mUploadObjectAssetCapability;
@@ -445,7 +418,8 @@ class LLMeshUploadThread : public LLThread
 	bool finished() { return mFinished; }
 	virtual void run();
 	void preStart();
-	
+	void discard() ;
+	BOOL isDiscarded();
 };
 
 class LLMeshRepository
@@ -475,17 +449,19 @@ class LLMeshRepository
 	void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
 	void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
 	void notifySkinInfoReceived(LLMeshSkinInfo& info);
-	void notifyDecompositionReceived(LLMeshDecomposition* info);
+	void notifyDecompositionReceived(LLModel::Decomposition* info);
 
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
 	U32 calcResourceCost(LLSD& header);
 	U32 getResourceCost(const LLUUID& mesh_params);
 	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id);
-	const LLMeshDecomposition* getDecomposition(const LLUUID& mesh_id);
+	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
 	void fetchPhysicsShape(const LLUUID& mesh_id);
 	bool hasPhysicsShape(const LLUUID& mesh_id);
 	
 	void buildHull(const LLVolumeParams& params, S32 detail);
+	void buildPhysicsMesh(LLModel::Decomposition& decomp);
+
 	const LLSD& getMeshHeader(const LLUUID& mesh_id);
 
 	void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
@@ -499,7 +475,7 @@ class LLMeshRepository
 	typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
 	skin_map mSkinMap;
 
-	typedef std::map<LLUUID, LLMeshDecomposition*> decomposition_map;
+	typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
 	decomposition_map mDecompositionMap;
 
 	LLMutex*					mMeshMutex;
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index de5439e4e03e5a88002a454a74e790cd503548db..0d9daeb44ead9302fbb14c5b818ec880ab4ee8ae 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -558,6 +558,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 	}
 	*/
 
+	// Add a nearby chat toast.
 	LLUUID id;
 	id.generate();
 
@@ -583,6 +584,10 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 		notification["text_color"] = r_color_name;
 		notification["color_alpha"] = r_color_alpha;
 		notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ;
+
+		// Pass sender info so that it can be rendered properly (STORM-1021).
+		notification["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args);
+
 		channel->addNotification(notification);	
 	}
 
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 0300ea0c928e276d75bbd63b9b1d7796cbcbe198..05e185dcfd4082293bc89ccdfcda4dbe46c1c904 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -1140,6 +1140,8 @@ void LLPanelObject::getState( )
 
 	if (selected_item == MI_SCULPT)
 	{
+
+
         LLUUID id;
 		LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 
@@ -1169,10 +1171,12 @@ void LLPanelObject::getState( )
 			BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
 			isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH);
 			
+			mComboBaseType->setEnabled(!isMesh);
+			
 			if (mCtrlSculptType)
 			{
 				mCtrlSculptType->setCurrentByIndex(sculpt_stitching);
-				mCtrlSculptType->setEnabled(editable);
+				mCtrlSculptType->setEnabled(editable && !isMesh);
 			}
 
 			if (mCtrlSculptMirror)
@@ -1924,6 +1928,7 @@ void LLPanelObject::refresh()
 	}
 	
 	bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && 
+					   gAgent.getRegion() &&
 					   !gAgent.getRegion()->getCapability("GetMesh").empty();
 
 	getChildView("label physicsshapetype")->setVisible(enable_mesh);
@@ -1940,15 +1945,14 @@ void LLPanelObject::refresh()
 	getChild<LLSpinCtrl>("Scale Y")->setMaxValue(max_scale);
 	getChild<LLSpinCtrl>("Scale Z")->setMaxValue(max_scale);
 
-	LLComboBox* sculpt_combo = getChild<LLComboBox>("sculpt type control");
-	BOOL found = sculpt_combo->itemExists("Mesh");
+	BOOL found = mCtrlSculptType->itemExists("Mesh");
 	if (enable_mesh && !found)
 	{
-		sculpt_combo->add("Mesh");
+		mCtrlSculptType->add("Mesh");
 	}
 	else if (!enable_mesh && found)
 	{
-		sculpt_combo->remove("Mesh");
+		mCtrlSculptType->remove("Mesh");
 	}
 }
 
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 22ff362b5a66d5c2c3869e78a7614ff7d1ed45e2..b19bf5d234c36544e12aee92ac14709ccc038add 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -956,16 +956,31 @@ void LLScriptEdCore::openInExternalEditor()
 	// Open it in external editor.
 	{
 		LLExternalEditor ed;
+		LLExternalEditor::EErrorCode status;
+		std::string msg;
 
-		if (!ed.setCommand("LL_SCRIPT_EDITOR"))
+		status = ed.setCommand("LL_SCRIPT_EDITOR");
+		if (status != LLExternalEditor::EC_SUCCESS)
 		{
-			std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR "
-				"or the ExternalEditor setting"; // *TODO: localize
+			if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error.
+			{
+				msg = getString("external_editor_not_set");
+			}
+			else
+			{
+				msg = LLExternalEditor::getErrorMessage(status);
+			}
+
 			LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
 			return;
 		}
 
-		ed.run(filename);
+		status = ed.run(filename);
+		if (status != LLExternalEditor::EC_SUCCESS)
+		{
+			msg = LLExternalEditor::getErrorMessage(status);
+			LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
+		}
 	}
 }
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 5e7af6bbb3e08547fe08c65890b8f308e69903d6..65f7d299bc92d5b7e5b01f65365fd31e809fd113 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2961,31 +2961,21 @@ S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& sca
 void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
 {
 	LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
-	const LLMeshDecomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+	LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
 
 	const LLVector3 center(0,0,0);
 	const LLVector3 size(0.25f,0.25f,0.25f);
 
 	if (decomp)
 	{		
-		LLVertexBuffer* buff = decomp->mBaseHullMesh;
-
-		if (buff && buff->getNumVerts() > 0)
+		if (!decomp->mBaseHullMesh.empty())
 		{
-			buff->setBuffer(data_mask);
-
-		/*	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-			glColor4fv(line_color.mV);
-			buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);*/
-
-			{
-				glColor4fv(color.mV);
-				buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-			}
+			glColor4fv(color.mV);
+			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
 		}
 		else
 		{
+			gMeshRepo.buildPhysicsMesh(*decomp);
 			gGL.color3f(0,1,1);
 			drawBoxOutline(center, size);
 		}
@@ -2998,19 +2988,16 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 	}
 }
 
-void render_hull(LLVertexBuffer* buff, U32 data_mask, const LLColor4& color, const LLColor4& line_color)
+void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
 {
-	buff->setBuffer(data_mask);
-
 	glColor4fv(color.mV);
-	buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
 	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 	glPolygonOffset(3.f, 3.f);
 	glLineWidth(3.f);
 	glColor4fv(line_color.mV);
-	buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
 	glLineWidth(1.f);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
@@ -3075,7 +3062,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
 	{
 		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
-		const LLMeshDecomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+		LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
 			
 		if (decomp)
 		{ //render a physics based mesh
@@ -3084,27 +3071,33 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 
 			if (!decomp->mHull.empty())
 			{ //decomposition exists, use that
-				for (U32 i = 0; i < decomp->mHull.size(); ++i)
+
+				if (decomp->mMesh.empty())
+				{
+					gMeshRepo.buildPhysicsMesh(*decomp);
+				}
+
+				for (U32 i = 0; i < decomp->mMesh.size(); ++i)
 				{		
-					render_hull(decomp->mMesh[i], data_mask, color, line_color);
+					render_hull(decomp->mMesh[i], color, line_color);
 				}
 			}
-			else if (decomp->mPhysicsShapeMesh.notNull() && decomp->mPhysicsShapeMesh->getNumVerts() > 0)
+			else if (!decomp->mPhysicsShapeMesh.empty())
 			{ 
 				//decomp has physics mesh, render that mesh
 				glColor4fv(color.mV);
-				pushBufferVerts(decomp->mPhysicsShapeMesh, data_mask);
-				
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+								
 				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 				glColor4fv(line_color.mV);
-				pushBufferVerts(decomp->mPhysicsShapeMesh, data_mask);
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
 				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 			}
 			else
 			{ //no mesh or decomposition, render base hull
 				renderMeshBaseHull(volume, data_mask, color, line_color);
 
-				if (decomp->mPhysicsShapeMesh.isNull())
+				if (decomp->mPhysicsShapeMesh.empty())
 				{
 					//attempt to fetch physics shape mesh if available
 					gMeshRepo.fetchPhysicsShape(mesh_id);
diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp
index 0af850a46b015b2de2e60d9c2cb4d7328e0a101a..286b16bab2ede0749a22b2ffbc91f679fd0c5856 100644
--- a/indra/newview/llviewerchat.cpp
+++ b/indra/newview/llviewerchat.cpp
@@ -31,6 +31,8 @@
 #include "llagent.h" 	// gAgent		
 #include "lluicolortable.h"
 #include "llviewercontrol.h" // gSavedSettings
+#include "llviewerregion.h"
+#include "llworld.h"
 #include "llinstantmessage.h" //SYSTEM_FROM
 
 // LLViewerChat
@@ -214,3 +216,43 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg)
 
 }
 
+//static
+std::string LLViewerChat::getSenderSLURL(const LLChat& chat, const LLSD& args)
+{
+	switch (chat.mSourceType)
+	{
+	case CHAT_SOURCE_AGENT:
+		return LLSLURL("agent", chat.mFromID, "about").getSLURLString();
+
+	case CHAT_SOURCE_OBJECT:
+		return getObjectImSLURL(chat, args);
+
+	default:
+		llwarns << "Getting SLURL for an unsupported sender type: " << chat.mSourceType << llendl;
+	}
+
+	return LLStringUtil::null;
+}
+
+//static
+std::string LLViewerChat::getObjectImSLURL(const LLChat& chat, const LLSD& args)
+{
+	std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString();
+	url += "?name=" + chat.mFromName;
+	url += "&owner=" + chat.mOwnerID.asString();
+
+	std::string slurl = args["slurl"].asString();
+	if (slurl.empty())
+	{
+		LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+		if(region)
+		{
+			LLSLURL region_slurl(region->getName(), chat.mPosAgent);
+			slurl = region_slurl.getLocationString();
+		}
+	}
+
+	url += "&slurl=" + LLURI::escape(slurl);
+
+	return url;
+}
diff --git a/indra/newview/llviewerchat.h b/indra/newview/llviewerchat.h
index a9f9a98960f06b60cc7c07d7ae390bbca65b83d4..0f15d29f04ec3a0a8f884d328d4b9cd78b3193dc 100644
--- a/indra/newview/llviewerchat.h
+++ b/indra/newview/llviewerchat.h
@@ -40,6 +40,10 @@ class LLViewerChat
 	static LLFontGL* getChatFont();
 	static S32 getChatFontSize();
 	static void formatChatMsg(const LLChat& chat, std::string& formated_msg);
+	static std::string getSenderSLURL(const LLChat& chat, const LLSD& args);
+
+private:
+	static std::string getObjectImSLURL(const LLChat& chat, const LLSD& args);
 
 };
 
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 5f0e4bcded0842a16a4c4b03581bc6bc590f7aeb..71706f0146669571b7b082caff2ff8fd5356d28e 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -762,6 +762,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mPelvisOffset = LLVector3(0.0f,0.0f,0.0f);
 	mLastPelvisToFoot = 0.0f;
 	mPelvisFixup = 0.0f;
+	mLastPelvisFixup = 0.0f;
 }
 
 //------------------------------------------------------------------------
@@ -1333,7 +1334,17 @@ const LLVector3 LLVOAvatar::getRenderPosition() const
 	}
 	else if (isRoot())
 	{
-		return mDrawable->getPositionAgent();
+		if ( !mHasPelvisOffset )
+		{
+			return mDrawable->getPositionAgent();
+		}
+		else
+		{
+			//Apply a pelvis fixup (as defined by the avs skin)
+			LLVector3 pos = mDrawable->getPositionAgent();
+			pos[VZ] += mPelvisFixup;
+			return pos;
+		}
 	}
 	else
 	{
@@ -3795,6 +3806,7 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,
 		//Store off last pelvis to foot value
 		mLastPelvisToFoot = mPelvisToFoot;
 		mPelvisOffset	  = offsetAmount;
+		mLastPelvisFixup  = mPelvisFixup;
 		mPelvisFixup	  = pelvisFixup;
 	}
 }
@@ -3810,6 +3822,15 @@ void LLVOAvatar::postPelvisSetRecalc( void )
 	updateHeadOffset();
 }
 //------------------------------------------------------------------------
+// pelisPoke
+//------------------------------------------------------------------------
+void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount )
+{	
+	mHasPelvisOffset  = true;
+	mLastPelvisFixup  = mPelvisFixup;	
+	mPelvisFixup	  = pelvisFixupAmount;	
+}
+//------------------------------------------------------------------------
 // updateVisibility()
 //------------------------------------------------------------------------
 void LLVOAvatar::updateVisibility()
@@ -4947,6 +4968,7 @@ void LLVOAvatar::resetJointPositions( void )
 		mSkeleton[i].setId( LLUUID::null );
 	}
 	mHasPelvisOffset = false;
+	mPelvisFixup	 = mLastPelvisFixup;
 }
 //-----------------------------------------------------------------------------
 // resetSpecificJointPosition
@@ -5006,6 +5028,7 @@ void LLVOAvatar::resetJointPositionsToDefault( void )
 	}
 	//make sure we don't apply the joint offset
 	mHasPelvisOffset = false;
+	mPelvisFixup	 = mLastPelvisFixup;
 	postPelvisSetRecalc();
 }
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 7209b9f1e5a330f0524f17861e6adacc104c805e..edec1b480aa8fadcc40a72f82900854607e85e73 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -295,11 +295,13 @@ class LLVOAvatar :
 	void				setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ;
 	bool				hasPelvisOffset( void ) { return mHasPelvisOffset; }
 	void				postPelvisSetRecalc( void );
+	void				setPelvisOffset( F32 pelvixFixupAmount );
 
 	bool				mHasPelvisOffset;
 	LLVector3			mPelvisOffset;
 	F32					mLastPelvisToFoot;
 	F32					mPelvisFixup;
+	F32					mLastPelvisFixup;
 
 	LLVector3			mHeadOffset; // current head position
 	LLViewerJoint		mRoot;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 43d8b9d356cce4d72d07a4259bb3e1cd2900ae65..98e5e4c6de1b5df17c73baeb7bb01457e5114ee2 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3941,7 +3941,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						if ( bindCnt > 0 )
 						{					
 							const int jointCnt = pSkinData->mJointNames.size();
-							const int pelvisZOffset = pSkinData->mPelvisOffset;
+							const F32 pelvisZOffset = pSkinData->mPelvisOffset;
 							bool fullRig = (jointCnt>=20) ? true : false;
 							if ( fullRig )
 							{
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 e79dfcbc7d3cc82969d5e87ea93e004b35d9cb87..0053be4f67514c0b4f1599407d7e49941b8798e2 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -390,10 +390,10 @@
       <check_box top_pad="5" left="20" name="upload_joints" height="15" follows="top|left" label="Joint positions"/>
 
       <text left="10" top_pad="4" width="90" bottom="30" follows="top|left" height="15">
-        Pelvis Offset:
+        Pelvis Z Offset:
       </text>
 
-      <spinner left="10" top_pad="4" height="20" follows="top|left" width="80" value="0.0" min_val="0.00" max_val="32.0" name="pelvis_offset"/>
+      <spinner left="10" top_pad="4" height="20" follows="top|left" width="80" value="0.0" min_val="-3.00" max_val="3.0" name="pelvis_offset"/>
 
     </panel>
   </tab_container>
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 f133d75eeee7e2090ca575a2e1e24989ddf178fb..93740007eeecba29a3a76416c323304372b3fc60 100644
--- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml
@@ -5,10 +5,10 @@
  name="Model Wizard"
  help_topic="model_wizard"
  bg_opaque_image_overlay="0.5 0.5 0.5 1"
- height="475"
+ height="480"
  save_rect="true"
  title="UPLOAD MODEL WIZARD"
- width="530">
+ width="535">
 	<button
 	 top="32"
 	 tab_stop="false"
@@ -45,6 +45,24 @@
 		<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"
@@ -101,23 +119,24 @@
 		 height="388"
 		 top_pad="0"
 		 name="choose_file_panel"
-		 visible="true"
-		 width="530"
+		 visible="false"
+		 width="535"
 		 left="0">
 		<panel
-		 height="20"
-		 top_pad="20"
-		 width="500"
+		 height="22"
+		 top_pad="15"
+		 width="505"
 		 name="header_panel"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
 		 background_opaque="true"
-		 left="20">
+		 left="15">
 			<text
 			 width="200"
 			 left="10"
-			 top="2"
+			 top="3"
 			 name="header_text"
+			 text_color="White"
 			 height="10"
 			 font="SansSerifBig"
 			 layout="topleft">
@@ -132,14 +151,14 @@
 		 font="SansSerifSmall"
 		 layout="topleft"
 		 word_wrap="true"
-		 left_delta="0">
+		 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"
 		 left="15"
-		 height="245"
-		 width="500"
+		 height="270"
+		 width="505"
 		 name="content"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
@@ -272,23 +291,24 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		 height="388"
 		 top_delta="0"
 		 name="optimize_panel"
-		 visible="false"
-		 width="530"
+		 visible="true"
+		 width="535"
 		 left="0">
 		<panel
-		 height="20"
-		 top_pad="20"
+		 height="22"
+		 top_pad="15"
 		 name="header_panel"
-		 width="500"
+		 width="505"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
 		 background_opaque="true"
-		 left="20">
+		 left="15">
 			<text
 			 width="200"
 			 left="10"
 			 name="header_text"
-			 top="2"
+			 top="3"
+			 text_color="White"
 			 height="10"
 			 font="SansSerifBig"
 			 layout="topleft">
@@ -303,15 +323,15 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		 layout="topleft"
 		 name="description"
 		 word_wrap="true"
-		 left_delta="0">
-			This wizard is optimizing your model. This may take several minutes. To stop the process click the back button
+		 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.
 		</text>
 		<panel
 		 top_delta="40"
 		 visible="false"
 		 left="15"
-		 height="245"
-		 width="500"
+		 height="270"
+		 width="505"
 		 name="content"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
@@ -385,8 +405,8 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		<panel
 				 top_delta="0"
 				 left_delta="0"
-				 height="245"
-				 width="500"
+				 height="270"
+				 width="505"
 				 name="content2"
 				 bg_opaque_color="DkGray2"
 				 background_visible="true"
@@ -394,7 +414,7 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 			<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="-2"  follows="left|top" list_position="below" height="18"
+			<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
@@ -417,27 +437,27 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 				 highlight_light_color="0.09 0.09 0.09 1"
 				 border_style="line"
 				 border="true"
-				 height="175"
+				 height="185"
 				 follows="all"
-				 width="175">
+				 width="185">
 			</panel>
-			<text top="35" left="220" text_color="White" font="SansSerifSmallBold" width="300" height="4">Performance</text>
-			<text top="55" left="200" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text>
-			<text top="35" left="380" text_color="White" font="SansSerifSmallBold" width="300" height="4">Accuracy</text>
-			<text top="55" 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="45" left="224" text_color="White" font="SansSerifSmallBold" width="300" height="4">Performance</text>
+			<text top="65" 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="384" text_color="White" font="SansSerifSmallBold" width="300" height="4">Accuracy</text>
+			<text top="65" left="364" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text>
 
 			<slider
 		   follows="left|top"
 		   height="20"
 		   increment="1"
 		   layout="topleft"
-		   left="200"
+		   left="204"
 		   max_val="2"
 		   initial_value="1"
 		   min_val="0"
 		   name="accuracy_slider"
 		   show_text="false"
-		   top="105"
+		   top="120"
 		   width="290" />
 			<text 
 			font="SansSerifSmall" 
@@ -448,14 +468,14 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 
 
 			<icon
-				 top_pad="10"
+				 top_pad="14"
 				 left_delta="0"
 				 width="280"
 				 height="2"
 				 image_name="model_wizard\divider_line.png"/>
 	
-			<text top_delta="25" width="200" text_color="White" left_delta="50" name="streaming cost"  height="20">Resource Cost:    [COST]</text>
-			<text top_delta="25" width="100" text_color="White" left_delta="0"  height="20">Upload Fee:</text>
+			<text top_delta="20" width="200" text_color="White" left_delta="50" name="streaming cost"  height="20">Resource Cost:    [COST]</text>
+			<text top_delta="24" width="100" text_color="White" left_delta="0"  height="20">Upload Fee:</text>
 			<text
 						 top_pad="5"
 						 width="130"
@@ -504,51 +524,50 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		</panel>
 	</panel>
 
-
-
 	<panel
 		 height="388"
 		 top_delta="0"
 		 name="physics_panel"
 		 visible="false"
-		 width="530"
+		 width="535"
 		 left="0">
 		<panel
-		 height="20"
-		 top_pad="20"
+		 height="22"
+		 top_pad="15"
 		 name="header_panel"
-		 width="500"
+		 width="505"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
 		 background_opaque="true"
-		 left="20">
+		 left="15">
 			<text
 			 width="200"
 			 left="10"
 			 name="header_text"
-			 top="2"
+			 top="3"
 			 height="10"
 			 font="SansSerifBig"
+			 text_color="White" 
 			 layout="topleft">
 				Physics
 			</text>
 		</panel>
 		<text
-		 top_pad="14"
-		 width="460"
+		 top_pad="10"
+		 width="474"
 		 height="50"
 		 font="SansSerifSmall"
 		 layout="topleft"
 		 name="description"
 		 word_wrap="true"
-		 left_delta="0">
+		 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:
 		</text>
     <panel
-		 top_delta="40"
+		 top_delta="44"
 		 left="15"
-		 height="265"
-		 width="500"
+		 height="270"
+		 width="505"
 		 name="content"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
@@ -596,23 +615,152 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
     </panel>
 	</panel>
 
+	<panel
+		 height="388"
+		 top_delta="0"
+		 name="physics2_panel"
+		 visible="false"
+		 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:
+			</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">
+				<combo_item name="high">
+					High
+				</combo_item>
+				<combo_item name="medium">
+					Medium
+				</combo_item>
+				<combo_item name="lowest">
+					Lowest
+				</combo_item>
+				<combo_item name="low">
+					Low
+				</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="40" width="180" text_color="White" left="225" name="streaming cost"  height="20">Resource Cost:       [COST]</text>
+			<text top_delta="26" width="180" text_color="White" left_delta="0" name="physics cost"  height="20">Physics Cost:           [COST]</text>
+			<text top_delta="26" width="180" text_color="White" left_delta="0"  height="20">Upload Fee:</text>
+
+		</panel>
+	</panel>
 
 	<panel
 		 height="388"
 		 top_delta="0"
 		 name="review_panel"
 		 visible="false"
-		 width="530"
+		 width="535"
 		 left="0">
 		<panel
 		 height="22"
-		 top_pad="16"
+		 top_pad="15"
 		 name="header_panel"
-		 width="500"
+		 width="505"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
 		 background_opaque="true"
-		 left="20">
+		 left="15">
 			<text
 			 width="200"
 			 left="10"
@@ -627,13 +775,13 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		</panel>
 		<text
 		 top_pad="14"
-		 width="460"
+		 width="470"
 		 height="24"
 		 font="SansSerifSmall"
 		 layout="topleft"
 		 name="description"
 		 word_wrap="true"
-		 left_delta="10">
+		 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
@@ -645,8 +793,8 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
     <panel
 		 top_pad="5"
 		 left="15"
-		 height="245"
-		 width="500"
+		 height="270"
+		 width="505"
 		 name="content">
       <text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
         Model Preview:
@@ -791,22 +939,22 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		 top_delta="0"
 		 name="upload_panel"
 		 visible="false"
-		 width="530"
+		 width="535"
 		 left="0">
 		<panel
-		 height="20"
-		 top_pad="20"
+		 height="22"
+		 top_pad="15"
 		 name="header_panel"
-		 width="500"
+		 width="505"
 		 bg_opaque_color="DkGray2"
 		 background_visible="true"
 		 background_opaque="true"
-		 left="20">
+		 left="15">
 			<text
 			 width="200"
 			 left="10"
 			 name="header_text"
-			 top="2"
+			 top="3"
 			 text_color="White" 
 			 height="10"
 			 font="SansSerifBig"
@@ -816,13 +964,13 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se
 		</panel>
 		<text
 		 top_pad="14"
-		 width="460"
+		 width="474"
 		 height="20"
 		 font="SansSerifSmall"
 		 layout="topleft"
 		 name="description"
 		 word_wrap="true"
-		 left_delta="0">
+		 left_delta="5">
 			Congratulations! Your model has been sucessfully uploaded.  You will find the model in the Objects folder in your inventory.
 		</text>
 		<icon
diff --git a/indra/newview/skins/default/xui/en/floater_ui_preview.xml b/indra/newview/skins/default/xui/en/floater_ui_preview.xml
index 12c45617530885b9677f4c40f7920e35f816b5db..3921cfcd2c92ffff9e226d134457e9a36840df25 100644
--- a/indra/newview/skins/default/xui/en/floater_ui_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_ui_preview.xml
@@ -12,6 +12,10 @@
  title="XUI PREVIEW TOOL"
  translate="false"
  width="750">
+    <string name="ExternalEditorNotSet">
+Select an editor by setting the environment variable LL_XUI_EDITOR
+or the ExternalEditor setting
+or specifying its path in the "Editor Path" field.</string>
     <panel
      bottom="640"
      follows="left|top|right|bottom"
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
index 84e81397beb465b0df1b180f7cd845ab60decc93..b8128da358631e2885fae37b4ebd0d72ba49eb66 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
@@ -68,7 +68,7 @@ name="Stand Up">
      function="Self.EnableStandUp" />
   </menu_item_call>
   <menu_item_call
-  label="Change Outfit"
+  label="My Appearance"
   name="Change Outfit">
     <menu_item_call.on_click
      function="CustomizeAvatar" />
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
index 2afa29ec100e4fcc500d3500feef858c2d16ac17..d727294cc8ebf23ff96af095c4d55c65d982936e 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
@@ -193,7 +193,7 @@
         </menu_item_call>
     </context_menu>
      <menu_item_call
-     label="Change Outfit"
+     label="My Appearance"
      layout="topleft"
      name="Chenge Outfit">
         <menu_item_call.on_click
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index ea40a08c95283185e3b231fda09e573a464a8814..8c783ae218e6e3d9eb934c1f85c1b0dd207d814b 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -41,7 +41,7 @@
              parameter="agent" />
         </menu_item_call>
         <menu_item_call
-         label="Change Outfit"
+         label="My Appearance"
          name="ChangeOutfit">
             <menu_item_call.on_click
              function="CustomizeAvatar" />
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f703acaa66dd8477454199b8b402aef1240b8578..d9d3fab6d473844d0f4a5c76da3945202b0b96f8 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -819,22 +819,6 @@ You need to enter either the Username or both the First and Last name of your av
   </notification>
   
 
-  <notification
-   icon="alertmodal.tga"
-   name="AddClassified"
-   type="alertmodal">
-Classified ads appear in the &apos;Classified&apos; section of the Search directory and on [http://secondlife.com/community/classifieds secondlife.com] for one week.
-Fill out your ad, then click &apos;Publish...&apos; to add it to the directory.
-You&apos;ll be asked for a price to pay when clicking Publish.
-Paying more makes your ad appear higher in the list, and also appear higher when people search for keywords.
-    <tag>confirm</tag>
-    <usetemplate
-     ignoretext="How to create a new Classified ad"
-     name="okcancelignore"
-     notext="Cancel"
-     yestext="OK"/>
-  </notification>
-
   <notification
    icon="alertmodal.tga"
    name="DeleteClassified"
diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml
index 627b12cfe17a71f088ff2293474425d03207f7ca..8d420243864c56e4cda3fa1d0f53e2b7ad2e00d1 100644
--- a/indra/newview/skins/default/xui/en/panel_script_ed.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml
@@ -28,6 +28,10 @@
      name="Title">
         Script: [NAME]
     </panel.string>
+    <panel.string
+     name="external_editor_not_set">
+        Select an editor by setting the environment variable LL_SCRIPT_EDITOR or the ExternalEditor setting.
+    </panel.string>
     <menu_bar
      bg_visible="false"
      follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index b7bf2526ab31ef408ee60bb32867387f265827be..a39832bbc54d6b77f9ef054017c0f181731a8746 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3312,6 +3312,14 @@ Abuse Report</string>
   <string name="DeleteItem">Delete selected item?</string>
 
   <string name="EmptyOutfitText">There are no items in this outfit</string>
+ 
+ <!-- External editor status codes -->
+ <string name="ExternalEditorNotSet">Select an editor using the ExternalEditor setting.</string>
+ <string name="ExternalEditorNotFound">Cannot find the external editor you specified.
+Try enclosing path to the editor with double quotes.
+(e.g. "/path to my/editor" "%s")</string>
+ <string name="ExternalEditorCommandParseError">Error parsing the external editor command.</string>
+ <string name="ExternalEditorFailedToRun">External editor failed to run.</string>
 
   <!-- Key names begin -->
   <string name="Esc">Esc</string>
diff --git a/indra/newview/skins/minimal/xui/de/floater_media_browser.xml b/indra/newview/skins/minimal/xui/de/floater_media_browser.xml
new file mode 100644
index 0000000000000000000000000000000000000000..63cf4a6cba3ea65b1e9d3dbca26ed33ff7034c7f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/floater_media_browser.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_about" title="MEDIEN-BROWSER">
+	<floater.string name="home_page_url">
+		http://www.secondlife.com
+	</floater.string>
+	<floater.string name="support_page_url">
+		http://support.secondlife.com
+	</floater.string>
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button label="Zurück" name="back"/>
+			<button label="Vorwärts" name="forward"/>
+			<button label="Neu laden" name="reload"/>
+			<button label="Los" name="go"/>
+		</layout_panel>
+		<layout_panel name="time_controls">
+			<button label="zurück" name="rewind"/>
+			<button label="anhalten" name="stop"/>
+			<button label="vorwärts" name="seek"/>
+		</layout_panel>
+		<layout_panel name="parcel_owner_controls">
+			<button label="Aktuelle Seite an Parzelle senden" name="assign"/>
+		</layout_panel>
+		<layout_panel name="external_controls">
+			<button label="In meinem Browser öffnen" name="open_browser"/>
+			<check_box label="Immer in meinem Browser öffnen" name="open_always"/>
+			<button label="Schließen" name="close"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/de/floater_web_content.xml b/indra/newview/skins/minimal/xui/de/floater_web_content.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6ab119eeab2b9a54049181e2b9af2a198e87019d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Rückwärts"/>
+			<button name="forward" tool_tip="Vorwärts"/>
+			<button name="stop" tool_tip="Navigation stoppen"/>
+			<button name="reload" tool_tip="Seite neu laden"/>
+			<combo_box name="address" tool_tip="URL hier eingeben"/>
+			<icon name="media_secure_lock_flag" tool_tip="Sicheres Browsen"/>
+			<button name="popexternal" tool_tip="Aktuelle URL im Desktop-Browser öffnen"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
index 851a96cc0997e4407964b42670548c61bdfac843..443092319b5049a5ea9d7a905d202c58c4d95d31 100644
--- a/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
@@ -1,10 +1,8 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu name="Gear Menu">
-	<menu_item_call label="Hinsetzen" name="sit_down_here"/>
-	<menu_item_call label="Aufstehen" name="stand_up"/>
-	<menu_item_call label="Outfit ändern" name="change_outfit"/>
-	<menu_item_call label="Mein Profil" name="my_profile"/>
-	<menu_item_call label="Meine Freunde" name="my_friends"/>
-	<menu_item_call label="Meine Gruppen" name="my_groups"/>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="Self Pie">
+	<menu_item_call label="Hinsetzen" name="Sit Down Here"/>
+	<menu_item_call label="Aufstehen" name="Stand Up"/>
+	<menu_item_call label="Meine Freunde" name="Friends..."/>
+	<menu_item_call label="Mein Profil" name="Profile..."/>
 	<menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/notifications.xml b/indra/newview/skins/minimal/xui/de/notifications.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1eee1d1c9b867b93e19c6d9ef6b139706fdf3a93
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/notifications.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<notifications>
+	<notification name="UserGiveItem">
+		[NAME_SLURL] bietet Ihnen [ITEM_SLURL] an. Zur Verwendung dieses Artikels müssen Sie in den erweiterten Modus umschalten, wo Sie den Artikel in Ihrem Inventar finden werden. Um in den erweiterten Modus umzuschalten, beenden Sie die Anwendung, starten Sie sie neu und ändern Sie die Moduseinstellung auf dem Anmeldebildschirm.
+		<form name="form">
+			<button name="Show" text="Artikel behalten"/>
+			<button name="Discard" text="Artikel ablehnen"/>
+			<button name="Mute" text="Benutzer blockieren"/>
+		</form>
+	</notification>
+	<notification name="ObjectGiveItem">
+		Ein Objekt namens &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt;, das [NAME_SLURL] gehört, bietet Ihnen [ITEM_SLURL] an. Zur Verwendung dieses Artikels müssen Sie in den erweiterten Modus umschalten, wo Sie den Artikel in Ihrem Inventar finden werden. Um in den erweiterten Modus umzuschalten, beenden Sie die Anwendung, starten Sie sie neu und ändern Sie die Moduseinstellung auf dem Anmeldebildschirm.
+		<form name="form">
+			<button name="Keep" text="Artikel behalten"/>
+			<button name="Discard" text="Artikel ablehnen"/>
+			<button name="Mute" text="Objekt blockieren"/>
+		</form>
+	</notification>
+</notifications>
diff --git a/indra/newview/skins/minimal/xui/de/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/de/panel_bottomtray.xml
index ea7cccbdf8957fa0355a03cea7f3a6e2b92b676f..a4d80921ece5d14f326bb65fa99b6e2f7cf9ffd2 100644
--- a/indra/newview/skins/minimal/xui/de/panel_bottomtray.xml
+++ b/indra/newview/skins/minimal/xui/de/panel_bottomtray.xml
@@ -11,10 +11,10 @@
 			<bottomtray_button label="Ansicht" name="camera_btn" tool_tip="Kamerasteuerung anzeigen/ausblenden"/>
 		</layout_panel>
 		<layout_panel name="avatar_and_destinations_panel">
-			<radio_group name="avatar_and_destination_btns">
-				<radio_item name="destination_btn" value="0"/>
-				<radio_item name="avatar_btn" value="1"/>
-			</radio_group>
+			<bottomtray_button label="Ziele" name="destination_btn" tool_tip="Zeigt Leutefenster an"/>
+		</layout_panel>
+		<layout_panel name="avatar_and_destinations_panel">
+			<bottomtray_button label="Mein Avatar" name="avatar_btn"/>
 		</layout_panel>
 		<layout_panel name="people_panel">
 			<bottomtray_button label="Leute" name="show_people_button" tool_tip="Zeigt Leutefenster an"/>
diff --git a/indra/newview/skins/minimal/xui/de/panel_group_control_panel.xml b/indra/newview/skins/minimal/xui/de/panel_group_control_panel.xml
new file mode 100644
index 0000000000000000000000000000000000000000..81e6040f84174461f81c8aae0850f990e816e851
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_group_control_panel.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+	<layout_stack name="vertical_stack">
+		<layout_panel name="end_call_btn_panel">
+			<button label="Anruf beenden" name="end_call_btn"/>
+		</layout_panel>
+		<layout_panel name="voice_ctrls_btn_panel">
+			<button label="Voice-Steuerung öffnen" name="voice_ctrls_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/de/panel_login.xml b/indra/newview/skins/minimal/xui/de/panel_login.xml
index dff70d6994f2ca626c443bfba2efa3fe18dbfdfe..2e82453aab1efee11edeaddecf0b18fa23e09c66 100644
--- a/indra/newview/skins/minimal/xui/de/panel_login.xml
+++ b/indra/newview/skins/minimal/xui/de/panel_login.xml
@@ -20,8 +20,8 @@
 			<text name="mode_selection_text">
 				Modus:
 			</text>
-			<combo_box name="mode_combo">
-				<combo_box.item label="Einfach (Standard)" name="Basic"/>
+			<combo_box name="mode_combo" tool_tip="Wählen Sie den gewünschten Modus aus. Basis: schnelles, einfaches Erkunden und Chatten. Erweitert: Zugriff auf zusätzliche Funktionen.">
+				<combo_box.item label="Basis" name="Basic"/>
 				<combo_box.item label="Erweitert" name="Advanced"/>
 			</combo_box>
 		</layout_panel>
diff --git a/indra/newview/skins/minimal/xui/en/floater_help_browser.xml b/indra/newview/skins/minimal/xui/en/floater_help_browser.xml
index eddfe41c25627ff94e3e1431731e5fd13dfb6398..cc551f7d58448b75f4a0ce56a6d5604a9c273628 100644
--- a/indra/newview/skins/minimal/xui/en/floater_help_browser.xml
+++ b/indra/newview/skins/minimal/xui/en/floater_help_browser.xml
@@ -8,12 +8,12 @@
  min_height="360"
  left="645"
  top="10" 
- min_width="300"
+ min_width="345"
  name="floater_help_browser"
  save_rect="true"
  single_instance="true"
  title="HOW TO"
- width="300">
+ width="335">
     <floater.string
      name="loading_text">
         Loading...
@@ -29,14 +29,14 @@
      orientation="vertical" 
      name="stack1"
      top="20"
-     width="290">
+     width="325">
         <layout_panel
          layout="topleft"
          left_delta="0"
          top_delta="0"
          name="external_controls"
          user_resize="false"
-         width="280">
+         width="325">
             <web_browser
               trusted_content="true" 
              bottom="-5"
@@ -46,7 +46,7 @@
              name="browser"
              top="0"
              height="300"
-             width="280" />
+             width="325" />
         </layout_panel>
     </layout_stack>
 </floater>
diff --git a/indra/newview/skins/minimal/xui/es/floater_media_browser.xml b/indra/newview/skins/minimal/xui/es/floater_media_browser.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a7086c2d6d25108179bf931a724b7fc79749cb01
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/floater_media_browser.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_about" title="EXPLORADOR DE MEDIA">
+	<floater.string name="home_page_url">
+		http://www.secondlife.com
+	</floater.string>
+	<floater.string name="support_page_url">
+		http://support.secondlife.com
+	</floater.string>
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button label="Atrás" name="back"/>
+			<button label="Adelante" name="forward"/>
+			<button label="Recargar" name="reload"/>
+			<button label="Ir" name="go"/>
+		</layout_panel>
+		<layout_panel name="time_controls">
+			<button label="rebobinar" name="rewind"/>
+			<button label="parar" name="stop"/>
+			<button label="avanzar" name="seek"/>
+		</layout_panel>
+		<layout_panel name="parcel_owner_controls">
+			<button label="Enviar a la parcela la página actual" name="assign"/>
+		</layout_panel>
+		<layout_panel name="external_controls">
+			<button label="Abrir en mi propio navegador" name="open_browser"/>
+			<check_box label="Abrir siempre en mi propio navegador" name="open_always"/>
+			<button label="Cerrar" name="close"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/es/floater_web_content.xml b/indra/newview/skins/minimal/xui/es/floater_web_content.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b0128096794af5d9ac9b8621066770b746bfee09
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Navegar hacia atrás"/>
+			<button name="forward" tool_tip="Navegar hacia adelante"/>
+			<button name="stop" tool_tip="Parar navegación"/>
+			<button name="reload" tool_tip="Recargar página"/>
+			<combo_box name="address" tool_tip="Escribe la URL aquí"/>
+			<icon name="media_secure_lock_flag" tool_tip="Navegación segura"/>
+			<button name="popexternal" tool_tip="Abrir la URL actual en tu explorador de escritorio"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
index c8a1e9d9da82bda2da74bcba2e93cf7b7faf3fac..1a49efb9d027903c07257b43dbd75b89f5a3838a 100644
--- a/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
@@ -1,10 +1,8 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu name="Gear Menu">
-	<menu_item_call label="Sentarte" name="sit_down_here"/>
-	<menu_item_call label="Levantarme" name="stand_up"/>
-	<menu_item_call label="Cambiar vestuario" name="change_outfit"/>
-	<menu_item_call label="Mi perfil" name="my_profile"/>
-	<menu_item_call label="Mis amigos" name="my_friends"/>
-	<menu_item_call label="Mis grupos" name="my_groups"/>
-	<menu_item_call label="Depurar las texturas" name="Debug..."/>
-</menu>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="Self Pie">
+	<menu_item_call label="Sentarme" name="Sit Down Here"/>
+	<menu_item_call label="Levantarme" name="Stand Up"/>
+	<menu_item_call label="Mis amigos" name="Friends..."/>
+	<menu_item_call label="Mi perfil" name="Profile..."/>
+	<menu_item_call label="Depurar texturas" name="Debug..."/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/notifications.xml b/indra/newview/skins/minimal/xui/es/notifications.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b08ebb5f767be8ab80d59c2b86c36404b0b42435
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/notifications.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<notifications>
+	<notification name="UserGiveItem">
+		[NAME_SLURL] te ofrece un/a [ITEM_SLURL]. Para utilizar este ítem, cambia al modo Avanzado y búscalo en el inventario. Para cambiar al modo Avanzado, sal de la aplicación, reiníciala y cambia el ajuste de modo en la pantalla de inicio de sesión.
+		<form name="form">
+			<button name="Show" text="Conservar ítem"/>
+			<button name="Discard" text="Rechazar ítem"/>
+			<button name="Mute" text="Bloquear usuario"/>
+		</form>
+	</notification>
+	<notification name="ObjectGiveItem">
+		Un objeto de nombre &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt;, propiedad de [NAME_SLURL], te ofrece un/a [ITEM_SLURL]. Para utilizar este ítem, cambia al modo Avanzado y búscalo en el inventario. Para cambiar al modo Avanzado, sal de la aplicación, reiníciala y cambia el ajuste de modo en la pantalla de inicio de sesión.
+		<form name="form">
+			<button name="Keep" text="Conservar ítem"/>
+			<button name="Discard" text="Rechazar ítem"/>
+			<button name="Mute" text="Bloquear objeto"/>
+		</form>
+	</notification>
+</notifications>
diff --git a/indra/newview/skins/minimal/xui/es/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/es/panel_bottomtray.xml
index 9ab30b5613d6636e96f083c78ed03b89edfe1f82..f782d66ae79609ed747d7ca92b6f7214c9592c48 100644
--- a/indra/newview/skins/minimal/xui/es/panel_bottomtray.xml
+++ b/indra/newview/skins/minimal/xui/es/panel_bottomtray.xml
@@ -11,10 +11,10 @@
 			<bottomtray_button label="Visión" name="camera_btn" tool_tip="Muestra/Oculta los controles de la cámara"/>
 		</layout_panel>
 		<layout_panel name="avatar_and_destinations_panel">
-			<radio_group name="avatar_and_destination_btns">
-				<radio_item name="destination_btn" value="0"/>
-				<radio_item name="avatar_btn" value="1"/>
-			</radio_group>
+			<bottomtray_button label="Destinos" name="destination_btn" tool_tip="Muestra la ventana de gente"/>
+		</layout_panel>
+		<layout_panel name="avatar_and_destinations_panel">
+			<bottomtray_button label="Mi avatar" name="avatar_btn"/>
 		</layout_panel>
 		<layout_panel name="people_panel">
 			<bottomtray_button label="Gente" name="show_people_button" tool_tip="Muestra la ventana de gente"/>
diff --git a/indra/newview/skins/minimal/xui/es/panel_group_control_panel.xml b/indra/newview/skins/minimal/xui/es/panel_group_control_panel.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e77156b0d415248d7c2dfe3a99ca668cb0945814
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_group_control_panel.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+	<layout_stack name="vertical_stack">
+		<layout_panel name="end_call_btn_panel">
+			<button label="Colgar" name="end_call_btn"/>
+		</layout_panel>
+		<layout_panel name="voice_ctrls_btn_panel">
+			<button label="Abrir los controles de la voz" name="voice_ctrls_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/es/panel_login.xml b/indra/newview/skins/minimal/xui/es/panel_login.xml
index 161ea19b0e99db38f1c3e813fadcd6d63f7412cb..689a71e277899738bba12b0adb353b9e1f420da1 100644
--- a/indra/newview/skins/minimal/xui/es/panel_login.xml
+++ b/indra/newview/skins/minimal/xui/es/panel_login.xml
@@ -20,8 +20,8 @@
 			<text name="mode_selection_text">
 				Modo:
 			</text>
-			<combo_box name="mode_combo">
-				<combo_box.item label="Básico (Predeterminado)" name="Basic"/>
+			<combo_box name="mode_combo" tool_tip="Selecciona el modo. Elige Básico para una exploración rápida y fácil y para chatear. Elige Avanzado para tener acceso a más funciones.">
+				<combo_box.item label="Básico" name="Basic"/>
 				<combo_box.item label="Avanzado" name="Advanced"/>
 			</combo_box>
 		</layout_panel>
diff --git a/indra/newview/skins/minimal/xui/fr/floater_media_browser.xml b/indra/newview/skins/minimal/xui/fr/floater_media_browser.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ba171c6363feb3d2c569fea2a9ef96268223c28b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/floater_media_browser.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_about" title="NAVIGATEUR DE MÉDIAS">
+	<floater.string name="home_page_url">
+		http://www.secondlife.com
+	</floater.string>
+	<floater.string name="support_page_url">
+		http://support.secondlife.com
+	</floater.string>
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button label="Préc." name="back"/>
+			<button label="Suiv." name="forward"/>
+			<button label="Recharger" name="reload"/>
+			<button label="OK" name="go"/>
+		</layout_panel>
+		<layout_panel name="time_controls">
+			<button label="retour" name="rewind"/>
+			<button label="stop" name="stop"/>
+			<button label="avance" name="seek"/>
+		</layout_panel>
+		<layout_panel name="parcel_owner_controls">
+			<button label="Envoyer la page actuelle à la parcelle" name="assign"/>
+		</layout_panel>
+		<layout_panel name="external_controls">
+			<button label="Ouvrir dans mon navigateur Web" name="open_browser"/>
+			<check_box label="Toujours ouvrir dans mon navigateur Web" name="open_always"/>
+			<button label="Fermer" name="close"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/fr/floater_web_content.xml b/indra/newview/skins/minimal/xui/fr/floater_web_content.xml
new file mode 100644
index 0000000000000000000000000000000000000000..71f44b6ec3686cbcfb440b45887179c092b081ef
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Précédente"/>
+			<button name="forward" tool_tip="Suivante"/>
+			<button name="stop" tool_tip="Arrêter"/>
+			<button name="reload" tool_tip="Recharger la page"/>
+			<combo_box name="address" tool_tip="Saisir une URL ici"/>
+			<icon name="media_secure_lock_flag" tool_tip="Navigation sécurisée"/>
+			<button name="popexternal" tool_tip="Ouvrir l&apos;URL actuelle dans votre navigateur de bureau"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
index 3bc164788a6e193b8189ea20eada2aabafa93701..fd48aa4f7d7bb76329cd11c989bff4ceab786e62 100644
--- a/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
@@ -1,10 +1,8 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu name="Gear Menu">
-	<menu_item_call label="M&apos;asseoir" name="sit_down_here"/>
-	<menu_item_call label="Me lever" name="stand_up"/>
-	<menu_item_call label="Changer de tenue" name="change_outfit"/>
-	<menu_item_call label="Mon profil" name="my_profile"/>
-	<menu_item_call label="Mes amis" name="my_friends"/>
-	<menu_item_call label="Mes groupes" name="my_groups"/>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="Self Pie">
+	<menu_item_call label="M&apos;asseoir" name="Sit Down Here"/>
+	<menu_item_call label="Me lever" name="Stand Up"/>
+	<menu_item_call label="Mes amis" name="Friends..."/>
+	<menu_item_call label="Mon profil" name="Profile..."/>
 	<menu_item_call label="Déboguer les textures" name="Debug..."/>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml
index 26bd3978a9bd08581bade90e0ada568019f19a48..f153ed15ae7610a6535ec3ddb0cc54ae7861923e 100644
--- a/indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml
@@ -9,5 +9,5 @@
 	<menu_item_call label="Partager" name="Share"/>
 	<menu_item_call label="Payer" name="Pay"/>
 	<menu_item_check label="Ignorer/Ne plus ignorer" name="Block/Unblock"/>
-	<menu_item_call label="Proposer une téléportation" name="teleport"/>
+	<menu_item_call label="Téléporter" name="teleport"/>
 </context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/notifications.xml b/indra/newview/skins/minimal/xui/fr/notifications.xml
new file mode 100644
index 0000000000000000000000000000000000000000..41dd42c39fbba205be5a4ebcb4da46afc755dc42
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/notifications.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<notifications>
+	<notification name="UserGiveItem">
+		[NAME_SLURL] vous offre [ITEM_SLURL]. Pour utiliser cet article, vous devez passer en mode Avancé. L&apos;article se trouve dans votre inventaire. Pour changer de mode, quittez l&apos;application, redémarrez-la, puis sélectionnez un autre mode sur l&apos;écran de connexion.
+		<form name="form">
+			<button name="Show" text="Garder l&apos;article"/>
+			<button name="Discard" text="Refuser l&apos;article"/>
+			<button name="Mute" text="Ignorer l&apos;utilisateur"/>
+		</form>
+	</notification>
+	<notification name="ObjectGiveItem">
+		Un objet nommé &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; appartenant à [NAME_SLURL] vous offre [ITEM_SLURL]. Pour utiliser cet article, vous devez passer en mode Avancé. L&apos;article se trouve dans votre inventaire. Pour changer de mode, quittez l&apos;application, redémarrez-la, puis sélectionnez un autre mode sur l&apos;écran de connexion.
+		<form name="form">
+			<button name="Keep" text="Garder l&apos;article"/>
+			<button name="Discard" text="Refuser l&apos;article"/>
+			<button name="Mute" text="Ignorer l&apos;objet"/>
+		</form>
+	</notification>
+</notifications>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml
index 3a01571f54c93a832b28c7235a28771887ba84d2..ef62901e9912a590960bac6c846472280a90d5cd 100644
--- a/indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml
+++ b/indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml
@@ -11,10 +11,10 @@
 			<bottomtray_button label="Affichage" name="camera_btn" tool_tip="Affiche/Masque le contrôle de la caméra"/>
 		</layout_panel>
 		<layout_panel name="avatar_and_destinations_panel">
-			<radio_group name="avatar_and_destination_btns">
-				<radio_item name="destination_btn" value="0"/>
-				<radio_item name="avatar_btn" value="1"/>
-			</radio_group>
+			<bottomtray_button label="Destinations" name="destination_btn" tool_tip="Afficher la fenêtre des personnes."/>
+		</layout_panel>
+		<layout_panel name="avatar_and_destinations_panel">
+			<bottomtray_button label="Mon avatar" name="avatar_btn"/>
 		</layout_panel>
 		<layout_panel name="people_panel">
 			<bottomtray_button label="Personnes" name="show_people_button" tool_tip="Afficher la fenêtre des personnes."/>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_group_control_panel.xml b/indra/newview/skins/minimal/xui/fr/panel_group_control_panel.xml
new file mode 100644
index 0000000000000000000000000000000000000000..676fa1d2229c358bf76f0804e064ef90e4d277c0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_group_control_panel.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+	<layout_stack name="vertical_stack">
+		<layout_panel name="end_call_btn_panel">
+			<button label="Quitter l&apos;appel" name="end_call_btn"/>
+		</layout_panel>
+		<layout_panel name="voice_ctrls_btn_panel">
+			<button label="Ouvrir contrôles vocaux" name="voice_ctrls_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_login.xml b/indra/newview/skins/minimal/xui/fr/panel_login.xml
index cb4822e96bb9a88baeb1af647e6d08f435baa157..0869778a547b7dfcb8929663678adf19159071a4 100644
--- a/indra/newview/skins/minimal/xui/fr/panel_login.xml
+++ b/indra/newview/skins/minimal/xui/fr/panel_login.xml
@@ -20,8 +20,8 @@
 			<text name="mode_selection_text">
 				Mode :
 			</text>
-			<combo_box name="mode_combo">
-				<combo_box.item label="Basique (par défaut)" name="Basic"/>
+			<combo_box name="mode_combo" tool_tip="Sélectionnez un mode. Pour une exploration facile et rapide avec chat, choisissez Basique. Pour accéder à plus de fonctionnalités, choisissez Avancé.">
+				<combo_box.item label="Basique" name="Basic"/>
 				<combo_box.item label="Avancé" name="Advanced"/>
 			</combo_box>
 		</layout_panel>
diff --git a/indra/newview/skins/minimal/xui/pt/floater_media_browser.xml b/indra/newview/skins/minimal/xui/pt/floater_media_browser.xml
new file mode 100644
index 0000000000000000000000000000000000000000..da7428007e5b1e27f41e8b040940bb910d796662
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/floater_media_browser.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_about" title="NAVEGADOR DE MÍDIA">
+	<floater.string name="home_page_url">
+		http://www.secondlife.com
+	</floater.string>
+	<floater.string name="support_page_url">
+		http://support.secondlife.com
+	</floater.string>
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button label="Atrás" name="back"/>
+			<button label="Frente" name="forward"/>
+			<button label="Recarregar" name="reload"/>
+			<button label="OK" name="go"/>
+		</layout_panel>
+		<layout_panel name="time_controls">
+			<button label="p/ trás" name="rewind"/>
+			<button label="parar" name="stop"/>
+			<button label="p/ frente" name="seek"/>
+		</layout_panel>
+		<layout_panel name="parcel_owner_controls">
+			<button label="Enviar esta página para lote" name="assign"/>
+		</layout_panel>
+		<layout_panel name="external_controls">
+			<button label="Abrir no meu navegador" name="open_browser"/>
+			<check_box label="Abrir sempre no meu navegador" name="open_always"/>
+			<button label="Fechar" name="close"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/pt/floater_web_content.xml b/indra/newview/skins/minimal/xui/pt/floater_web_content.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5101579c6f21e8fde127f7e08487b5f6c50a29b4
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Navegar para trás"/>
+			<button name="forward" tool_tip="Navegar para frente"/>
+			<button name="stop" tool_tip="Parar a navegação"/>
+			<button name="reload" tool_tip="Recarregar página"/>
+			<combo_box name="address" tool_tip="Digite a URL aqui"/>
+			<icon name="media_secure_lock_flag" tool_tip="Navegação segura"/>
+			<button name="popexternal" tool_tip="Abrir a URL atual no navegador do seu computador"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
index 7e67f4cfd41556b197405452f418563a8970882c..c1f27e765d797fe223fc1042ae3940570ee0f400 100644
--- a/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
@@ -1,10 +1,8 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu name="Gear Menu">
-	<menu_item_call label="Sentar" name="sit_down_here"/>
-	<menu_item_call label="Ficar de pé" name="stand_up"/>
-	<menu_item_call label="Trocar de look" name="change_outfit"/>
-	<menu_item_call label="Meu perfil" name="my_profile"/>
-	<menu_item_call label="Meus amigos" name="my_friends"/>
-	<menu_item_call label="Meus grupos" name="my_groups"/>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="Self Pie">
+	<menu_item_call label="Sentar" name="Sit Down Here"/>
+	<menu_item_call label="Ficar de pé" name="Stand Up"/>
+	<menu_item_call label="Meus amigos" name="Friends..."/>
+	<menu_item_call label="Meu perfil" name="Profile..."/>
 	<menu_item_call label="Depurar texturas" name="Debug..."/>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml
index 7c720f262bae51f07ac232916877ba5fa0bc3d09..b446a2fe81af14d3715688e821387716cb052f9a 100644
--- a/indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <context_menu name="Avatar Context Menu">
 	<menu_item_call label="Ver perfil" name="View Profile"/>
-	<menu_item_call label="Adicionar amigo..." name="Add Friend"/>
-	<menu_item_call label="Remover amigo..." name="Remove Friend"/>
-	<menu_item_call label="MI" name="IM"/>
+	<menu_item_call label="Adicionar amigo" name="Add Friend"/>
+	<menu_item_call label="Remover amigo" name="Remove Friend"/>
+	<menu_item_call label="IM" name="IM"/>
 	<menu_item_call label="Ligar" name="Call"/>
 	<menu_item_call label="Mapa" name="Map"/>
 	<menu_item_call label="Compartilhar" name="Share"/>
diff --git a/indra/newview/skins/minimal/xui/pt/notifications.xml b/indra/newview/skins/minimal/xui/pt/notifications.xml
new file mode 100644
index 0000000000000000000000000000000000000000..30ba6f68bf2fcff2508ccd7072ccbd8c1d2bf727
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/notifications.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<notifications>
+	<notification name="UserGiveItem">
+		[NAME_SLURL] quer lhe dar [ITEM_SLURL].  Esta ação requer o modo Avançado. Passe para o modo avançado e você verá o item em seu inventário. Para passar para o modo avançado, feche e reinicialize esse aplicativo e mude o modo (indicado na tela de login).
+		<form name="form">
+			<button name="Show" text="Guardar item"/>
+			<button name="Discard" text="Recusar item"/>
+			<button name="Mute" text="Bloquear usuário"/>
+		</form>
+	</notification>
+	<notification name="ObjectGiveItem">
+		Um objeto chamado &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt;, de [NAME_SLURL], está lhe oferecendo [ITEM_SLURL].  Esta ação requer o modo Avançado. Passe para o modo Avançado e você verá o item em seu Inventário. Para passar para o modo Avançado, feche e reinicialize esse aplicativo e mude o modo (indicado na tela de login).
+		<form name="form">
+			<button name="Keep" text="Guardar item"/>
+			<button name="Discard" text="Recusar item"/>
+			<button name="Mute" text="Bloquear objeto"/>
+		</form>
+	</notification>
+</notifications>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml
index 243f323f093cb970ed15912a2f978ba2c1c5d76b..f67823dbd80dfc140b0f20d31f84b7c0eea3a940 100644
--- a/indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml
+++ b/indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml
@@ -11,10 +11,10 @@
 			<bottomtray_button label="Exibir" name="camera_btn" tool_tip="Mostra/oculta os controles da câmera"/>
 		</layout_panel>
 		<layout_panel name="avatar_and_destinations_panel">
-			<radio_group name="avatar_and_destination_btns">
-				<radio_item name="destination_btn" value="0"/>
-				<radio_item name="avatar_btn" value="1"/>
-			</radio_group>
+			<bottomtray_button label="Destinos" name="destination_btn" tool_tip="Exibe janela de pessoas"/>
+		</layout_panel>
+		<layout_panel name="avatar_and_destinations_panel">
+			<bottomtray_button label="Meu avatar" name="avatar_btn"/>
 		</layout_panel>
 		<layout_panel name="people_panel">
 			<bottomtray_button label="Pessoas" name="show_people_button" tool_tip="Exibe as pessoas"/>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_group_control_panel.xml b/indra/newview/skins/minimal/xui/pt/panel_group_control_panel.xml
new file mode 100644
index 0000000000000000000000000000000000000000..177cee28a648d10fb6e28890de05b1eceb365923
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_group_control_panel.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+	<layout_stack name="vertical_stack">
+		<layout_panel name="end_call_btn_panel">
+			<button label="Desligar" name="end_call_btn"/>
+		</layout_panel>
+		<layout_panel name="voice_ctrls_btn_panel">
+			<button label="Abrir controles de voz" name="voice_ctrls_btn"/>
+		</layout_panel>
+	</layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_login.xml b/indra/newview/skins/minimal/xui/pt/panel_login.xml
index cd529b0b066b595e1aeb8f96b76b88ff503016a6..de9717874f375926e4d46f25a17c74aec5c593f9 100644
--- a/indra/newview/skins/minimal/xui/pt/panel_login.xml
+++ b/indra/newview/skins/minimal/xui/pt/panel_login.xml
@@ -20,8 +20,8 @@
 			<text name="mode_selection_text">
 				Modo:
 			</text>
-			<combo_box name="mode_combo">
-				<combo_box.item label="Básico (padrão)" name="Basic"/>
+			<combo_box name="mode_combo" tool_tip="Selecione o modo. O modo Básico é mais rápido e ideal para explorar e conversar. Use o modo Avançado para acessar mais recursos.">
+				<combo_box.item label="Básico" name="Basic"/>
 				<combo_box.item label="Avançado" name="Advanced"/>
 			</combo_box>
 		</layout_panel>