diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index 552e8201279564695b4cfa119f15ec6ad76897c5..4617309606dfc3c17d27015dd83b1f9875cd474b 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -4,12 +4,14 @@ project(llmath)
 
 include(00-Common)
 include(LLCommon)
+include(LLMeshOptimizer)
 include(bugsplat)
 include(Boost)
 
 include_directories(
     ${LLCOMMON_INCLUDE_DIRS}
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
+    ${LLMESHOPTIMIZER_INCLUDE_DIRS}
     )
 
 set(llmath_SOURCE_FILES
@@ -109,6 +111,7 @@ add_library (llmath ${llmath_SOURCE_FILES})
 
 target_link_libraries(llmath
     ${LLCOMMON_LIBRARIES}
+    ${LLMESHOPTIMIZER_LIBRARIES}
     )
 
 # Add tests
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 2b23325bff2892bf9886269e77cec7a12e2df222..c27b144f1967bb48d49ee925c3b0b92f2e250850 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -49,6 +49,7 @@
 #include "llsdserialize.h"
 #include "llvector4a.h"
 #include "llmatrix4a.h"
+#include "llmeshoptimizer.h"
 #include "lltimer.h"
 
 #define DEBUG_SILHOUETTE_BINORMALS 0
@@ -4952,6 +4953,50 @@ bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a
 	return a.mV[2] < b.mV[2];
 }
 
+void LLVolumeFace::remap()
+{
+    // Generate a remap buffer
+    std::vector<unsigned int> remap(mNumVertices);
+    S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0],
+        mIndices,
+        mNumIndices,
+        mPositions,
+        mNormals,
+        mTexCoords,
+        mNumVertices);
+
+    // Allocate new buffers
+    S32 size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF;
+    U16* remap_indices = (U16*)ll_aligned_malloc_16(size);
+
+    S32 tc_bytes_size = ((remap_vertices_count * sizeof(LLVector2)) + 0xF) & ~0xF;
+    LLVector4a* remap_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * remap_vertices_count + tc_bytes_size);
+    LLVector4a* remap_normals = remap_positions + remap_vertices_count;
+    LLVector2* remap_tex_coords = (LLVector2*)(remap_normals + remap_vertices_count);
+
+    // Fill the buffers
+    LLMeshOptimizer::remapIndexBufferU16(remap_indices, mIndices, mNumIndices, &remap[0]);
+    LLMeshOptimizer::remapPositionsBuffer(remap_positions, mPositions, mNumVertices, &remap[0]);
+    LLMeshOptimizer::remapNormalsBuffer(remap_normals, mNormals, mNumVertices, &remap[0]);
+    LLMeshOptimizer::remapUVBuffer(remap_tex_coords, mTexCoords, mNumVertices, &remap[0]);
+
+    // Free unused buffers
+    ll_aligned_free_16(mIndices);
+    ll_aligned_free<64>(mPositions);
+
+    // Tangets are now invalid
+    ll_aligned_free_16(mTangents);
+    mTangents = NULL;
+
+    // Assign new values
+    mIndices = remap_indices;
+    mPositions = remap_positions;
+    mNormals = remap_normals;
+    mTexCoords = remap_tex_coords;
+    mNumVertices = remap_vertices_count;
+    mNumAllocatedVertices = remap_vertices_count;
+}
+
 void LLVolumeFace::optimize(F32 angle_cutoff)
 {
 	LLVolumeFace new_face;
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index c0b224b1ff1867cb67ea9641f9f8adeb35d2b4a7..9697952f5b6c89e6c2b6b0711320a49da03774e5 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -902,6 +902,10 @@ class LLVolumeFace
 		typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
 	};
 
+    // Eliminates non unique triangles, takes positions,
+    // normals and texture coordinates into account.
+    void remap();
+
 	void optimize(F32 angle_cutoff = 2.f);
 	bool cacheOptimize();
 
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index a879389c5adec63666535769e9ec40097709ea9a..c178348968c24599183bec3b560686f32afd1534 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -28,6 +28,9 @@
 
 #include "meshoptimizer.h"
 
+#include "llmath.h"
+#include "v2math.h"
+
 LLMeshOptimizer::LLMeshOptimizer()
 {
     // Todo: Looks like for memory management, we can add allocator and deallocator callbacks
@@ -40,24 +43,218 @@ LLMeshOptimizer::~LLMeshOptimizer()
 }
 
 //static
-void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination,
-    const U16 *indices,
+void LLMeshOptimizer::generateShadowIndexBufferU32(U32 *destination,
+    const U32 *indices,
     U64 index_count,
-    const LLVector4a *vertex_positions,
-    U64 vertex_count,
-    U64 vertex_positions_stride
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count
 )
 {
-    meshopt_generateShadowIndexBuffer<unsigned short>(destination,
+    meshopt_Stream streams[3];
+
+    S32 index = 0;
+    if (vertex_positions)
+    {
+        streams[index].data = (const float*)vertex_positions;
+        // Despite being LLVector4a, only x, y and z are in use
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (normals)
+    {
+        streams[index].data = (const float*)normals;
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (text_coords)
+    {
+        streams[index].data = (const float*)text_coords;
+        streams[index].size = sizeof(F32) * 2;
+        streams[index].stride = sizeof(F32) * 2;
+        index++;
+    }
+
+    if (index == 0)
+    {
+        // invalid
+        return;
+    }
+
+    meshopt_generateShadowIndexBufferMulti<unsigned int>(destination,
         indices,
         index_count,
-        (const float*)vertex_positions, // verify that it is correct to convert to float
         vertex_count,
-        sizeof(LLVector4a),
-        vertex_positions_stride
+        streams,
+        index
         );
 }
 
+//static
+void LLMeshOptimizer::generateShadowIndexBufferU16(U16 *destination,
+    const U16 *indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count
+)
+{
+    meshopt_Stream streams[3];
+
+    S32 index = 0;
+    if (vertex_positions)
+    {
+        streams[index].data = (const float*)vertex_positions;
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (normals)
+    {
+        streams[index].data = (const float*)normals;
+        streams[index].size = sizeof(F32) * 3;
+        streams[index].stride = sizeof(F32) * 4;
+        index++;
+    }
+    if (text_coords)
+    {
+        streams[index].data = (const float*)text_coords;
+        streams[index].size = sizeof(F32) * 2;
+        streams[index].stride = sizeof(F32) * 2;
+        index++;
+    }
+
+    if (index == 0)
+    {
+        // invalid
+        return;
+    }
+
+    meshopt_generateShadowIndexBufferMulti<unsigned short>(destination,
+        indices,
+        index_count,
+        vertex_count,
+        streams,
+        index);
+}
+
+void LLMeshOptimizer::optimizeVertexCacheU32(U32 * destination, const U32 * indices, U64 index_count, U64 vertex_count)
+{
+    meshopt_optimizeVertexCache<unsigned int>(destination, indices, index_count, vertex_count);
+}
+
+void LLMeshOptimizer::optimizeVertexCacheU16(U16 * destination, const U16 * indices, U64 index_count, U64 vertex_count)
+{
+    meshopt_optimizeVertexCache<unsigned short>(destination, indices, index_count, vertex_count);
+}
+
+size_t LLMeshOptimizer::generateRemapMultiU32(
+    unsigned int* remap,
+    const U32 * indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count)
+{
+    meshopt_Stream streams[] = {
+       {(const float*)vertex_positions, sizeof(F32) * 3, sizeof(F32) * 4},
+       {(const float*)normals, sizeof(F32) * 3, sizeof(F32) * 4},
+       {(const float*)text_coords, sizeof(F32) * 2, sizeof(F32) * 2},
+    };
+
+    // Remap can function without indices,
+    // but providing indices helps with removing unused vertices
+    U64 indeces_cmp = indices ? index_count : vertex_count;
+
+    // meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count)
+    return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
+}
+
+size_t LLMeshOptimizer::generateRemapMultiU16(
+    unsigned int* remap,
+    const U16 * indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count)
+{
+    S32 out_of_range_count = 0;
+    U32* indices_u32 = NULL;
+    if (indices)
+    {
+        indices_u32 = (U32*)ll_aligned_malloc_32(index_count * sizeof(U32));
+        for (U64 i = 0; i < index_count; i++)
+        {
+            if (indices[i] < vertex_count)
+            {
+                indices_u32[i] = (U32)indices[i];
+            }
+            else
+            {
+                out_of_range_count++;
+                indices_u32[i] = 0;
+            }
+        }
+    }
+
+    if (out_of_range_count)
+    {
+        LL_WARNS() << out_of_range_count << " indices are out of range." << LL_ENDL;
+    }
+
+    size_t unique = generateRemapMultiU32(remap, indices_u32, index_count, vertex_positions, normals, text_coords, vertex_count);
+
+    ll_aligned_free_32(indices_u32);
+
+    return unique;
+}
+
+void LLMeshOptimizer::remapIndexBufferU32(U32 * destination_indices,
+    const U32 * indices,
+    U64 index_count,
+    const unsigned int* remap)
+{
+    meshopt_remapIndexBuffer<unsigned int>(destination_indices, indices, index_count, remap);
+}
+
+void LLMeshOptimizer::remapIndexBufferU16(U16 * destination_indices,
+    const U16 * indices,
+    U64 index_count,
+    const unsigned int* remap)
+{
+    meshopt_remapIndexBuffer<unsigned short>(destination_indices, indices, index_count, remap);
+}
+
+void LLMeshOptimizer::remapPositionsBuffer(LLVector4a * destination_vertices,
+    const LLVector4a * vertex_positions,
+    U64 vertex_count,
+    const unsigned int* remap)
+{
+    meshopt_remapVertexBuffer((float*)destination_vertices, (const float*)vertex_positions, vertex_count, sizeof(LLVector4a), remap);
+}
+
+void LLMeshOptimizer::remapNormalsBuffer(LLVector4a * destination_normalss,
+    const LLVector4a * normals,
+    U64 mormals_count,
+    const unsigned int* remap)
+{
+    meshopt_remapVertexBuffer((float*)destination_normalss, (const float*)normals, mormals_count, sizeof(LLVector4a), remap);
+}
+
+void LLMeshOptimizer::remapUVBuffer(LLVector2 * destination_uvs,
+    const LLVector2 * uv_positions,
+    U64 uv_count,
+    const unsigned int* remap)
+{
+    meshopt_remapVertexBuffer((float*)destination_uvs, (const float*)uv_positions, uv_count, sizeof(LLVector2), remap);
+}
+
 //static
 U64 LLMeshOptimizer::simplifyU32(U32 *destination,
     const U32 *indices,
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index e8dd16dae967593e7aec99522bdba81de9cedc85..ea965d6b47c1311f9bf8e7738b83f88b7cdc4cd6 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -28,7 +28,8 @@
 
 #include "linden_common.h"
 
-#include "llmath.h"
+class LLVector4a;
+class LLVector2;
 
 class LLMeshOptimizer
 {
@@ -36,13 +37,85 @@ class LLMeshOptimizer
     LLMeshOptimizer();
     ~LLMeshOptimizer();
 
-    static void generateShadowIndexBuffer(
+    static void generateShadowIndexBufferU32(
+        U32 *destination,
+        const U32 *indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static void generateShadowIndexBufferU16(
         U16 *destination,
         const U16 *indices,
         U64 index_count,
-        const LLVector4a *vertex_positions,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static void optimizeVertexCacheU32(
+        U32 *destination,
+        const U32 *indices,
+        U64 index_count,
+        U64 vertex_count);
+
+    static void optimizeVertexCacheU16(
+        U16 *destination,
+        const U16 *indices,
+        U64 index_count,
+        U64 vertex_count);
+
+    // Remap functions
+    // Welds indentical vertexes together.
+    // Removes unused vertices if indices were provided.
+
+    static size_t generateRemapMultiU32(
+        unsigned int* remap,
+        const U32 * indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static size_t generateRemapMultiU16(
+        unsigned int* remap,
+        const U16 * indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
+    static void remapIndexBufferU32(U32 * destination_indices,
+        const U32 * indices,
+        U64 index_count,
+        const unsigned int* remap);
+
+    static void remapIndexBufferU16(U16 * destination_indices,
+        const U16 * indices,
+        U64 index_count,
+        const unsigned int* remap);
+
+
+    static void remapPositionsBuffer(LLVector4a * destination_vertices,
+        const LLVector4a * vertex_positions,
         U64 vertex_count,
-        U64 vertex_positions_stride);
+        const unsigned int* remap);
+
+    static void remapNormalsBuffer(LLVector4a * destination_normalss,
+        const LLVector4a * normals,
+        U64 mormals_count,
+        const unsigned int* remap);
+
+    static void remapUVBuffer(LLVector2 * destination_uvs,
+        const LLVector2 * uv_positions,
+        U64 uv_count,
+        const unsigned int* remap);
+
+    // Simplification
 
     // returns amount of indices in destiantion
     // sloppy engages a variant of a mechanizm that does not respect topology as much
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index e89690438eb6e20714446c4066d44c118e2a9131..68654486a4088fa07b24d13d97434ae3c63cf942 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -2577,7 +2577,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
 
 		if (!mNoOptimize)
 		{
-			ret->optimizeVolumeFaces();
+			ret->remapVolumeFaces();
 		}
 
 		volume_faces = remainder.size();
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index e52c675b60e8de5d5aacd8cac5b43bc959201d97..555164f3b001c2fe46ad3d855008d8fc1fe52011 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -107,6 +107,14 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint )
 	}
 }
 
+void LLModel::remapVolumeFaces()
+{
+    for (U32 i = 0; i < getNumVolumeFaces(); ++i)
+    {
+        mVolumeFaces[i].remap();
+    }
+}
+
 void LLModel::optimizeVolumeFaces()
 {
 	for (U32 i = 0; i < getNumVolumeFaces(); ++i)
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index bffac0f3b5e41fd8a451d9e08678a66968b086a9..a6ab96ab18400dcfd57c02064a1bc1eb6bbbdcdf 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -194,6 +194,7 @@ class LLModel : public LLVolume
 	void sortVolumeFacesByMaterialName();
 	void normalizeVolumeFaces();
 	void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
+    void remapVolumeFaces();
 	void optimizeVolumeFaces();
 	void offsetMesh( const LLVector3& pivotPoint );
 	void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 0e59fdf51936e4c302cbcb66a8e2c5684ebf818e..8028f397f3ebf99bc2c52d25888ab68c8d350bbf 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -102,6 +102,7 @@ LLButton::Params::Params()
 	scale_image("scale_image", true),
 	hover_glow_amount("hover_glow_amount"),
 	commit_on_return("commit_on_return", true),
+    commit_on_capture_lost("commit_on_capture_lost", false),
 	display_pressed_state("display_pressed_state", true),
 	use_draw_context_alpha("use_draw_context_alpha", true),
 	badge("badge"),
@@ -165,6 +166,7 @@ LLButton::LLButton(const LLButton::Params& p)
 	mBottomVPad(p.pad_bottom),
 	mHoverGlowStrength(p.hover_glow_amount),
 	mCommitOnReturn(p.commit_on_return),
+    mCommitOnCaptureLost(p.commit_on_capture_lost),
 	mFadeWhenDisabled(FALSE),
 	mForcePressedState(false),
 	mDisplayPressedState(p.display_pressed_state),
@@ -475,6 +477,10 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 	// We only handle the click if the click both started and ended within us
 	if( hasMouseCapture() )
 	{
+        // reset timers before focus change, to not cause
+        // additional commits if mCommitOnCaptureLost.
+        resetMouseDownTimer();
+
 		// Always release the mouse
 		gFocusMgr.setMouseCapture( NULL );
 
@@ -489,8 +495,6 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 		// Regardless of where mouseup occurs, handle callback
 		if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
 
-		resetMouseDownTimer();
-
 		// DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
 		// If mouseup in the widget, it's been clicked
 		if (pointInView(x, y))
@@ -1195,6 +1199,18 @@ void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignmen
 
 void LLButton::onMouseCaptureLost()
 {
+    if (mCommitOnCaptureLost
+        && mMouseDownTimer.getStarted())
+    {
+        if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
+
+        if (mIsToggle)
+        {
+            toggleState();
+        }
+
+        LLUICtrl::onCommit();
+    }
 	resetMouseDownTimer();
 }
 
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 572d36996c47e64cbf9f622823a86340de66eef8..ccd31e90c0309ecbd4b83915d2d4fc88dc3996da 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -124,6 +124,7 @@ class LLButton
 		Optional<bool>			is_toggle,
 								scale_image,
 								commit_on_return,
+								commit_on_capture_lost,
 								display_pressed_state;
 		
 		Optional<F32>				hover_glow_amount;
@@ -374,6 +375,7 @@ class LLButton
 	F32							mCurGlowStrength;
 
 	bool						mCommitOnReturn;
+    bool						mCommitOnCaptureLost;
 	bool						mFadeWhenDisabled;
 	bool						mForcePressedState;
 	bool						mDisplayPressedState;
diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp
index 209796565c7410cc197cfdcef40e2e632ea4513c..cf57b1fe76e0030277690bfd88228af162f2afda 100644
--- a/indra/llui/llprogressbar.cpp
+++ b/indra/llui/llprogressbar.cpp
@@ -69,16 +69,22 @@ void LLProgressBar::draw()
 	static LLTimer timer;
 	F32 alpha = getDrawContext().mAlpha;
 	
-	LLColor4 image_bar_color = mColorBackground.get();
-	image_bar_color.setAlpha(alpha);
-	mImageBar->draw(getLocalRect(), image_bar_color);
+    if (mImageBar) // optional according to parameters
+    {
+        LLColor4 image_bar_color = mColorBackground.get();
+        image_bar_color.setAlpha(alpha);
+        mImageBar->draw(getLocalRect(), image_bar_color);
+    }
 
-	alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
-	LLColor4 bar_color = mColorBar.get();
-	bar_color.mV[VALPHA] *= alpha; // modulate alpha
-	LLRect progress_rect = getLocalRect();
-	progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
-	mImageFill->draw(progress_rect, bar_color);
+    if (mImageFill)
+    {
+        alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
+        LLColor4 bar_color = mColorBar.get();
+        bar_color.mV[VALPHA] *= alpha; // modulate alpha
+        LLRect progress_rect = getLocalRect();
+        progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
+        mImageFill->draw(progress_rect, bar_color);
+    }
 }
 
 void LLProgressBar::setValue(const LLSD& value)
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index ee78b824295ce7d01ce2ca8b59e165a2d2d6e60e..ef7c8ec0129fc4ba40cddc8a9d778055e81cc0de 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -103,6 +103,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
 	up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
 	up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
 	up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
+    up_button_params.commit_on_capture_lost = true;
 
 	mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
 	addChild(mUpBtn);
@@ -111,6 +112,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
 	down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
 	down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
 	down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
+    down_button_params.commit_on_capture_lost = true;
 	mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
 	addChild(mDownBtn);
 
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 28179fc1f51c8e3ccacab1b8e36a63af4aa9e1bf..e411592c25a87f92cf75d9c3d7c9a774fdea79db 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.6.2
+6.6.3
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cf0ad449da539c20d79bf41633bd123679ada75c..d61a66c696c35a5fd27493f0e6ac18b379383ea4 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2718,19 +2718,14 @@ bool LLAppViewer::initConfiguration()
 
 	if (clp.hasOption("graphicslevel"))
 	{
-		// User explicitly requested --graphicslevel on the command line. We
-		// expect this switch has already set RenderQualityPerformance. Check
-		// that value for validity.
-		U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance");
-		if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel))
-        {
-			// graphicslevel is valid: save it and engage it later. Capture
-			// the requested value separately from the settings variable
-			// because, if this is the first run, LLViewerWindow's constructor
-			// will call LLFeatureManager::applyRecommendedSettings(), which
-			// overwrites this settings variable!
-			mForceGraphicsLevel = graphicslevel;
-        }
+        // User explicitly requested --graphicslevel on the command line. We
+        // expect this switch has already set RenderQualityPerformance. Check
+        // that value for validity later.
+        // Capture the requested value separately from the settings variable
+        // because, if this is the first run, LLViewerWindow's constructor
+        // will call LLFeatureManager::applyRecommendedSettings(), which
+        // overwrites this settings variable!
+        mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance");
 	}
 
 	LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance");
@@ -3088,7 +3083,7 @@ bool LLAppViewer::initWindow()
 	// Initialize GL stuff
 	//
 
-	if (mForceGraphicsLevel)
+	if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel)))
 	{
 		LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false);
 		gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel);
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index 20fa6d490b4562c24c3bf13349103130b07d61af..48c7df40dfbe2045beb932119eac68c139b9e32b 100644
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -272,9 +272,9 @@ BOOL LLConversationViewSession::postBuild()
 		default:
 			break;
 		}
-	}
 
-	refresh();
+        refresh(); // requires vmi
+	}
 
 	return TRUE;
 }
@@ -490,17 +490,20 @@ void LLConversationViewSession::refresh()
 {
 	// Refresh the session view from its model data
 	LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
-	vmi->resetRefresh();
+    if (vmi)
+    {
+        vmi->resetRefresh();
 
-	if (mSessionTitle)
-	{		
-		if (!highlightFriendTitle(vmi))
-		{
-			LLStyle::Params title_style;
-			title_style.color = LLUIColorTable::instance().getColor("LabelTextColor");
-			mSessionTitle->setText(vmi->getDisplayName(), title_style);
-		}
-	}
+        if (mSessionTitle)
+        {
+            if (!highlightFriendTitle(vmi))
+            {
+                LLStyle::Params title_style;
+                title_style.color = LLUIColorTable::instance().getColor("LabelTextColor");
+                mSessionTitle->setText(vmi->getDisplayName(), title_style);
+            }
+        }
+    }
 
 	// Update all speaking indicators
 	LLSpeakingIndicatorManager::updateSpeakingIndicators();
@@ -524,8 +527,11 @@ void LLConversationViewSession::refresh()
 	}
 
 	requestArrange();
-	// Do the regular upstream refresh
-	LLFolderViewFolder::refresh();
+    if (vmi)
+    {
+        // Do the regular upstream refresh
+        LLFolderViewFolder::refresh();
+    }
 }
 
 void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& session_id)
@@ -627,8 +633,11 @@ BOOL LLConversationViewParticipant::postBuild()
     }
 
     updateChildren();
-	LLFolderViewItem::postBuild();
-    refresh();
+    if (getViewModelItem())
+    {
+        LLFolderViewItem::postBuild();
+        refresh();
+    }
     return TRUE;
 }
 
@@ -712,10 +721,10 @@ void LLConversationViewParticipant::refresh()
 
         // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
         mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
+        
+        // Do the regular upstream refresh
+        LLFolderViewItem::refresh();
     }
-
-	// Do the regular upstream refresh
-	LLFolderViewItem::refresh();
 }
 
 void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder)
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 34499ac170e1ecf02a81ac952c33b009ecc7ddea..93a0b39e023189167cdd50b4279c923e27b9da81 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -551,7 +551,7 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part
 void LLFloaterIMSessionTab::updateConversationViewParticipant(const LLUUID& participant_id)
 {
 	LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id);
-	if (widget)
+	if (widget && widget->getViewModelItem())
 	{
 		widget->refresh();
 	}
@@ -576,8 +576,11 @@ void LLFloaterIMSessionTab::refreshConversation()
 		{
 			participants_uuids.push_back(widget_it->first);
 		}
-		widget_it->second->refresh();
-		widget_it->second->setVisible(TRUE);
+        if (widget_it->second->getViewModelItem())
+        {
+            widget_it->second->refresh();
+            widget_it->second->setVisible(TRUE);
+        }
 		++widget_it;
 	}
 	if (is_ad_hoc || mIsP2PChat)
@@ -1126,7 +1129,10 @@ void LLFloaterIMSessionTab::getSelectedUUIDs(uuid_vec_t& selected_uuids)
     for (; it != it_end; ++it)
     {
         LLConversationItem* conversation_item = static_cast<LLConversationItem *>((*it)->getViewModelItem());
-        selected_uuids.push_back(conversation_item->getUUID());
+        if (conversation_item)
+        {
+            selected_uuids.push_back(conversation_item->getUUID());
+        }
     }
 }
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 50acb2a766c7851799cbaa0c2d977255ace6573d..90390de52a2a1aee768cff5088d50efd9d2f0737 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -750,7 +750,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
     {
     case LLModelPreview::MESH_OPTIMIZER_AUTO:
     case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
-    case LLModelPreview::MESH_OPTIMIZER_COMBINE:
+    case LLModelPreview::MESH_OPTIMIZER_PRECISE:
         mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode);
         break;
     default:
@@ -1754,7 +1754,7 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
     S32 index = lod_source_combo->getCurrentIndex();
 	if (index == LLModelPreview::MESH_OPTIMIZER_AUTO
         || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
-        || index == LLModelPreview::MESH_OPTIMIZER_COMBINE)
+        || index == LLModelPreview::MESH_OPTIMIZER_PRECISE)
 	{ //rebuild LoD to update triangle counts
 		onLODParamCommit(lod, true);
 	}
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index f04666cb79ec8987ee4427030ba816544356b698..b6acba6558b90cb2e8ac14aa548fb61655323add 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -473,30 +473,61 @@ void LLFloaterTools::refresh()
 	else
 #endif
 	{
-		F32 link_cost  = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost();
-		S32 link_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount();
-
-		LLCrossParcelFunctor func;
-		if (LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true))
-		{
-			// Selection crosses parcel bounds.
-			// We don't display remaining land capacity in this case.
-			const LLStringExplicit empty_str("");
-			childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", empty_str);
-		}
-		else
-		{
-			LLViewerObject* selected_object = mObjectSelection->getFirstObject();
-			if (selected_object)
-			{
-				// Select a parcel at the currently selected object's position.
-				LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
-			}
-			else
-			{
-				LL_WARNS() << "Failed to get selected object" << LL_ENDL;
-			}
-		}
+        LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+        F32 link_cost = selection->getSelectedLinksetCost();
+        S32 link_count = selection->getRootObjectCount();
+        S32 object_count = selection->getObjectCount();
+
+        LLCrossParcelFunctor func;
+        if (!LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true))
+        {
+            // Unless multiple parcels selected, higlight parcel object is at.
+            LLViewerObject* selected_object = mObjectSelection->getFirstObject();
+            if (selected_object)
+            {
+                // Select a parcel at the currently selected object's position.
+                LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
+            }
+            else
+            {
+                LL_WARNS() << "Failed to get selected object" << LL_ENDL;
+            }
+        }
+
+        if (object_count == 1)
+        {
+            // "selection_faces" shouldn't be visible if not LLToolFace::getInstance()
+            // But still need to be populated in case user switches
+
+            std::string faces_str = "";
+
+            for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end();)
+            {
+                LLObjectSelection::iterator nextiter = iter++; // not strictly needed, we have only one object
+                LLSelectNode* node = *nextiter;
+                LLViewerObject* object = (*nextiter)->getObject();
+                if (!object)
+                    continue;
+                S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces());
+                for (S32 te = 0; te < num_tes; ++te)
+                {
+                    if (node->isTESelected(te))
+                    {
+                        if (!faces_str.empty())
+                        {
+                            faces_str += ", ";
+                        }
+                        faces_str += llformat("%d", te);
+                    }
+                }
+            }
+
+            childSetTextArg("selection_faces", "[FACES_STRING]", faces_str);
+        }
+
+        bool show_faces = (object_count == 1)
+                          && LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+        getChildView("selection_faces")->setVisible(show_faces);
 
 		LLStringUtil::format_map_t selection_args;
 		selection_args["OBJ_COUNT"] = llformat("%.1d", link_count);
@@ -814,7 +845,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
 	bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();
 
 	getChildView("selection_count")->setVisible(!land_visible && have_selection);
-	getChildView("remaining_capacity")->setVisible(!land_visible && have_selection);
+    getChildView("selection_faces")->setVisible(LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()
+                                                && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1);
 	getChildView("selection_empty")->setVisible(!land_visible && !have_selection);
 	
 	mTab->setVisible(!land_visible);
@@ -1084,7 +1116,7 @@ void LLFloaterTools::onClickGridOptions()
 {
 	LLFloater* floaterp = LLFloaterReg::showInstance("build_options");
 	// position floater next to build tools, not over
-	floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));
+	floaterp->setShape(gFloaterView->findNeighboringPosition(this, floaterp), true);
 }
 
 // static
@@ -1125,26 +1157,6 @@ void LLFloaterTools::updateLandImpacts()
 		return;
 	}
 
-	S32 rezzed_prims = parcel->getSimWidePrimCount();
-	S32 total_capacity = parcel->getSimWideMaxPrimCapacity();
-	LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
-	if (region)
-	{
-		S32 max_tasks_per_region = (S32)region->getMaxTasks();
-		total_capacity = llmin(total_capacity, max_tasks_per_region);
-	}
-	std::string remaining_capacity_str = "";
-
-	bool show_mesh_cost = gMeshRepo.meshRezEnabled();
-	if (show_mesh_cost)
-	{
-		LLStringUtil::format_map_t remaining_capacity_args;
-		remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims);
-		remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args);
-	}
-
-	childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", remaining_capacity_str);
-
 	// Update land impacts info in the weights floater
 	LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance<LLFloaterObjectWeights>("object_weights");
 	if(object_weights_floater)
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 4c83488d8169fc6162b89d9276c82c6b49cc1c63..977023cfe4aa2b18483a6642ebadbf69b604b6f1 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -45,6 +45,7 @@
 //#include "llfirstuse.h"
 #include "llfloaterreg.h"		// getTypedInstance()
 #include "llfocusmgr.h"
+#include "lliconctrl.h"
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
 #include "llinventorymodelbackgroundfetch.h"
@@ -307,6 +308,8 @@ BOOL LLFloaterWorldMap::postBuild()
 	
 	mCurZoomVal = log(LLWorldMapView::sMapScale/256.f)/log(2.f);
 	getChild<LLUICtrl>("zoom slider")->setValue(mCurZoomVal);
+
+    getChild<LLPanel>("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this));
 	
 	setDefaultBtn(NULL);
 	
@@ -1315,6 +1318,22 @@ void LLFloaterWorldMap::onCopySLURL()
 	LLNotificationsUtil::add("CopySLURL", args);
 }
 
+void LLFloaterWorldMap::onExpandCollapseBtn()
+{
+    LLLayoutStack* floater_stack = getChild<LLLayoutStack>("floater_map_stack");
+    LLLayoutPanel* controls_panel = getChild<LLLayoutPanel>("controls_lp");
+    
+    bool toggle_collapse = !controls_panel->isCollapsed();
+    floater_stack->collapsePanel(controls_panel, toggle_collapse);
+    floater_stack->updateLayout();
+   
+    std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon");
+    std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip");
+    getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name));
+    getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip);
+    getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip);
+}
+
 // protected
 void LLFloaterWorldMap::centerOnTarget(BOOL animate)
 {
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index 14a9c26fb97fe7687eb540e06c154ade3fb26621..fcb55e9666e17624e1a793dd6b16383243dadcc8 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -130,6 +130,8 @@ class LLFloaterWorldMap : public LLFloater
 	void			onShowAgentBtn();
 	void			onCopySLURL();
 
+    void            onExpandCollapseBtn();
+
 	void			centerOnTarget(BOOL animate);
 	void			updateLocation();
 
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 10814ac0769db1f3675c36211e83774d3a9eb84f..f357899be0a458094ce0bd1dc386d2704dad7f7a 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -348,7 +348,7 @@ void LLInspectAvatar::onClickMuteVolume()
 	LLMuteList* mute_list = LLMuteList::getInstance();
 	bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat);
 
-	LLMute mute(mAvatarID, mAvatarName.getDisplayName(), LLMute::AGENT);
+	LLMute mute(mAvatarID, mAvatarName.getUserName(), LLMute::AGENT);
 	if (!is_muted)
 	{
 		mute_list->add(mute, LLMute::flagVoiceChat);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index f0a9e998bcf1fb09ed1bfcba224b4b6a78eaf77f..f42c95418530f65dc812bd7b9d03aed54bd95389 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -792,6 +792,19 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 			disabled_items.push_back(std::string("Copy"));
 		}
 
+        if (isAgentInventory())
+        {
+            items.push_back(std::string("New folder from selected"));
+            items.push_back(std::string("Subfolder Separator"));
+            std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
+            uuid_vec_t ids;
+            std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids));
+            if (!is_only_items_selected(ids) && !is_only_cats_selected(ids))
+            {
+                disabled_items.push_back(std::string("New folder from selected"));
+            }
+        }
+
 		if (obj->getIsLinkType())
 		{
 			items.push_back(std::string("Find Original"));
@@ -4269,7 +4282,16 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
 			items.push_back(std::string("Conference Chat Folder"));
 			items.push_back(std::string("IM All Contacts In Folder"));
 		}
+
+        if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren())
+        {
+            items.push_back(std::string("Ungroup folder items"));
+        }
 	}
+    else
+    {
+        disabled_items.push_back(std::string("New folder from selected"));
+    }
 
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 	if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory)
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index d239b23e83da281636e8f275bdf9cc57f9841ae5..27edc8148efc638062c5d43063048263b98f0c6c 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -1868,6 +1868,86 @@ void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id)
 	}
 }
 
+void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids)
+{
+    for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
+    {
+        LLInventoryItem* inv_item = gInventory.getItem(*it);
+        if (inv_item)
+        {
+            change_item_parent(*it, new_cat_uuid);
+        }
+        else
+        {
+            LLInventoryCategory* inv_cat = gInventory.getCategory(*it);
+            if (inv_cat && !LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+            {
+                gInventory.changeCategoryParent((LLViewerInventoryCategory*)inv_cat, new_cat_uuid, false);
+            }
+        }
+    }
+
+    LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
+    if (!floater_inventory)
+    {
+        LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL;
+        return;
+    }
+    LLSidepanelInventory *sidepanel_inventory =	LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+    if (sidepanel_inventory)
+    {
+        if (sidepanel_inventory->getActivePanel())
+        {
+            sidepanel_inventory->getActivePanel()->setSelection(new_cat_uuid, TAKE_FOCUS_YES);
+            LLFolderViewItem* fv_folder = sidepanel_inventory->getActivePanel()->getItemByID(new_cat_uuid);
+            if (fv_folder)
+            {
+                fv_folder->setOpen(TRUE);
+            }
+        }
+    }
+}
+
+bool is_only_cats_selected(const uuid_vec_t& selected_uuids)
+{
+    for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
+    {
+        LLInventoryCategory* inv_cat = gInventory.getCategory(*it);
+        if (!inv_cat)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool is_only_items_selected(const uuid_vec_t& selected_uuids)
+{
+    for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
+    {
+        LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+        if (!inv_item)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+
+void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name)
+{
+    LLInventoryObject* first_item = gInventory.getObject(*selected_uuids.begin());
+    if (!first_item)
+    {
+        return;
+    }
+
+    inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids);
+    gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
+
+}
+
 ///----------------------------------------------------------------------------
 /// LLInventoryCollectFunctor implementations
 ///----------------------------------------------------------------------------
@@ -2522,6 +2602,81 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
     {
         (new LLDirPickerThread(boost::bind(&LLInventoryAction::saveMultipleTextures, _1, selected_items, model), std::string()))->getFile();
     }
+    else if ("new_folder_from_selected" == action)
+    {
+
+        LLInventoryObject* first_item = gInventory.getObject(*ids.begin());
+        if (!first_item)
+        {
+            return;
+        }
+        const LLUUID& parent_uuid = first_item->getParentUUID();
+        for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
+        {
+            LLInventoryObject *item = gInventory.getObject(*it);
+            if (!item || item->getParentUUID() != parent_uuid)
+            {
+                LLNotificationsUtil::add("SameFolderRequired");
+                return;
+            }
+        }
+        
+        LLSD args;
+        args["DESC"] = LLTrans::getString("New Folder");
+ 
+        LLNotificationsUtil::add("CreateSubfolder", args, LLSD(),
+            [ids](const LLSD& notification, const LLSD& response)
+        {
+            S32 opt = LLNotificationsUtil::getSelectedOption(notification, response);
+            if (opt == 0)
+            {
+                std::string settings_name = response["message"].asString();
+
+                LLInventoryObject::correctInventoryName(settings_name);
+                if (settings_name.empty())
+                {
+                    settings_name = LLTrans::getString("New Folder");
+                }
+                move_items_to_new_subfolder(ids, settings_name);
+            }
+        });
+    }
+    else if ("ungroup_folder_items" == action)
+    {
+        if (selected_uuid_set.size() == 1)
+        {
+            LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());
+            if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+            {
+                return;
+            }
+            const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
+            LLInventoryModel::cat_array_t* cat_array;
+            LLInventoryModel::item_array_t* item_array;
+            gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
+            LLInventoryModel::cat_array_t cats = *cat_array;
+            LLInventoryModel::item_array_t items = *item_array;
+
+            for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
+            {
+                LLViewerInventoryCategory* cat = *cat_iter;
+                if (cat)
+                {
+                    gInventory.changeCategoryParent(cat, new_cat_uuid, false);
+                }
+            }
+            for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
+            {
+                LLViewerInventoryItem* item = *item_iter;
+                if(item)
+                {
+                    gInventory.changeItemParent(item, new_cat_uuid, false);
+                }
+            }
+            gInventory.removeCategory(inv_cat->getUUID());
+            gInventory.notifyObservers();
+        }
+    }
     else
     {
         std::set<LLFolderViewItem*>::iterator set_iter;
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 8915bfa1e050d26f224a88dc8b883ab6e83a4b68..ba9f157e47ba97b389c9a51d14a49c87d3a5fc36 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -93,6 +93,10 @@ LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
 S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
 
 void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id);
+void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name);
+void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids);
+bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
+bool is_only_items_selected(const uuid_vec_t& selected_uuids);
 
 /**                    Miscellaneous global functions
  **                                                                            **
diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp
index 12bb609df8c5cc4c1776ffd5861407415419912f..de6a850b5705ad221a8ec77c9db95e42c71075e2 100644
--- a/indra/newview/llinventorylistitem.cpp
+++ b/indra/newview/llinventorylistitem.cpp
@@ -298,31 +298,41 @@ LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem
 	applyXUILayout(icon_params, this);
 
 	mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
-	if (mIconCtrl)
-	{
-		addChild(mIconCtrl);
-	}
-	else
+    if (!mIconCtrl)
 	{
 		LLIconCtrl::Params icon_params;
 		icon_params.name = "item_icon";
 		mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
 	}
 
+    if (mIconCtrl)
+    {
+        addChild(mIconCtrl);
+    }
+    else
+    {
+        LL_ERRS() << "Failed to create mIconCtrl" << LL_ENDL;
+    }
+
 	LLTextBox::Params text_params(params.item_name);
 	applyXUILayout(text_params, this);
 
 	mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params);
-	if (mTitleCtrl)
+	if (!mTitleCtrl)
 	{
-		addChild(mTitleCtrl);
-	}
-	else
-	{
-		LLTextBox::Params text_aprams;
+		LLTextBox::Params text_params;
 		text_params.name = "item_title";
 		mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params);
 	}
+
+    if (mTitleCtrl)
+    {
+        addChild(mTitleCtrl);
+    }
+    else
+    {
+        LL_ERRS() << "Failed to create mTitleCtrl" << LL_ENDL;
+    }
 }
 
 class WidgetVisibilityChanger
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
index d5ee7efdc640cfa5c90028c5e8b8f7fd8d823986..def5a6bd6ed44090e3c5b8dff4e2941fe6a8b8c7 100644
--- a/indra/newview/lllocalbitmaps.h
+++ b/indra/newview/lllocalbitmaps.h
@@ -122,7 +122,7 @@ class LLLocalBitmapMgr : public LLSingleton<LLLocalBitmapMgr>
 	LLUUID       getWorldID(LLUUID tracking_id);
     bool         isLocal(LLUUID world_id);
 	std::string  getFilename(LLUUID tracking_id);
-
+    
 	void         feedScrollList(LLScrollListCtrl* ctrl);
 	void         doUpdates();
 	void         setNeedsRebake();
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 7956967fd076f55de6f59a4b3bc975a5d85ce78c..3401587450bb6ccfc43a17fbac945c9fb35cc44a 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -816,8 +816,10 @@ void LLModelPreview::clearIncompatible(S32 lod)
     // at this point we don't care about sub-models,
     // different amount of sub-models means face count mismatch, not incompatibility
     U32 lod_size = countRootModels(mModel[lod]);
+    bool replaced_base_model = (lod == LLModel::LOD_HIGH);
     for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
-    { //clear out any entries that aren't compatible with this model
+    {
+        // Clear out any entries that aren't compatible with this model
         if (i != lod)
         {
             if (countRootModels(mModel[i]) != lod_size)
@@ -831,9 +833,47 @@ void LLModelPreview::clearIncompatible(S32 lod)
                     mBaseModel = mModel[lod];
                     mBaseScene = mScene[lod];
                     mVertexBuffer[5].clear();
+                    replaced_base_model = true;
+                }
+            }
+        }
+    }
+
+    if (replaced_base_model && !mGenLOD)
+    {
+        // In case base was replaced, we might need to restart generation
+
+        // Check if already started
+        bool subscribe_for_generation = mLodsQuery.empty();
+        
+        // Remove previously scheduled work
+        mLodsQuery.clear();
+
+        LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
+        if (!fmp) return;
+
+        // Schedule new work
+        for (S32 i = LLModel::LOD_HIGH; i >= 0; --i)
+        {
+            if (mModel[i].empty())
+            {
+                // Base model was replaced, regenerate this lod if applicable
+                LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[i]);
+                if (!lod_combo) return;
+
+                S32 lod_mode = lod_combo->getCurrentIndex();
+                if (lod_mode != LOD_FROM_FILE)
+                {
+                    mLodsQuery.push_back(i);
                 }
             }
         }
+
+        // Subscribe if we have pending work and not subscribed yet
+        if (!mLodsQuery.empty() && subscribe_for_generation)
+        {
+            doOnIdleRepeating(lodQueryCallback);
+        }
     }
 }
 
@@ -1221,8 +1261,9 @@ void LLModelPreview::restoreNormals()
 // Runs per object, but likely it is a better way to run per model+submodels
 // returns a ratio of base model indices to resulting indices
 // returns -1 in case of failure
-F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy)
+F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode)
 {
+    // I. Weld faces together
     // Figure out buffer size
     S32 size_indices = 0;
     S32 size_vertices = 0;
@@ -1257,20 +1298,21 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     {
         const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
 
-        // vertices
+        // Vertices
         S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
         LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes);
 
-        // normals
+        // Normals
         LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
 
-        // tex coords
+        // Tex coords
         copy_bytes = face.mNumVertices * sizeof(LLVector2);
         memcpy((void*)(combined_tex_coords + combined_positions_shift), (void*)face.mTexCoords, copy_bytes);
 
         combined_positions_shift += face.mNumVertices;
 
-        // indices, sadly can't do dumb memcpy for indices, need to adjust each value
+        // Indices
+        // Sadly can't do dumb memcpy for indices, need to adjust each value
         for (S32 i = 0; i < face.mNumIndices; ++i)
         {
             U16 idx = face.mIndices[i];
@@ -1281,10 +1323,42 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
         indices_idx_shift += face.mNumVertices;
     }
 
-    // Now that we have buffers, optimize
+    // II. Generate a shadow buffer if nessesary.
+    // Welds together vertices if possible
+
+    U32* shadow_indices = NULL;
+    // if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32
+    // won't do anything new, model was remaped on a per face basis.
+    // Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
+    // since 'simplifySloppy' ignores all topology, including normals and uvs.
+    // Note: simplifySloppy can affect UVs significantly.
+    if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS)
+    {
+        // strip normals, reflections should restore relatively correctly
+        shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+        LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, combined_tex_coords, size_vertices);
+    }
+    if (simplification_mode == MESH_OPTIMIZER_NO_UVS)
+    {
+        // strip uvs, can heavily affect textures
+        shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
+        LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, NULL, size_vertices);
+    }
+
+    U32* source_indices = NULL;
+    if (shadow_indices)
+    {
+        source_indices = shadow_indices;
+    }
+    else
+    {
+        source_indices = combined_indices;
+    }
+
+    // III. Simplify
     S32 target_indices = 0;
     F32 result_error = 0; // how far from original the model is, 1 == 100%
-    S32 new_indices = 0;
+    S32 size_new_indices = 0;
 
     if (indices_decimator > 0)
     {
@@ -1294,38 +1368,43 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     {
         target_indices = 3;
     }
-    new_indices = LLMeshOptimizer::simplifyU32(
+
+    size_new_indices = LLMeshOptimizer::simplifyU32(
         output_indices,
-        combined_indices,
+        source_indices,
         size_indices,
         combined_positions,
         size_vertices,
         LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
         target_indices,
         error_threshold,
-        sloppy,
+        simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY,
         &result_error);
 
-
     if (result_error < 0)
     {
         LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel
             << " target Indices: " << target_indices
-            << " new Indices: " << new_indices
+            << " new Indices: " << size_new_indices
             << " original count: " << size_indices << LL_ENDL;
     }
 
-    if (new_indices < 3)
+    // free unused buffers
+    ll_aligned_free_32(combined_indices);
+    ll_aligned_free_32(shadow_indices);
+    combined_indices = NULL;
+    shadow_indices = NULL;
+
+    if (size_new_indices < 3)
     {
         // Model should have at least one visible triangle
         ll_aligned_free<64>(combined_positions);
         ll_aligned_free_32(output_indices);
-        ll_aligned_free_32(combined_indices);
 
         return -1;
     }
 
-    // repack back into individual faces
+    // IV. Repack back into individual faces
 
     LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
     LLVector4a* buffer_normals = buffer_positions + size_vertices;
@@ -1356,7 +1435,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
         }
 
         // Copy relevant indices and vertices
-        for (S32 i = 0; i < new_indices; ++i)
+        for (S32 i = 0; i < size_new_indices; ++i)
         {
             U32 idx = output_indices[i];
 
@@ -1379,19 +1458,19 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
                         LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for"
                             << " model " << target_model->mLabel
                             << " target Indices: " << target_indices
-                            << " new Indices: " << new_indices
+                            << " new Indices: " << size_new_indices
                             << " original count: " << size_indices
                             << " error treshold: " << error_threshold
                             << LL_ENDL;
 
                         // U16 vertices overflow shouldn't happen, but just in case
-                        new_indices = 0;
+                        size_new_indices = 0;
                         valid_faces = 0;
                         for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
                         {
-                            genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, false);
+                            genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, simplification_mode);
                             const LLVolumeFace &face = target_model->getVolumeFace(face_idx);
-                            new_indices += face.mNumIndices;
+                            size_new_indices += face.mNumIndices;
                             if (face.mNumIndices >= 3)
                             {
                                 valid_faces++;
@@ -1399,7 +1478,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
                         }
                         if (valid_faces)
                         {
-                            return (F32)size_indices / (F32)new_indices;
+                            return (F32)size_indices / (F32)size_new_indices;
                         }
                         else
                         {
@@ -1469,18 +1548,17 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
     ll_aligned_free<64>(buffer_positions);
     ll_aligned_free_32(output_indices);
     ll_aligned_free_16(buffer_indices);
-    ll_aligned_free_32(combined_indices);
 
-    if (new_indices < 3 || valid_faces == 0)
+    if (size_new_indices < 3 || valid_faces == 0)
     {
         // Model should have at least one visible triangle
         return -1;
     }
 
-    return (F32)size_indices / (F32)new_indices;
+    return (F32)size_indices / (F32)size_new_indices;
 }
 
-F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, bool sloppy)
+F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode)
 {
     const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
     S32 size_indices = face.mNumIndices;
@@ -1488,14 +1566,40 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
     {
         return -1;
     }
-    // todo: do not allocate per each face, add one large buffer somewhere
-    // faces have limited amount of indices
+
     S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
-    U16* output = (U16*)ll_aligned_malloc_16(size);
+    U16* output_indices = (U16*)ll_aligned_malloc_16(size);
+
+    U16* shadow_indices = NULL;
+    // if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32
+    // won't do anything new, model was remaped on a per face basis.
+    // Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
+    // since 'simplifySloppy' ignores all topology, including normals and uvs.
+    if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS)
+    {
+        U16* shadow_indices = (U16*)ll_aligned_malloc_16(size);
+        LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, face.mTexCoords, face.mNumVertices);
+    }
+    if (simplification_mode == MESH_OPTIMIZER_NO_UVS)
+    {
+        U16* shadow_indices = (U16*)ll_aligned_malloc_16(size);
+        LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, NULL, face.mNumVertices);
+    }
+    // Don't run ShadowIndexBuffer for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
+
+    U16* source_indices = NULL;
+    if (shadow_indices)
+    {
+        source_indices = shadow_indices;
+    }
+    else
+    {
+        source_indices = face.mIndices;
+    }
 
     S32 target_indices = 0;
     F32 result_error = 0; // how far from original the model is, 1 == 100%
-    S32 new_indices = 0;
+    S32 size_new_indices = 0;
 
     if (indices_decimator > 0)
     {
@@ -1505,25 +1609,25 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
     {
         target_indices = 3;
     }
-    new_indices = LLMeshOptimizer::simplify(
-        output,
-        face.mIndices,
+
+    size_new_indices = LLMeshOptimizer::simplify(
+        output_indices,
+        source_indices,
         size_indices,
         face.mPositions,
         face.mNumVertices,
         LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
         target_indices,
         error_threshold,
-        sloppy,
+        simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY,
         &result_error);
 
-
     if (result_error < 0)
     {
         LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx
             << " of model " << target_model->mLabel
             << " target Indices: " << target_indices
-            << " new Indices: " << new_indices
+            << " new Indices: " << size_new_indices
             << " original count: " << size_indices
             << " error treshold: " << error_threshold
             << LL_ENDL;
@@ -1534,10 +1638,9 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
     // Copy old values
     new_face = face;
 
-
-    if (new_indices < 3)
+    if (size_new_indices < 3)
     {
-        if (!sloppy)
+        if (simplification_mode != MESH_OPTIMIZER_NO_TOPOLOGY)
         {
             // meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2,
             // but optimize() isn't supposed to
@@ -1561,23 +1664,24 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
     else
     {
         // Assign new values
-        new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
-        S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
-        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
+        new_face.resizeIndices(size_new_indices); // will wipe out mIndices, so new_face can't substitute output
+        S32 idx_size = (size_new_indices * sizeof(U16) + 0xF) & ~0xF;
+        LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output_indices, idx_size);
 
-        // clear unused values
+        // Clear unused values
         new_face.optimize();
     }
 
-    ll_aligned_free_16(output);
+    ll_aligned_free_16(output_indices);
+    ll_aligned_free_16(shadow_indices);
      
-    if (new_indices < 3)
+    if (size_new_indices < 3)
     {
         // At least one triangle is needed
         return -1;
     }
 
-    return (F32)size_indices / (F32)new_indices;
+    return (F32)size_indices / (F32)size_new_indices;
 }
 
 void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit)
@@ -1711,16 +1815,19 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
 
             // Ideally this should run not per model,
             // but combine all submodels with origin model as well
-            if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE)
+            if (model_meshopt_mode == MESH_OPTIMIZER_PRECISE)
             {
-                // Run meshoptimizer for each model/object, up to 8 faces in one model.
-
-                // Ideally this should run not per model,
-                // but combine all submodels with origin model as well
-                F32 res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
-                if (res < 0)
+                // Run meshoptimizer for each face
+                for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    target_model->copyVolumeFaces(base);
+                    F32 res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
+                    if (res < 0)
+                    {
+                        // Mesh optimizer failed and returned an invalid model
+                        const LLVolumeFace &face = base->getVolumeFace(face_idx);
+                        LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
+                        new_face = face;
+                    }
                 }
             }
 
@@ -1729,19 +1836,29 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                 // Run meshoptimizer for each face
                 for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
                 {
-                    if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0)
+                    if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY) < 0)
                     {
                         // Sloppy failed and returned an invalid model
-                        genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+                        genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
                     }
                 }
             }
 
             if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
             {
-                // Switches between 'combine' method and 'sloppy' based on combine's result.
-                F32 allowed_ratio_drift = 2.f;
-                F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+                // Remove progressively more data if we can't reach the target.
+                F32 allowed_ratio_drift = 1.8f;
+                F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
+
+                if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
+                {
+                    precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_NORMALS);
+                }
+
+                if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
+                {
+                    precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_UVS);
+                }
                 
                 if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
                 {
@@ -1749,10 +1866,11 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                     // Sloppy variant can fail entirely and has issues with precision,
                     // so code needs to do multiple attempts with different decimators.
                     // Todo: this is a bit of a mess, needs to be refined and improved
+
                     F32 last_working_decimator = 0.f;
                     F32 last_working_ratio = F32_MAX;
 
-                    F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+                    F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
 
                     if (sloppy_ratio > 0)
                     {
@@ -1775,13 +1893,13 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                         // side due to overal lack of precision, and we don't need an ideal result, which
                         // likely does not exist, just a better one, so a partial correction is enough.
                         F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2;
-                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
                     }
 
                     if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio)
                     {
                         // Compensation didn't work, return back to previous decimator
-                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
                     }
 
                     if (sloppy_ratio < 0)
@@ -1814,7 +1932,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                                 && sloppy_decimator > precise_ratio
                                 && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case
                             {
-                                sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+                                sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
                                 sloppy_decimator = sloppy_decimator / sloppy_decimation_step;
                             }
                         }
@@ -1834,7 +1952,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
                         else
                         {
                             // Fallback to normal method
-                            precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+                            precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
                         }
 
                         LL_INFOS() << "Model " << target_model->getName()
@@ -3784,7 +3902,7 @@ bool LLModelPreview::lodQueryCallback()
             }
 
             // return false to continue cycle
-            return false;
+            return preview->mLodsQuery.empty();
         }
     }
     // nothing to process
diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h
index feff019ccef281836ebaadfd069409bf9658dfda..7cb5fd68457ee9129047a27318cba1bc4e0346e6 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -125,7 +125,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     {
         LOD_FROM_FILE = 0,
         MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
-        MESH_OPTIMIZER_COMBINE, // combines faces into a single model, simplifies, then splits back into faces
+        MESH_OPTIMIZER_PRECISE, // combines faces into a single model, simplifies, then splits back into faces
         MESH_OPTIMIZER_SLOPPY, // uses sloppy method, works per face
         USE_LOD_ABOVE,
     } eLoDMode;
@@ -227,13 +227,21 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     LLVector3   mGroundPlane[4];
 	void		renderGroundPlane(float z_offset = 0.0f);
 
+    typedef enum
+    {
+        MESH_OPTIMIZER_FULL,
+        MESH_OPTIMIZER_NO_NORMALS,
+        MESH_OPTIMIZER_NO_UVS,
+        MESH_OPTIMIZER_NO_TOPOLOGY,
+    } eSimplificationMode;
+
     // Merges faces into single mesh, simplifies using mesh optimizer,
     // then splits back into faces.
     // Returns reached simplification ratio. -1 in case of a failure.
-    F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy);
+    F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);
     // Simplifies specified face using mesh optimizer.
     // Returns reached simplification ratio. -1 in case of a failure.
-    F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy);
+    F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);
 
 protected:
     friend class LLModelLoader;
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index 3322e8a3df435c58e87c5e076aa9cf06643a7e05..3a4fc613b7b08037d4ccaba0a37bc39c9f90ffce 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -232,7 +232,7 @@ void LLPanelBlockedList::onFilterEdit(const std::string& search_string)
 void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
 {
 	if (names.empty() || ids.empty()) return;
-	LLMute mute(ids[0], names[0].getAccountName(), LLMute::AGENT);
+    LLMute mute(ids[0], names[0].getUserName(), LLMute::AGENT);
 	LLMuteList::getInstance()->add(mute);
 	showPanelAndSelect(mute.mID);
 }
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index be11a4a9f3ad285df567eb4a4de9d3e4187b0434..6e897e2c7ece4ed752bee18933aeacc07a88d8cc 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1308,7 +1308,8 @@ void LLPanelEditWearable::changeCamera(U8 subpart)
         gMorphView->setCameraOffset( subpart_entry->mCameraOffset );
         if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
         {
-                gMorphView->updateCamera();
+            gAgentCamera.setFocusOnAvatar(FALSE, FALSE);
+            gMorphView->updateCamera();
         }
 }
 
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 8e7d4a2d115aadffb7304132fe1322662888a280..de1a84e0f1f4d987a7f6a61a599521950e8d75a3 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -38,6 +38,7 @@
 #include "llfontgl.h"
 
 // project includes
+#include "llagent.h"
 #include "llagentdata.h"
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
@@ -45,12 +46,16 @@
 #include "llcombobox.h"
 #include "lldrawpoolbump.h"
 #include "llface.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h" // gInventory
+#include "llinventorymodelbackgroundfetch.h"
 #include "llfloatermediasettings.h"
 #include "llfloaterreg.h"
 #include "lllineeditor.h"
 #include "llmaterialmgr.h"
 #include "llmediactrl.h"
 #include "llmediaentry.h"
+#include "llmenubutton.h"
 #include "llnotificationsutil.h"
 #include "llpanelcontents.h"
 #include "llradiogroup.h"
@@ -61,6 +66,8 @@
 #include "lltexturectrl.h"
 #include "lltextureentry.h"
 #include "lltooldraganddrop.h"
+#include "lltoolface.h"
+#include "lltoolmgr.h"
 #include "lltrans.h"
 #include "llui.h"
 #include "llviewercontrol.h"
@@ -303,6 +310,9 @@ BOOL	LLPanelFace::postBuild()
 		mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this);
 	}
 
+    mMenuClipboardColor = getChild<LLMenuButton>("clipboard_color_params_btn");
+    mMenuClipboardTexture = getChild<LLMenuButton>("clipboard_texture_params_btn");
+    
     mTitleMedia = getChild<LLMediaCtrl>("title_media");
     mTitleMediaText = getChild<LLTextBox>("media_info");
 
@@ -319,7 +329,9 @@ LLPanelFace::LLPanelFace()
     mTitleMediaText(NULL),
     mNeedMediaTitle(true)
 {
-	USE_TEXTURE = LLTrans::getString("use_texture");
+    USE_TEXTURE = LLTrans::getString("use_texture");
+    mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2));
+    mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2));
 }
 
 
@@ -329,6 +341,13 @@ LLPanelFace::~LLPanelFace()
 }
 
 
+void LLPanelFace::draw()
+{
+    updateCopyTexButton();
+
+    LLPanel::draw();
+}
+
 void LLPanelFace::sendTexture()
 {
 	LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("texture control");
@@ -1516,6 +1535,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				}
 			}
 		}
+        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+        BOOL single_volume = (selected_count == 1);
+        mMenuClipboardColor->setEnabled(editable && single_volume);
 
 		// Set variable values for numeric expressions
 		LLCalc* calcp = LLCalc::getInstance();
@@ -1576,6 +1598,17 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 }
 
 
+void LLPanelFace::updateCopyTexButton()
+{
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    mMenuClipboardTexture->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify() 
+                                                    && !objectp->isPermanentEnforced() && !objectp->isInventoryPending() 
+                                                    && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1));
+    std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");
+    mMenuClipboardTexture->setToolTip(tooltip);
+
+}
+
 void LLPanelFace::refresh()
 {
 	LL_DEBUGS("Materials") << LL_ENDL;
@@ -3373,6 +3406,819 @@ void LLPanelFace::onAlignTexture(void* userdata)
     self->alignTestureLayer();
 }
 
+enum EPasteMode
+{
+    PASTE_COLOR,
+    PASTE_TEXTURE
+};
+
+struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor
+{
+    LLPanelFacePasteTexFunctor(LLPanelFace* panel, EPasteMode mode) :
+        mPanelFace(panel), mMode(mode) {}
+
+    virtual bool apply(LLViewerObject* objectp, S32 te)
+    {
+        switch (mMode)
+        {
+        case PASTE_COLOR:
+            mPanelFace->onPasteColor(objectp, te);
+            break;
+        case PASTE_TEXTURE:
+            mPanelFace->onPasteTexture(objectp, te);
+            break;
+        }
+        return true;
+    }
+private:
+    LLPanelFace *mPanelFace;
+    EPasteMode mMode;
+};
+
+struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor
+{
+    LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {}
+    virtual bool apply(LLViewerObject* object)
+    {
+        object->sendTEUpdate();
+        if (mUpdateMedia)
+        {
+            LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
+            if (vo && vo->hasMedia())
+            {
+                vo->sendMediaDataUpdate();
+            }
+        }
+        return true;
+    }
+private:
+    bool mUpdateMedia;
+};
+
+struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor
+{
+    virtual bool apply(LLViewerObject* objectp, S32 te)
+    {
+        if (objectp && objectp->getTE(te))
+        {
+            LLTextureEntry* tep = objectp->getTE(te);
+            const LLMediaEntry *media_data = tep->getMediaData();
+            if (media_data)
+            {
+                if (media_data->getCurrentURL().empty() && media_data->getAutoPlay())
+                {
+                    viewer_media_t media_impl =
+                        LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID());
+                    if (media_impl)
+                    {
+                        media_impl->navigateHome();
+                    }
+                }
+            }
+        }
+        return true;
+    }
+};
+
+void LLPanelFace::onCopyColor()
+{
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        return;
+    }
+
+    if (mClipboardParams.has("color"))
+    {
+        mClipboardParams["color"].clear();
+    }
+    else
+    {
+        mClipboardParams["color"] = LLSD::emptyArray();
+    }
+
+    std::map<LLUUID, LLUUID> asset_item_map;
+
+    // a way to resolve situations where source and target have different amount of faces
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool());
+    for (S32 te = 0; te < num_tes; ++te)
+    {
+        if (node->isTESelected(te))
+        {
+            LLTextureEntry* tep = objectp->getTE(te);
+            if (tep)
+            {
+                LLSD te_data;
+
+                // asLLSD() includes media
+                te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow
+
+                mClipboardParams["color"].append(te_data);
+            }
+        }
+    }
+}
+
+void LLPanelFace::onPasteColor()
+{
+    if (!mClipboardParams.has("color"))
+    {
+        return;
+    }
+
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        // not supposed to happen
+        LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL;
+        return;
+    }
+
+    bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+    LLSD &clipboard = mClipboardParams["color"]; // array
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    S32 compare_tes = num_tes;
+
+    if (face_selection_mode)
+    {
+        compare_tes = 0;
+        for (S32 te = 0; te < num_tes; ++te)
+        {
+            if (node->isTESelected(te))
+            {
+                compare_tes++;
+            }
+        }
+    }
+
+    // we can copy if single face was copied in edit face mode or if face count matches
+    if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean())
+        && compare_tes != clipboard.size())
+    {
+        LLSD notif_args;
+        if (face_selection_mode)
+        {
+            static std::string reason = getString("paste_error_face_selection_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        else
+        {
+            static std::string reason = getString("paste_error_object_face_count_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        LLNotificationsUtil::add("FacePasteFailed", notif_args);
+        return;
+    }
+
+    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+
+    LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR);
+    selected_objects->applyToTEs(&paste_func);
+
+    LLPanelFaceUpdateFunctor sendfunc(false);
+    selected_objects->applyToObjects(&sendfunc);
+}
+
+void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te)
+{
+    LLSD te_data;
+    LLSD &clipboard = mClipboardParams["color"]; // array
+    if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean())
+    {
+        te_data = *(clipboard.beginArray());
+    }
+    else if (clipboard[te])
+    {
+        te_data = clipboard[te];
+    }
+    else
+    {
+        return;
+    }
+
+    LLTextureEntry* tep = objectp->getTE(te);
+    if (tep)
+    {
+        if (te_data.has("te"))
+        {
+            // Color / Alpha
+            if (te_data["te"].has("colors"))
+            {
+                LLColor4 color = tep->getColor();
+
+                LLColor4 clip_color;
+                clip_color.setValue(te_data["te"]["colors"]);
+
+                // Color
+                color.mV[VRED] = clip_color.mV[VRED];
+                color.mV[VGREEN] = clip_color.mV[VGREEN];
+                color.mV[VBLUE] = clip_color.mV[VBLUE];
+
+                // Alpha
+                color.mV[VALPHA] = clip_color.mV[VALPHA];
+
+                objectp->setTEColor(te, color);
+            }
+
+            // Color/fullbright
+            if (te_data["te"].has("fullbright"))
+            {
+                objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger());
+            }
+
+            // Glow
+            if (te_data["te"].has("glow"))
+            {
+                objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal());
+            }
+        }
+    }
+}
+
+void LLPanelFace::onCopyTexture()
+{
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        return;
+    }
+
+    if (mClipboardParams.has("texture"))
+    {
+        mClipboardParams["texture"].clear();
+    }
+    else
+    {
+        mClipboardParams["texture"] = LLSD::emptyArray();
+    }
+
+    std::map<LLUUID, LLUUID> asset_item_map;
+
+    // a way to resolve situations where source and target have different amount of faces
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool());
+    for (S32 te = 0; te < num_tes; ++te)
+    {
+        if (node->isTESelected(te))
+        {
+            LLTextureEntry* tep = objectp->getTE(te);
+            if (tep)
+            {
+                LLSD te_data;
+
+                // asLLSD() includes media
+                te_data["te"] = tep->asLLSD();
+                te_data["te"]["shiny"] = tep->getShiny();
+                te_data["te"]["bumpmap"] = tep->getBumpmap();
+                te_data["te"]["bumpshiny"] = tep->getBumpShiny();
+                te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright();
+
+                if (te_data["te"].has("imageid"))
+                {
+                    LLUUID item_id;
+                    LLUUID id = te_data["te"]["imageid"].asUUID();
+                    bool from_library = get_is_predefined_texture(id);
+                    bool full_perm = from_library;
+
+                    if (!full_perm
+                        && objectp->permCopy()
+                        && objectp->permTransfer()
+                        && objectp->permModify())
+                    {
+                        // If agent created this object and nothing is limiting permissions, mark as full perm
+                        // If agent was granted permission to edit objects owned and created by somebody else, mark full perm
+                        // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive
+                        std::string creator_app_link;
+                        LLUUID creator_id;
+                        LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link);
+                        full_perm = objectp->mOwnerID == creator_id;
+                    }
+
+                    if (id.notNull() && !full_perm)
+                    {
+                        std::map<LLUUID, LLUUID>::iterator iter = asset_item_map.find(id);
+                        if (iter != asset_item_map.end())
+                        {
+                            item_id = iter->second;
+                        }
+                        else
+                        {
+                            // What this does is simply searches inventory for item with same asset id,
+                            // as result it is Hightly unreliable, leaves little control to user, borderline hack
+                            // but there are little options to preserve permissions - multiple inventory
+                            // items might reference same asset and inventory search is expensive.
+                            bool no_transfer = false;
+                            if (objectp->getInventoryItemByAsset(id))
+                            {
+                                no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm();
+                            }
+                            item_id = get_copy_free_item_by_asset_id(id, no_transfer);
+                            // record value to avoid repeating inventory search when possible
+                            asset_item_map[id] = item_id;
+                        }
+                    }
+
+                    if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID()))
+                    {
+                        full_perm = true;
+                        from_library = true;
+                    }
+
+                    {
+                        te_data["te"]["itemfullperm"] = full_perm;
+                        te_data["te"]["fromlibrary"] = from_library; 
+
+                        // If full permission object, texture is free to copy,
+                        // but otherwise we need to check inventory and extract permissions
+                        //
+                        // Normally we care only about restrictions for current user and objects
+                        // don't inherit any 'next owner' permissions from texture, so there is
+                        // no need to record item id if full_perm==true
+                        if (!full_perm && !from_library && item_id.notNull())
+                        {
+                            LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+                            if (itemp)
+                            {
+                                LLPermissions item_permissions = itemp->getPermissions();
+                                if (item_permissions.allowOperationBy(PERM_COPY,
+                                    gAgent.getID(),
+                                    gAgent.getGroupID()))
+                                {
+                                    te_data["te"]["imageitemid"] = item_id;
+                                    te_data["te"]["itemfullperm"] = itemp->getIsFullPerm();
+                                    if (!itemp->isFinished())
+                                    {
+                                        // needed for dropTextureAllFaces
+                                        LLInventoryModelBackgroundFetch::instance().start(item_id, false);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                LLMaterialPtr material_ptr = tep->getMaterialParams();
+                if (!material_ptr.isNull())
+                {
+                    LLSD mat_data;
+
+                    mat_data["NormMap"] = material_ptr->getNormalID();
+                    mat_data["SpecMap"] = material_ptr->getSpecularID();
+
+                    mat_data["NormRepX"] = material_ptr->getNormalRepeatX();
+                    mat_data["NormRepY"] = material_ptr->getNormalRepeatY();
+                    mat_data["NormOffX"] = material_ptr->getNormalOffsetX();
+                    mat_data["NormOffY"] = material_ptr->getNormalOffsetY();
+                    mat_data["NormRot"] = material_ptr->getNormalRotation();
+
+                    mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX();
+                    mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY();
+                    mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX();
+                    mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY();
+                    mat_data["SpecRot"] = material_ptr->getSpecularRotation();
+
+                    mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue();
+                    mat_data["SpecExp"] = material_ptr->getSpecularLightExponent();
+                    mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity();
+                    mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff();
+                    mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode();
+
+                    // Replace no-copy textures, destination texture will get used instead if available
+                    if (mat_data.has("NormMap"))
+                    {
+                        LLUUID id = mat_data["NormMap"].asUUID();
+                        if (id.notNull() && !get_can_copy_texture(id))
+                        {
+                            mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
+                            mat_data["NormMapNoCopy"] = true;
+                        }
+
+                    }
+                    if (mat_data.has("SpecMap"))
+                    {
+                        LLUUID id = mat_data["SpecMap"].asUUID();
+                        if (id.notNull() && !get_can_copy_texture(id))
+                        {
+                            mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
+                            mat_data["SpecMapNoCopy"] = true;
+                        }
+
+                    }
+
+                    te_data["material"] = mat_data;
+                }
+
+                mClipboardParams["texture"].append(te_data);
+            }
+        }
+    }
+}
+
+void LLPanelFace::onPasteTexture()
+{
+    if (!mClipboardParams.has("texture"))
+    {
+        return;
+    }
+
+    LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+    S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+    if (!objectp || !node
+        || objectp->getPCode() != LL_PCODE_VOLUME
+        || !objectp->permModify()
+        || objectp->isPermanentEnforced()
+        || selected_count > 1)
+    {
+        // not supposed to happen
+        LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL;
+        return;
+    }
+
+    bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+    LLSD &clipboard = mClipboardParams["texture"]; // array
+    S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+    S32 compare_tes = num_tes;
+
+    if (face_selection_mode)
+    {
+        compare_tes = 0;
+        for (S32 te = 0; te < num_tes; ++te)
+        {
+            if (node->isTESelected(te))
+            {
+                compare_tes++;
+            }
+        }
+    }
+
+    // we can copy if single face was copied in edit face mode or if face count matches
+    if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) 
+        && compare_tes != clipboard.size())
+    {
+        LLSD notif_args;
+        if (face_selection_mode)
+        {
+            static std::string reason = getString("paste_error_face_selection_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        else
+        {
+            static std::string reason = getString("paste_error_object_face_count_mismatch");
+            notif_args["REASON"] = reason;
+        }
+        LLNotificationsUtil::add("FacePasteFailed", notif_args);
+        return;
+    }
+
+    bool full_perm_object = true;
+    LLSD::array_const_iterator iter = clipboard.beginArray();
+    LLSD::array_const_iterator end = clipboard.endArray();
+    for (; iter != end; ++iter)
+    {
+        const LLSD& te_data = *iter;
+        if (te_data.has("te") && te_data["te"].has("imageid"))
+        {
+            bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean();
+            full_perm_object &= full_perm;
+            if (!full_perm)
+            {
+                if (te_data["te"].has("imageitemid"))
+                {
+                    LLUUID item_id = te_data["te"]["imageitemid"].asUUID();
+                    if (item_id.notNull())
+                    {
+                        LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+                        if (!itemp)
+                        {
+                            // image might be in object's inventory, but it can be not up to date
+                            LLSD notif_args;
+                            static std::string reason = getString("paste_error_inventory_not_found");
+                            notif_args["REASON"] = reason;
+                            LLNotificationsUtil::add("FacePasteFailed", notif_args);
+                            return;
+                        }
+                    }
+                }
+                else
+                {
+                    // Item was not found on 'copy' stage
+                    // Since this happened at copy, might be better to either show this
+                    // at copy stage or to drop clipboard here
+                    LLSD notif_args;
+                    static std::string reason = getString("paste_error_inventory_not_found");
+                    notif_args["REASON"] = reason;
+                    LLNotificationsUtil::add("FacePasteFailed", notif_args);
+                    return;
+                }
+            }
+        }
+    }
+
+    if (!full_perm_object)
+    {
+        LLNotificationsUtil::add("FacePasteTexturePermissions");
+    }
+
+    LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+
+    LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE);
+    selected_objects->applyToTEs(&paste_func);
+
+    LLPanelFaceUpdateFunctor sendfunc(true);
+    selected_objects->applyToObjects(&sendfunc);
+
+    LLPanelFaceNavigateHomeFunctor navigate_home_func;
+    selected_objects->applyToTEs(&navigate_home_func);
+}
+
+void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
+{
+    LLSD te_data;
+    LLSD &clipboard = mClipboardParams["texture"]; // array
+    if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean())
+    {
+        te_data = *(clipboard.beginArray());
+    }
+    else if (clipboard[te])
+    {
+        te_data = clipboard[te];
+    }
+    else
+    {
+        return;
+    }
+
+    LLTextureEntry* tep = objectp->getTE(te);
+    if (tep)
+    {
+        if (te_data.has("te"))
+        {
+            // Texture
+            bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean();
+            bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean();
+            if (te_data["te"].has("imageid"))
+            {
+                const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id
+                LLViewerInventoryItem* itemp_res = NULL;
+
+                if (te_data["te"].has("imageitemid"))
+                {
+                    LLUUID item_id = te_data["te"]["imageitemid"].asUUID();
+                    if (item_id.notNull())
+                    {
+                        LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+                        if (itemp && itemp->isFinished())
+                        {
+                            // dropTextureAllFaces will fail if incomplete
+                            itemp_res = itemp;
+                        }
+                        else
+                        {
+                            // Theoretically shouldn't happend, but if it does happen, we
+                            // might need to add a notification to user that paste will fail
+                            // since inventory isn't fully loaded
+                            LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL;
+                        }
+                    }
+                }
+                // for case when item got removed from inventory after we pressed 'copy'
+                // or texture got pasted into previous object
+                if (!itemp_res && !full_perm)
+                {
+                    // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable.
+                    LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL;
+                    // Todo: fix this, we are often searching same texture multiple times (equal to number of faces)
+                    // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work
+                    LLViewerInventoryCategory::cat_array_t cats;
+                    LLViewerInventoryItem::item_array_t items;
+                    LLAssetIDMatches asset_id_matches(imageid);
+                    gInventory.collectDescendentsIf(LLUUID::null,
+                        cats,
+                        items,
+                        LLInventoryModel::INCLUDE_TRASH,
+                        asset_id_matches);
+
+                    // Extremely unreliable and perfomance unfriendly.
+                    // But we need this to check permissions and it is how texture control finds items
+                    for (S32 i = 0; i < items.size(); i++)
+                    {
+                        LLViewerInventoryItem* itemp = items[i];
+                        if (itemp && itemp->isFinished())
+                        {
+                            // dropTextureAllFaces will fail if incomplete
+                            LLPermissions item_permissions = itemp->getPermissions();
+                            if (item_permissions.allowOperationBy(PERM_COPY,
+                                gAgent.getID(),
+                                gAgent.getGroupID()))
+                            {
+                                itemp_res = itemp;
+                                break; // first match
+                            }
+                        }
+                    }
+                }
+
+                if (itemp_res)
+                {
+                    if (te == -1) // all faces
+                    {
+                        LLToolDragAndDrop::dropTextureAllFaces(objectp,
+                            itemp_res,
+                            from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+                            LLUUID::null);
+                    }
+                    else // one face
+                    {
+                        LLToolDragAndDrop::dropTextureOneFace(objectp,
+                            te,
+                            itemp_res,
+                            from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+                            LLUUID::null,
+                            0);
+                    }
+                }
+                // not an inventory item or no complete items
+                else if (full_perm)
+                {
+                    // Either library, local or existed as fullperm when user made a copy
+                    LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+                    objectp->setTEImage(U8(te), image);
+                }
+            }
+
+            if (te_data["te"].has("bumpmap"))
+            {
+                objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger());
+            }
+            if (te_data["te"].has("bumpshiny"))
+            {
+                objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger());
+            }
+            if (te_data["te"].has("bumpfullbright"))
+            {
+                objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger());
+            }
+
+            // Texture map
+            if (te_data["te"].has("scales") && te_data["te"].has("scalet"))
+            {
+                objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal());
+            }
+            if (te_data["te"].has("offsets") && te_data["te"].has("offsett"))
+            {
+                objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal());
+            }
+            if (te_data["te"].has("imagerot"))
+            {
+                objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal());
+            }
+
+            // Media
+            if (te_data["te"].has("media_flags"))
+            {
+                U8 media_flags = te_data["te"]["media_flags"].asInteger();
+                objectp->setTEMediaFlags(te, media_flags);
+                LLVOVolume *vo = dynamic_cast<LLVOVolume*>(objectp);
+                if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY))
+                {
+                    vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/);
+                }
+            }
+            else
+            {
+                // Keep media flags on destination unchanged
+            }
+        }
+
+        if (te_data.has("material"))
+        {
+            LLUUID object_id = objectp->getID();
+
+            LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id);
+
+            // Normal
+            // Replace placeholders with target's
+            if (te_data["material"].has("NormMapNoCopy"))
+            {
+                LLMaterialPtr material = tep->getMaterialParams();
+                if (material.notNull())
+                {
+                    LLUUID id = material->getNormalID();
+                    if (id.notNull())
+                    {
+                        te_data["material"]["NormMap"] = id;
+                    }
+                }
+            }
+            LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id);
+            LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id);
+
+            // Specular
+                // Replace placeholders with target's
+            if (te_data["material"].has("SpecMapNoCopy"))
+            {
+                LLMaterialPtr material = tep->getMaterialParams();
+                if (material.notNull())
+                {
+                    LLUUID id = material->getSpecularID();
+                    if (id.notNull())
+                    {
+                        te_data["material"]["SpecMap"] = id;
+                    }
+                }
+            }
+            LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id);
+            LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id);
+            LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id);
+            LLColor4 spec_color(te_data["material"]["SpecColor"]);
+            LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te);
+            LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id);
+            LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id);
+            LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id);
+            if (te_data.has("te") && te_data["te"].has("shiny"))
+            {
+                objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger());
+            }
+        }
+    }
+}
+
+void LLPanelFace::menuDoToSelected(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste
+    if (command == "color_paste")
+    {
+        onPasteColor();
+    }
+    else if (command == "texture_paste")
+    {
+        onPasteTexture();
+    }
+    // copy
+    else if (command == "color_copy")
+    {
+        onCopyColor();
+    }
+    else if (command == "texture_copy")
+    {
+        onCopyTexture();
+    }
+}
+
+bool LLPanelFace::menuEnableItem(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste options
+    if (command == "color_paste")
+    {
+        return mClipboardParams.has("color");
+    }
+    else if (command == "texture_paste")
+    {
+        return mClipboardParams.has("texture");
+    }
+    return false;
+}
+
+
+// TODO: I don't know who put these in or what these are for???
+void LLPanelFace::setMediaURL(const std::string& url)
+{
+}
+void LLPanelFace::setMediaType(const std::string& mime_type)
+{
+}
+
 // static
 void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata)
 {
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 58c66bfdac0d1eef25babed5eb07c2d345a29767..688bdc7278f52d016afc1786be15df247c231528 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -48,6 +48,7 @@ class LLViewerObject;
 class LLFloater;
 class LLMaterialID;
 class LLMediaCtrl;
+class LLMenuButton;
 
 // Represents an edit for use in replicating the op across one or more materials in the selection set.
 //
@@ -97,6 +98,8 @@ class LLPanelFace : public LLPanel
 	LLPanelFace();
 	virtual ~LLPanelFace();
 
+    void draw();
+
 	void			refresh();
     void			refreshMedia();
     void			unloadMedia();
@@ -137,6 +140,8 @@ class LLPanelFace : public LLPanel
 	void			sendMedia();
     void            alignTestureLayer();
 
+    void            updateCopyTexButton();
+
 	// this function is to return TRUE if the drag should succeed.
 	static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item);
 
@@ -220,6 +225,18 @@ class LLPanelFace : public LLPanel
 	static void		onClickAutoFix(void*);
     static void		onAlignTexture(void*);
 
+public: // needs to be accessible to selection manager
+    void            onCopyColor(); // records all selected faces
+    void            onPasteColor(); // to specific face
+    void            onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
+    void            onCopyTexture();
+    void            onPasteTexture();
+    void            onPasteTexture(LLViewerObject* objectp, S32 te);
+
+protected:
+    void            menuDoToSelected(const LLSD& userdata);
+    bool            menuEnableItem(const LLSD& userdata);
+
 	static F32     valueGlow(LLViewerObject* object, S32 face);
 
 	
@@ -415,7 +432,10 @@ class LLPanelFace : public LLPanel
 	 * If agent selects texture which is not allowed to be applied for the currently selected object,
 	 * all controls of the floater texture picker which allow to apply the texture will be disabled.
 	 */
-	void onTextureSelectionChanged(LLInventoryItem* itemp);
+    void onTextureSelectionChanged(LLInventoryItem* itemp);
+
+    LLMenuButton*   mMenuClipboardColor;
+    LLMenuButton*   mMenuClipboardTexture;
 
 	bool mIsAlpha;
 	
@@ -430,7 +450,9 @@ class LLPanelFace : public LLPanel
 	 * up-arrow on a spinner, and avoids running afoul of its throttle.
 	 */
 	bool mUpdateInFlight;
-	bool mUpdatePending;
+    bool mUpdatePending;
+
+    LLSD            mClipboardParams;
 
     LLSD mMediaSettings;
     bool mNeedMediaTitle;
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index a4a668803a221be2367da640597aea820fe50fad..0bfc1297d35b0339d4b1a06dadd81d102e1fc66d 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -46,6 +46,7 @@
 #include "llcombobox.h"
 #include "llfocusmgr.h"
 #include "llmanipscale.h"
+#include "llmenubutton.h"
 #include "llpreviewscript.h"
 #include "llresmgr.h"
 #include "llselectmgr.h"
@@ -117,8 +118,9 @@ BOOL	LLPanelObject::postBuild()
 	// Phantom checkbox
 	mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");
 	childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
-       
+
 	// Position
+	mMenuClipboardPos = getChild<LLMenuButton>("clipboard_pos_btn");
 	mLabelPosition = getChild<LLTextBox>("label position");
 	mCtrlPosX = getChild<LLSpinCtrl>("Pos X");
 	childSetCommitCallback("Pos X",onCommitPosition,this);
@@ -128,6 +130,7 @@ BOOL	LLPanelObject::postBuild()
 	childSetCommitCallback("Pos Z",onCommitPosition,this);
 
 	// Scale
+	mMenuClipboardSize = getChild<LLMenuButton>("clipboard_size_btn");
 	mLabelSize = getChild<LLTextBox>("label size");
 	mCtrlScaleX = getChild<LLSpinCtrl>("Scale X");
 	childSetCommitCallback("Scale X",onCommitScale,this);
@@ -141,6 +144,7 @@ BOOL	LLPanelObject::postBuild()
 	childSetCommitCallback("Scale Z",onCommitScale,this);
 
 	// Rotation
+	mMenuClipboardRot = getChild<LLMenuButton>("clipboard_rot_btn");
 	mLabelRotation = getChild<LLTextBox>("label rotation");
 	mCtrlRotX = getChild<LLSpinCtrl>("Rot X");
 	childSetCommitCallback("Rot X",onCommitRotation,this);
@@ -155,6 +159,8 @@ BOOL	LLPanelObject::postBuild()
 	mComboBaseType = getChild<LLComboBox>("comboBaseType");
 	childSetCommitCallback("comboBaseType",onCommitParametric,this);
 
+	mMenuClipboardParams = getChild<LLMenuButton>("clipboard_obj_params_btn");
+
 	// Cut
 	mLabelCut = getChild<LLTextBox>("text cut");
 	mSpinCutBegin = getChild<LLSpinCtrl>("cut begin");
@@ -285,8 +291,13 @@ LLPanelObject::LLPanelObject()
 	mSelectedType(MI_BOX),
 	mSculptTextureRevert(LLUUID::null),
 	mSculptTypeRevert(0),
+    mHasClipboardPos(false),
+    mHasClipboardSize(false),
+    mHasClipboardRot(false),
 	mSizeChanged(FALSE)
 {
+    mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2));
+    mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2));
 }
 
 
@@ -373,7 +384,7 @@ void LLPanelObject::getState( )
 		calcp->clearVar(LLCalc::Z_POS);
 	}
 
-
+	mMenuClipboardPos->setEnabled(enable_move);
 	mLabelPosition->setEnabled( enable_move );
 	mCtrlPosX->setEnabled(enable_move);
 	mCtrlPosY->setEnabled(enable_move);
@@ -399,6 +410,7 @@ void LLPanelObject::getState( )
 		calcp->setVar(LLCalc::Z_SCALE, 0.f);
 	}
 
+	mMenuClipboardSize->setEnabled(enable_scale);
 	mLabelSize->setEnabled( enable_scale );
 	mCtrlScaleX->setEnabled( enable_scale );
 	mCtrlScaleY->setEnabled( enable_scale );
@@ -430,6 +442,7 @@ void LLPanelObject::getState( )
 		calcp->clearVar(LLCalc::Z_ROT);
 	}
 
+	mMenuClipboardRot->setEnabled(enable_rotate);
 	mLabelRotation->setEnabled( enable_rotate );
 	mCtrlRotX->setEnabled( enable_rotate );
 	mCtrlRotY->setEnabled( enable_rotate );
@@ -607,7 +620,7 @@ void LLPanelObject::getState( )
 		}
 		else
 		{
-			LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;
+			LL_INFOS("FloaterTools") << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;
 			selected_item = MI_BOX;
 		}
 
@@ -933,6 +946,7 @@ void LLPanelObject::getState( )
 
 	// Update field enablement
 	mComboBaseType	->setEnabled( enabled );
+	mMenuClipboardParams->setEnabled(enabled);
 
 	mLabelCut		->setEnabled( enabled );
 	mSpinCutBegin	->setEnabled( enabled );
@@ -1093,7 +1107,8 @@ void LLPanelObject::getState( )
 			}
 
 			mComboBaseType->setEnabled(!isMesh);
-			
+			mMenuClipboardParams->setEnabled(!isMesh);
+
 			if (mCtrlSculptType)
 			{
 				if (sculpt_stitching == LL_SCULPT_TYPE_NONE)
@@ -1157,11 +1172,11 @@ void LLPanelObject::sendIsPhysical()
 		LLSelectMgr::getInstance()->selectionUpdatePhysics(value);
 		mIsPhysical = value;
 
-		LL_INFOS() << "update physics sent" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update physics sent" << LL_ENDL;
 	}
 	else
 	{
-		LL_INFOS() << "update physics not changed" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update physics not changed" << LL_ENDL;
 	}
 }
 
@@ -1173,11 +1188,11 @@ void LLPanelObject::sendIsTemporary()
 		LLSelectMgr::getInstance()->selectionUpdateTemporary(value);
 		mIsTemporary = value;
 
-		LL_INFOS() << "update temporary sent" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update temporary sent" << LL_ENDL;
 	}
 	else
 	{
-		LL_INFOS() << "update temporary not changed" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update temporary not changed" << LL_ENDL;
 	}
 }
 
@@ -1190,11 +1205,11 @@ void LLPanelObject::sendIsPhantom()
 		LLSelectMgr::getInstance()->selectionUpdatePhantom(value);
 		mIsPhantom = value;
 
-		LL_INFOS() << "update phantom sent" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update phantom sent" << LL_ENDL;
 	}
 	else
 	{
-		LL_INFOS() << "update phantom not changed" << LL_ENDL;
+		LL_INFOS("FloaterTools") << "update phantom not changed" << LL_ENDL;
 	}
 }
 
@@ -1304,7 +1319,7 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
 		break;
 		
 	default:
-		LL_WARNS() << "Unknown base type " << selected_type 
+		LL_WARNS("FloaterTools") << "Unknown base type " << selected_type 
 			<< " in getVolumeParams()" << LL_ENDL;
 		// assume a box
 		selected_type = MI_BOX;
@@ -1644,6 +1659,8 @@ void LLPanelObject::sendPosition(BOOL btn_down)
 	LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
 	LLViewerRegion* regionp = mObject->getRegion();
 
+	if (!regionp) return;
+
 	if (!mObject->isAttachment())
 	{
         // Clamp the Z height
@@ -2011,3 +2028,283 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata)
 
 	self->sendSculpt();
 }
+
+void LLPanelObject::menuDoToSelected(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste
+    if (command == "psr_paste")
+    {
+        onPastePos();
+        onPasteSize();
+        onPasteRot();
+    }
+    else if (command == "pos_paste")
+    {
+        onPastePos();
+    }
+    else if (command == "size_paste")
+    {
+        onPasteSize();
+    }
+    else if (command == "rot_paste")
+    {
+        onPasteRot();
+    }
+    else if (command == "params_paste")
+    {
+        onPasteParams();
+    }
+    // copy
+    else if (command == "psr_copy")
+    {
+        onCopyPos();
+        onCopySize();
+        onCopyRot();
+    }
+    else if (command == "pos_copy")
+    {
+        onCopyPos();
+    }
+    else if (command == "size_copy")
+    {
+        onCopySize();
+    }
+    else if (command == "rot_copy")
+    {
+        onCopyRot();
+    }
+    else if (command == "params_copy")
+    {
+        onCopyParams();
+    }
+}
+
+bool LLPanelObject::menuEnableItem(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste options
+    if (command == "psr_paste")
+    {
+        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+        BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME))
+            && (selected_count == 1);
+
+        if (!single_volume)
+        {
+            return false;
+        }
+
+        bool enable_move;
+        bool enable_modify;
+
+        LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify);
+
+        return enable_move && enable_modify && mHasClipboardPos && mHasClipboardSize && mHasClipboardRot;
+    }
+    else if (command == "pos_paste")
+    {
+        // assumes that menu won't be active if there is no move permission
+        return mHasClipboardPos;
+    }
+    else if (command == "size_paste")
+    {
+        return mHasClipboardSize;
+    }
+    else if (command == "rot_paste")
+    {
+        return mHasClipboardRot;
+    }
+    else if (command == "params_paste")
+    {
+        return mClipboardParams.isMap() && !mClipboardParams.emptyMap();
+    }
+    // copy options
+    else if (command == "psr_copy")
+    {
+        S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+        BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME))
+            && (selected_count == 1);
+
+        if (!single_volume)
+        {
+            return false;
+        }
+
+        bool enable_move;
+        bool enable_modify;
+
+        LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify);
+
+        // since we forbid seeing values we also should forbid copying them
+        return enable_move && enable_modify;
+    }
+    return false;
+}
+
+void LLPanelObject::onCopyPos()
+{
+    mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
+
+    std::string stringVec = llformat("<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ]);
+    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
+
+    mHasClipboardPos = true;
+}
+
+void LLPanelObject::onCopySize()
+{
+    mClipboardSize = LLVector3(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
+
+    std::string stringVec = llformat("<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ]);
+    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
+
+    mHasClipboardSize = true;
+}
+
+void LLPanelObject::onCopyRot()
+{
+    mClipboardRot = LLVector3(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
+
+    std::string stringVec = llformat("<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ]);
+    LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
+
+    mHasClipboardRot = true;
+}
+
+void LLPanelObject::onPastePos()
+{
+    if (!mHasClipboardPos) return;
+    if (mObject.isNull()) return;
+
+    LLViewerRegion* regionp = mObject->getRegion();
+    if (!regionp) return;
+
+
+    // Clamp pos on non-attachments, just keep the prims within the region
+    if (!mObject->isAttachment())
+    {
+        F32 max_width = regionp->getWidth(); // meters
+        mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], 0.f, max_width);
+        mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], 0.f, max_width);
+        //height will get properly clamped by sendPosition
+    }
+
+    mCtrlPosX->set( mClipboardPos.mV[VX] );
+    mCtrlPosY->set( mClipboardPos.mV[VY] );
+    mCtrlPosZ->set( mClipboardPos.mV[VZ] );
+
+    sendPosition(FALSE);
+}
+
+void LLPanelObject::onPasteSize()
+{
+    if (!mHasClipboardSize) return;
+
+    mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
+    mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
+    mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
+
+    mCtrlScaleX->set(mClipboardSize.mV[VX]);
+    mCtrlScaleY->set(mClipboardSize.mV[VY]);
+    mCtrlScaleZ->set(mClipboardSize.mV[VZ]);
+
+    sendScale(FALSE);
+}
+
+void LLPanelObject::onPasteRot()
+{
+    if (!mHasClipboardRot) return;
+
+    mCtrlRotX->set(mClipboardRot.mV[VX]);
+    mCtrlRotY->set(mClipboardRot.mV[VY]);
+    mCtrlRotZ->set(mClipboardRot.mV[VZ]);
+
+    sendRotation(FALSE);
+}
+
+void LLPanelObject::onCopyParams()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp || objectp->isMesh())
+    {
+        return;
+    }
+
+    mClipboardParams.clear();
+
+    // Parametrics
+    LLVolumeParams params;
+    getVolumeParams(params);
+    mClipboardParams["volume_params"] = params.asLLSD();
+
+    // Sculpted Prim
+    if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
+    {
+        LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+
+        LLUUID texture_id = sculpt_params->getSculptTexture();
+        if (get_can_copy_texture(texture_id))
+        {
+            LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL;
+            mClipboardParams["sculpt"]["id"] = texture_id;
+        }
+        else
+        {
+            mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE);
+        }
+
+        mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType();
+    }
+}
+
+void LLPanelObject::onPasteParams()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp)
+    {
+        return;
+    }
+
+    // Sculpted Prim
+    if (mClipboardParams.has("sculpt"))
+    {
+        LLSculptParams sculpt_params;
+        LLUUID sculpt_id = mClipboardParams["sculpt"]["id"].asUUID();
+        U8 sculpt_type = (U8)mClipboardParams["sculpt"]["type"].asInteger();
+        sculpt_params.setSculptTexture(sculpt_id, sculpt_type);
+        objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
+    }
+    else
+    {
+        LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+        if (sculpt_params)
+        {
+            objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE);
+        }
+    }
+
+    // volume params
+    // make sure updateVolume() won't affect flexible
+    if (mClipboardParams.has("volume_params"))
+    {
+        LLVolumeParams params;
+        params.fromLLSD(mClipboardParams["volume_params"]);
+        LLVOVolume *volobjp = (LLVOVolume *)objectp;
+        if (volobjp->isFlexible())
+        {
+            if (params.getPathParams().getCurveType() == LL_PCODE_PATH_LINE)
+            {
+                params.getPathParams().setCurveType(LL_PCODE_PATH_FLEXIBLE);
+            }
+        }
+        else if (params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
+        {
+            params.getPathParams().setCurveType(LL_PCODE_PATH_LINE);
+        }
+
+        objectp->updateVolume(params);
+    }
+}
diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h
index 8829f493fa73621ecf60224835be0a6496a3779f..515dd27c0a8b313e128af523c90b06be83b1a7a6 100644
--- a/indra/newview/llpanelobject.h
+++ b/indra/newview/llpanelobject.h
@@ -37,6 +37,7 @@ class LLCheckBoxCtrl;
 class LLTextBox;
 class LLUICtrl;
 class LLButton;
+class LLMenuButton;
 class LLViewerObject;
 class LLComboBox;
 class LLColorSwatchCtrl;
@@ -66,6 +67,14 @@ class LLPanelObject : public LLPanel
 	static void 	onCommitPhantom(		LLUICtrl* ctrl, void* userdata);
 	static void 	onCommitPhysics(		LLUICtrl* ctrl, void* userdata);
 
+    void            onCopyPos();
+    void            onPastePos();
+    void            onCopySize();
+    void            onPasteSize();
+    void            onCopyRot();
+    void            onPasteRot();
+    void            onCopyParams();
+    void            onPasteParams();
 	static void 	onCommitParametric(LLUICtrl* ctrl, void* userdata);
 
 
@@ -75,6 +84,9 @@ class LLPanelObject : public LLPanel
 	BOOL     		onDropSculpt(LLInventoryItem* item);
 	static void     onCommitSculptType(    LLUICtrl *ctrl, void* userdata);
 
+    void            menuDoToSelected(const LLSD& userdata);
+    bool            menuEnableItem(const LLSD& userdata);
+
 protected:
 	void			getState();
 
@@ -92,6 +104,7 @@ class LLPanelObject : public LLPanel
 protected:
 	// Per-object options
 	LLComboBox*		mComboBaseType;
+	LLMenuButton*	mMenuClipboardParams;
 
 	LLTextBox*		mLabelCut;
 	LLSpinCtrl*		mSpinCutBegin;
@@ -131,17 +144,20 @@ class LLPanelObject : public LLPanel
 	LLTextBox*		mLabelRevolutions;
 	LLSpinCtrl*		mSpinRevolutions;
 
+	LLMenuButton*   mMenuClipboardPos;
 	LLTextBox*		mLabelPosition;
 	LLSpinCtrl*		mCtrlPosX;
 	LLSpinCtrl*		mCtrlPosY;
 	LLSpinCtrl*		mCtrlPosZ;
 
+	LLMenuButton*   mMenuClipboardSize;
 	LLTextBox*		mLabelSize;
 	LLSpinCtrl*		mCtrlScaleX;
 	LLSpinCtrl*		mCtrlScaleY;
 	LLSpinCtrl*		mCtrlScaleZ;
 	BOOL			mSizeChanged;
 
+	LLMenuButton*   mMenuClipboardRot;
 	LLTextBox*		mLabelRotation;
 	LLSpinCtrl*		mCtrlRotX;
 	LLSpinCtrl*		mCtrlRotY;
@@ -157,7 +173,7 @@ class LLPanelObject : public LLPanel
 	LLComboBox      *mCtrlSculptType;
 	LLCheckBoxCtrl  *mCtrlSculptMirror;
 	LLCheckBoxCtrl  *mCtrlSculptInvert;
-	
+
 	LLVector3		mCurEulerDegrees;		// to avoid sending rotation when not changed
 	BOOL			mIsPhysical;			// to avoid sending "physical" when not changed
 	BOOL			mIsTemporary;			// to avoid sending "temporary" when not changed
@@ -167,6 +183,15 @@ class LLPanelObject : public LLPanel
 	LLUUID          mSculptTextureRevert;   // so we can revert the sculpt texture on cancel
 	U8              mSculptTypeRevert;      // so we can revert the sculpt type on cancel
 
+    LLVector3       mClipboardPos;
+    LLVector3       mClipboardSize;
+    LLVector3       mClipboardRot;
+    LLSD            mClipboardParams;
+
+    bool            mHasClipboardPos;
+    bool            mHasClipboardSize;
+    bool            mHasClipboardRot;
+
 	LLPointer<LLViewerObject> mObject;
 	LLPointer<LLViewerObject> mRootObject;
 };
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 0d987df6caf094b92b7aa4c1f22db823ae09c4d2..cfaa9456be3f1242305981d5e0d477eaafdbcfc0 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -618,7 +618,18 @@ const std::string& LLTaskCategoryBridge::getDisplayName() const
 
 	if (cat)
 	{
-		mDisplayName.assign(cat->getName());
+        std::string name = cat->getName();
+        if (mChildren.size() > 0)
+        {
+            // Add item count
+            // Normally we would be using getLabelSuffix for this
+            // but object's inventory just uses displaynames
+            LLStringUtil::format_map_t args;
+            args["[ITEMS_COUNT]"] = llformat("%d", mChildren.size());
+
+            name.append(" " + LLTrans::getString("InventoryItemsCount", args));
+        }
+		mDisplayName.assign(name);
 	}
 
 	return mDisplayName;
@@ -1522,6 +1533,8 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root
 		{
 			createViewsForCategory(&contents, inventory_root, new_folder);
 		}
+        // Refresh for label to add item count
+        new_folder->refresh();
 	}
 }
 
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 0151eabba90f73048b1dbb40dc66612561e81054..39f4c7485b20d4a3db25632912872b6581bd97ec 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -51,6 +51,7 @@
 #include "llfocusmgr.h"
 #include "llmanipscale.h"
 #include "llinventorymodel.h"
+#include "llmenubutton.h"
 #include "llpreviewscript.h"
 #include "llresmgr.h"
 #include "llselectmgr.h"
@@ -168,6 +169,9 @@ BOOL	LLPanelVolume::postBuild()
 		mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution));
 	}
 
+    mMenuClipboardFeatures = getChild<LLMenuButton>("clipboard_features_params_btn");
+    mMenuClipboardLight = getChild<LLMenuButton>("clipboard_light_params_btn");
+
 	std::map<std::string, std::string> material_name_map;
 	material_name_map["Stone"]= LLTrans::getString("Stone");
 	material_name_map["Metal"]= LLTrans::getString("Metal");	
@@ -208,6 +212,8 @@ LLPanelVolume::LLPanelVolume()
 {
 	setMouseOpaque(FALSE);
 
+    mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2));
+    mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2));
 }
 
 
@@ -409,7 +415,6 @@ void LLPanelVolume::getState( )
 			gAgentAvatarp->updateMeshVisibility();
 		}
 	}
-	
 
 	// Flexible properties
 	BOOL is_flexible = volobjp && volobjp->isFlexible();
@@ -564,6 +569,9 @@ void LLPanelVolume::getState( )
 
 	mObject = objectp;
 	mRootObject = root_objectp;
+
+    mMenuClipboardFeatures->setEnabled(editable && single_volume && volobjp); // Note: physics doesn't need to be limited by single volume
+    mMenuClipboardLight->setEnabled(editable && single_volume && volobjp);
 }
 
 // static
@@ -824,6 +832,290 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data)
 	}
 }
 
+void LLPanelVolume::onCopyFeatures()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp)
+    {
+        return;
+    }
+
+    LLSD clipboard;
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Flexi Prim
+    if (volobjp && volobjp->isFlexible())
+    {
+        LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
+        if (attributes)
+        {
+            clipboard["flex"]["lod"] = attributes->getSimulateLOD();
+            clipboard["flex"]["gav"] = attributes->getGravity();
+            clipboard["flex"]["ten"] = attributes->getTension();
+            clipboard["flex"]["fri"] = attributes->getAirFriction();
+            clipboard["flex"]["sen"] = attributes->getWindSensitivity();
+            LLVector3 force = attributes->getUserForce();
+            clipboard["flex"]["forx"] = force.mV[0];
+            clipboard["flex"]["fory"] = force.mV[1];
+            clipboard["flex"]["forz"] = force.mV[2];
+        }
+    }
+
+    // Physics
+    {
+        clipboard["physics"]["shape"] = objectp->getPhysicsShapeType();
+        clipboard["physics"]["gravity"] = objectp->getPhysicsGravity();
+        clipboard["physics"]["friction"] = objectp->getPhysicsFriction();
+        clipboard["physics"]["density"] = objectp->getPhysicsDensity();
+        clipboard["physics"]["restitution"] = objectp->getPhysicsRestitution();
+
+        U8 material_code = 0;
+        struct f : public LLSelectedTEGetFunctor<U8>
+        {
+            U8 get(LLViewerObject* object, S32 te)
+            {
+                return object->getMaterial();
+            }
+        } func;
+        bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, material_code);
+        // This should always be true since material should be per object.
+        if (material_same)
+        {
+            clipboard["physics"]["material"] = material_code;
+        }
+    }
+
+    mClipboardParams["features"] = clipboard;
+}
+
+void LLPanelVolume::onPasteFeatures()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp && mClipboardParams.has("features"))
+    {
+        return;
+    }
+
+    LLSD &clipboard = mClipboardParams["features"];
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Physics
+    bool is_root = objectp->isRoot();
+
+    // Not sure if phantom should go under physics, but doesn't fit elsewhere
+    BOOL is_phantom = clipboard["is_phantom"].asBoolean() && is_root;
+    LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom);
+
+    BOOL is_physical = clipboard["is_physical"].asBoolean() && is_root;
+    LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical);
+
+    if (clipboard.has("physics"))
+    {
+        objectp->setPhysicsShapeType((U8)clipboard["physics"]["shape"].asInteger());
+        U8 cur_material = objectp->getMaterial();
+        U8 material = (U8)clipboard["physics"]["material"].asInteger() | (cur_material & ~LL_MCODE_MASK);
+
+        objectp->setMaterial(material);
+        objectp->sendMaterialUpdate();
+        objectp->setPhysicsGravity(clipboard["physics"]["gravity"].asReal());
+        objectp->setPhysicsFriction(clipboard["physics"]["friction"].asReal());
+        objectp->setPhysicsDensity(clipboard["physics"]["density"].asReal());
+        objectp->setPhysicsRestitution(clipboard["physics"]["restitution"].asReal());
+        objectp->updateFlags(TRUE);
+    }
+
+    // Flexible
+    bool is_flexible = clipboard.has("flex");
+    if (is_flexible && volobjp->canBeFlexible())
+    {
+        LLVOVolume *volobjp = (LLVOVolume *)objectp;
+        BOOL update_shape = FALSE;
+
+        // do before setParameterEntry or it will think that it is already flexi
+        update_shape = volobjp->setIsFlexible(is_flexible);
+
+        if (objectp->getClickAction() == CLICK_ACTION_SIT)
+        {
+            objectp->setClickAction(CLICK_ACTION_NONE);
+        }
+
+        LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
+        if (attributes)
+        {
+            LLFlexibleObjectData new_attributes;
+            new_attributes = *attributes;
+            new_attributes.setSimulateLOD(clipboard["flex"]["lod"].asInteger());
+            new_attributes.setGravity(clipboard["flex"]["gav"].asReal());
+            new_attributes.setTension(clipboard["flex"]["ten"].asReal());
+            new_attributes.setAirFriction(clipboard["flex"]["fri"].asReal());
+            new_attributes.setWindSensitivity(clipboard["flex"]["sen"].asReal());
+            F32 fx = (F32)clipboard["flex"]["forx"].asReal();
+            F32 fy = (F32)clipboard["flex"]["fory"].asReal();
+            F32 fz = (F32)clipboard["flex"]["forz"].asReal();
+            LLVector3 force(fx, fy, fz);
+            new_attributes.setUserForce(force);
+            objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true);
+        }
+
+        if (update_shape)
+        {
+            mObject->sendShapeUpdate();
+            LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
+        }
+    }
+    else
+    {
+        LLVOVolume *volobjp = (LLVOVolume *)objectp;
+        if (volobjp->setIsFlexible(false))
+        {
+            mObject->sendShapeUpdate();
+            LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
+        }
+    }
+}
+
+void LLPanelVolume::onCopyLight()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp)
+    {
+        return;
+    }
+
+    LLSD clipboard;
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Light Source
+    if (volobjp && volobjp->getIsLight())
+    {
+        clipboard["light"]["intensity"] = volobjp->getLightIntensity();
+        clipboard["light"]["radius"] = volobjp->getLightRadius();
+        clipboard["light"]["falloff"] = volobjp->getLightFalloff();
+        LLColor3 color = volobjp->getLightSRGBColor();
+        clipboard["light"]["r"] = color.mV[0];
+        clipboard["light"]["g"] = color.mV[1];
+        clipboard["light"]["b"] = color.mV[2];
+
+        // Spotlight
+        if (volobjp->isLightSpotlight())
+        {
+            LLUUID id = volobjp->getLightTextureID();
+            if (id.notNull() && get_can_copy_texture(id))
+            {
+                clipboard["spot"]["id"] = id;
+                LLVector3 spot_params = volobjp->getSpotLightParams();
+                clipboard["spot"]["fov"] = spot_params.mV[0];
+                clipboard["spot"]["focus"] = spot_params.mV[1];
+                clipboard["spot"]["ambiance"] = spot_params.mV[2];
+            }
+        }
+    }
+
+    mClipboardParams["light"] = clipboard;
+}
+
+void LLPanelVolume::onPasteLight()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp && mClipboardParams.has("light"))
+    {
+        return;
+    }
+
+    LLSD &clipboard = mClipboardParams["light"];
+
+    LLVOVolume *volobjp = NULL;
+    if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+    {
+        volobjp = (LLVOVolume *)objectp;
+    }
+
+    // Light Source
+    if (volobjp)
+    {
+        if (clipboard.has("light"))
+        {
+            volobjp->setIsLight(TRUE);
+            volobjp->setLightIntensity((F32)clipboard["light"]["intensity"].asReal());
+            volobjp->setLightRadius((F32)clipboard["light"]["radius"].asReal());
+            volobjp->setLightFalloff((F32)clipboard["light"]["falloff"].asReal());
+            F32 r = (F32)clipboard["light"]["r"].asReal();
+            F32 g = (F32)clipboard["light"]["g"].asReal();
+            F32 b = (F32)clipboard["light"]["b"].asReal();
+            volobjp->setLightSRGBColor(LLColor3(r, g, b));
+        }
+        else
+        {
+            volobjp->setIsLight(FALSE);
+        }
+
+        if (clipboard.has("spot"))
+        {
+            volobjp->setLightTextureID(clipboard["spot"]["id"].asUUID());
+            LLVector3 spot_params;
+            spot_params.mV[0] = (F32)clipboard["spot"]["fov"].asReal();
+            spot_params.mV[1] = (F32)clipboard["spot"]["focus"].asReal();
+            spot_params.mV[2] = (F32)clipboard["spot"]["ambiance"].asReal();
+            volobjp->setSpotLightParams(spot_params);
+        }
+    }
+}
+
+void LLPanelVolume::menuDoToSelected(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste
+    if (command == "features_paste")
+    {
+        onPasteFeatures();
+    }
+    else if (command == "light_paste")
+    {
+        onPasteLight();
+    }
+    // copy
+    else if (command == "features_copy")
+    {
+        onCopyFeatures();
+    }
+    else if (command == "light_copy")
+    {
+        onCopyLight();
+    }
+}
+
+bool LLPanelVolume::menuEnableItem(const LLSD& userdata)
+{
+    std::string command = userdata.asString();
+
+    // paste options
+    if (command == "features_paste")
+    {
+        return mClipboardParams.has("features");
+    }
+    else if (command == "light_paste")
+    {
+        return mClipboardParams.has("light");
+    }
+    return false;
+}
+
 // static
 void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata )
 {
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index 6e49ccb742649f769ea61ece67939a302854946a..d9198f36932a17576e7bdb0779eec1d4c4d2c56a 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -37,6 +37,7 @@ class LLCheckBoxCtrl;
 class LLTextBox;
 class LLUICtrl;
 class LLButton;
+class LLMenuButton;
 class LLViewerObject;
 class LLComboBox;
 class LLColorSwatchCtrl;
@@ -76,6 +77,13 @@ class LLPanelVolume : public LLPanel
 
     static void    setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp);
 
+    void            onCopyFeatures();
+    void            onPasteFeatures();
+    void            onCopyLight();
+    void            onPasteLight();
+ 
+    void        menuDoToSelected(const LLSD& userdata);
+    bool        menuEnableItem(const LLSD& userdata);
 
 protected:
 	void			getState();
@@ -123,6 +131,11 @@ class LLPanelVolume : public LLPanel
 	LLSpinCtrl*     mSpinPhysicsFriction;
 	LLSpinCtrl*     mSpinPhysicsDensity;
 	LLSpinCtrl*     mSpinPhysicsRestitution;
+
+    LLMenuButton*   mMenuClipboardFeatures;
+    LLMenuButton*   mMenuClipboardLight;
+
+    LLSD            mClipboardParams;
 };
 
 #endif
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 1c4a56b549a78654afa0ffe93e9fad2f819ce43e..51ee5b615799b880645d9dd43c6934d3915d7399 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -80,6 +80,67 @@ static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
 //static const char WHITE_IMAGE_NAME[] = "Blank Texture";
 //static const char NO_IMAGE_NAME[] = "None";
 
+
+
+//static
+bool get_is_predefined_texture(LLUUID asset_id)
+{
+    if (asset_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture"))
+        || asset_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID"))
+        || asset_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID"))
+        || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE))
+    {
+        return true;
+    }
+    return false;
+}
+
+LLUUID get_copy_free_item_by_asset_id(LLUUID asset_id, bool no_trans_perm)
+{
+    LLViewerInventoryCategory::cat_array_t cats;
+    LLViewerInventoryItem::item_array_t items;
+    LLAssetIDMatches asset_id_matches(asset_id);
+    gInventory.collectDescendentsIf(LLUUID::null,
+        cats,
+        items,
+        LLInventoryModel::INCLUDE_TRASH,
+        asset_id_matches);
+    
+    LLUUID res;
+    if (items.size())
+    {
+        for (S32 i = 0; i < items.size(); i++)
+        {
+            LLViewerInventoryItem* itemp = items[i];
+            if (itemp)
+            {
+                LLPermissions item_permissions = itemp->getPermissions();
+                if (item_permissions.allowOperationBy(PERM_COPY,
+                    gAgent.getID(),
+                    gAgent.getGroupID()))
+                {
+                    bool allow_trans = item_permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID(), gAgent.getGroupID());
+                    if (allow_trans != no_trans_perm)
+                    {
+                        return itemp->getUUID();
+                    }
+                    res = itemp->getUUID();
+                }
+            }
+        }
+    }
+    return res;
+}
+
+bool get_can_copy_texture(LLUUID asset_id)
+{
+    // User is allowed to copy a texture if:
+    // library asset or default texture,
+    // or copy perm asset exists in user's inventory
+
+    return get_is_predefined_texture(asset_id) || get_copy_free_item_by_asset_id(asset_id).notNull();
+}
+
 LLFloaterTexturePicker::LLFloaterTexturePicker(	
 	LLView* owner,
 	LLUUID image_asset_id,
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 92f6f89af62ab1a947a795f403adc4bbe4146867..3769f437375e2bffbd1d8739f6ea214d19bd3f84 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -52,6 +52,16 @@ class LLViewerFetchedTexture;
 typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback;
 typedef boost::function<void (LLInventoryItem*)> texture_selected_callback;
 
+// Helper functions for UI that work with picker
+bool get_is_predefined_texture(LLUUID asset_id);
+
+// texture picker works by asset ids since objects normaly do
+// not retain inventory ids as result these functions are looking
+// for textures in inventory by asset ids
+// This search can be performance unfriendly and doesn't warranty
+// that the texture is original source of asset
+LLUUID get_copy_free_item_by_asset_id(LLUUID image_id, bool no_trans_perm = false);
+bool get_can_copy_texture(LLUUID image_id);
 
 //////////////////////////////////////////////////////////////////////////////////////////
 // LLTextureCtrl
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 8baad30e8f09e0593a2e617cb34e283ab46e47a9..692e8d91a9c8d90c4cadc48447d4a4f1b52e78dc 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -291,7 +291,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
 			mLineEditor->setText(edit_text_contents);
 
 			std::string notif_name = mNotification->getName();
-			if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name))
+			if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name) || ("CreateSubfolder" == notif_name))
 			{
 				mLineEditor->setPrevalidate(&LLTextValidate::validateASCII);
 			}
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 50868d0fa5aaa29b6501fff756fb3d8a14b83b4c..f76a2f7f905fd9f32a65578150aeacd321294893 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1100,7 +1100,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
 										   S32 hit_face,
 										   LLInventoryItem* item,
 										   LLToolDragAndDrop::ESource source,
-										   const LLUUID& src_id)
+										   const LLUUID& src_id,
+                                           S32 tex_channel)
 {
 	if (hit_face == -1) return;
 	if (!item)
@@ -1124,7 +1125,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
 
 	if (gFloaterTools->getVisible() && panel_face)
 	{
-		switch (LLSelectMgr::getInstance()->getTextureChannel())
+        tex_channel = (tex_channel > -1) ? tex_channel : LLSelectMgr::getInstance()->getTextureChannel();
+        switch (tex_channel)
 		{
 
 		case 0:
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index 24a712029c9e30ed735f8e75335be0382a3a434e..4537d73332e346fff24d2e424f137b309b21f4db 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -244,7 +244,8 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 	static void dropTextureOneFace(LLViewerObject* hit_obj, S32 hit_face,
 								   LLInventoryItem* item,
 								   ESource source,
-								   const LLUUID& src_id);
+								   const LLUUID& src_id,
+                                   S32 tex_channel = -1);
 	static void dropTextureAllFaces(LLViewerObject* hit_obj,
 									LLInventoryItem* item,
 									ESource source,
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index d905ba39424ba846130c8f064dab003e0ee7a512..23c67c72076436e76180b9f466e5e3fd91bd8c41 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -2760,6 +2760,32 @@ void handle_object_touch()
 	send_ObjectDeGrab_message(object, pick);
 }
 
+void handle_object_show_original()
+{
+    LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+    if (!object)
+    {
+        return;
+    }
+
+    LLViewerObject *parent = (LLViewerObject*)object->getParent();
+    while (parent)
+    {
+        if(parent->isAvatar())
+        {
+            break;
+        }
+        object = parent;
+        parent = (LLViewerObject*)parent->getParent();
+    }
+
+    if (!object || object->isAvatar())
+    {
+        return;
+    }
+
+    show_item_original(object->getAttachmentItemID());
+}
 
 
 static void init_default_item_label(const std::string& item_name)
@@ -9545,6 +9571,7 @@ void initialize_menus()
 	// Object pie menu
 	view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
 	commit.add("Object.Touch", boost::bind(&handle_object_touch));
+	commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original));
 	commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
 	commit.add("Object.Delete", boost::bind(&handle_object_delete));
 	view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 12624ec3a20ed3dd626541fefc83b5ea4cf51e11..36b2bd4c32bc8eb9bae12515a0dab07c2b9e28d9 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -948,6 +948,7 @@ void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_M
         break;
 
     case STATE_MODE_DIFF:
+        if (mOctreeNode)
         {
             LLSpatialSetOcclusionStateDiff setter(state);
             setter.traverse(mOctreeNode);
@@ -955,6 +956,7 @@ void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_M
         break;
 
     case STATE_MODE_BRANCH:
+        if (mOctreeNode)
         {
             LLSpatialSetOcclusionState setter(state);
             setter.traverse(mOctreeNode);
@@ -1024,6 +1026,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE
             break;
 
         case STATE_MODE_DIFF:
+            if (mOctreeNode)
             {
                 LLSpatialClearOcclusionStateDiff clearer(state);
                 clearer.traverse(mOctreeNode);
@@ -1031,6 +1034,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE
             break;
 
         case STATE_MODE_BRANCH:
+            if (mOctreeNode)
             {
                 LLSpatialClearOcclusionState clearer(state);
                 clearer.traverse(mOctreeNode);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 02589c23e4202f7762ea32a49805aa63e2a7bb5f..5ce46b143a37479b180d8c617981a3002ab3a92f 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -103,7 +103,6 @@
 #include "llfilepicker.h"
 #include "llfirstuse.h"
 #include "llfloater.h"
-#include "llfloaterbuildoptions.h"
 #include "llfloaterbuyland.h"
 #include "llfloatercamera.h"
 #include "llfloaterland.h"
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index c16295821e0a5973d9acd98933ebd629ee42589b..6543081bd8adbe7fdefc0da9bbda7a4b5a0624ce 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -4621,7 +4621,12 @@ bool LLVOAvatar::updateCharacter(LLAgent &agent)
 	}
 	else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
 	{
-		getOffObject();
+        // If we are starting up, motion might be loading
+        LLMotion *motionp = mMotionController.findMotion(ANIM_AGENT_SIT_GROUND_CONSTRAINED);
+        if (!motionp || !mMotionController.isMotionLoading(motionp))
+        {
+            getOffObject();
+        }
 	}
 
 	//--------------------------------------------------------------------
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index bae3d540e3a5e2a289ea3fe9afc66216baf3067c..f4a938e57dce4d5244d50e84112432b75b32e731 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -230,6 +230,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 
 	mMediaImplList.resize(getNumTEs());
 	mLastFetchedMediaVersion = -1;
+    mServerDrawableUpdateCount = 0;
 	memset(&mIndexInTex, 0, sizeof(S32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS);
 	mMDCImplCount = 0;
 	mLastRiggingInfoLOD = -1;
@@ -325,6 +326,9 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 	 	
 	LLColor4U color;
 	const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA);
+    const bool previously_volume_changed = mVolumeChanged;
+    const bool previously_face_mapping_changed = mFaceMappingChanged;
+    const bool previously_color_changed = mColorChanged;
 
 	// Do base class updates...
 	U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
@@ -548,9 +552,31 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 	// ...and clean up any media impls
 	cleanUpMediaImpls();
 
+    if ((
+            (mVolumeChanged && !previously_volume_changed) ||
+            (mFaceMappingChanged && !previously_face_mapping_changed) ||
+            (mColorChanged && !previously_color_changed)
+        )
+        && !mLODChanged) {
+        onDrawableUpdateFromServer();
+    }
+
 	return retval;
 }
 
+// Called when a volume, material, etc is updated by the server, possibly by a
+// script. If this occurs too often for this object, mark it as active so that
+// it doesn't disrupt the octree/render batches, thereby potentially causing a
+// big performance penalty.
+void LLVOVolume::onDrawableUpdateFromServer()
+{
+    constexpr U32 UPDATES_UNTIL_ACTIVE = 8;
+    ++mServerDrawableUpdateCount;
+    if (mDrawable && !mDrawable->isActive() && mServerDrawableUpdateCount > UPDATES_UNTIL_ACTIVE)
+    {
+        mDrawable->makeActive();
+    }
+}
 
 void LLVOVolume::animateTextures()
 {
@@ -1670,7 +1696,7 @@ void LLVOVolume::regenFaces()
 	}
 }
 
-BOOL LLVOVolume::genBBoxes(BOOL force_global)
+BOOL LLVOVolume::genBBoxes(BOOL force_global, BOOL should_update_octree_bounds)
 {
     LL_PROFILE_ZONE_SCOPED;
     BOOL res = TRUE;
@@ -1746,20 +1772,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
         }
     }
 
-    bool rigged = false;
-
-    if (!isAnimatedObject())
-    {
-        rigged = isRiggedMesh() && isAttachment();
-    }
-    else
-    {
-        rigged = isRiggedMesh() && getControlAvatar() && getControlAvatar()->mPlaying;
-    }
-
     if (any_valid_boxes)
     {
-        if (rebuild)
+        if (rebuild && should_update_octree_bounds)
         {
             //get the Avatar associated with this object if it's rigged
             LLVOAvatar* avatar = nullptr;
@@ -1921,7 +1936,7 @@ void LLVOVolume::updateRelativeXform(bool force_identity)
 	}
 }
 
-bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
+bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &should_update_octree_bounds)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 	bool regen_faces = false;
@@ -1953,6 +1968,9 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
         }
 
 		compiled = TRUE;
+        // new_lod > old_lod breaks a feedback loop between LOD updates and
+        // bounding box updates.
+        should_update_octree_bounds = should_update_octree_bounds || mSculptChanged || new_lod > old_lod;
 		sNumLODChanges += new_num_faces;
 
 		if ((S32)getNumTEs() != getVolume()->getNumFaces())
@@ -2012,8 +2030,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 		group->dirtyMesh();
 	}
 
-	BOOL compiled = FALSE;
-			
 	updateRelativeXform();
 	
 	if (mDrawable.isNull()) // Not sure why this is happening, but it is...
@@ -2021,49 +2037,55 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 		return TRUE; // No update to complete
 	}
 
+	BOOL compiled = FALSE;
+    // This should be true in most cases, unless we're sure no octree update is
+    // needed.
+    BOOL should_update_octree_bounds = bool(getRiggedVolume()) || mDrawable->isState(LLDrawable::REBUILD_POSITION) || !mDrawable->getSpatialExtents()->isFinite3();
+
 	if (mVolumeChanged || mFaceMappingChanged)
 	{
 		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
 
 		bool was_regen_faces = false;
+        should_update_octree_bounds = true;
 
 		if (mVolumeChanged)
 		{
-			was_regen_faces = lodOrSculptChanged(drawable, compiled);
+            was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
 			drawable->setState(LLDrawable::REBUILD_VOLUME);
 		}
 		else if (mSculptChanged || mLODChanged || mColorChanged)
 		{
 			compiled = TRUE;
-			was_regen_faces = lodOrSculptChanged(drawable, compiled);
+            was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
 		}
 
 		if (!was_regen_faces) {
 			regenFaces();
 		}
-
-		genBBoxes(FALSE);
 	}
 	else if (mLODChanged || mSculptChanged || mColorChanged)
 	{
 		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
 		compiled = TRUE;
-		lodOrSculptChanged(drawable, compiled);
+        lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
 		
 		if(drawable->isState(LLDrawable::REBUILD_RIGGED | LLDrawable::RIGGED)) 
 		{
 			updateRiggedVolume(false);
 		}
-		genBBoxes(FALSE);
 	}
 	// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
 	else
 	{
 		compiled = TRUE;
 		// All it did was move or we changed the texture coordinate offset
-		genBBoxes(FALSE);
 	}
 
+    // Generate bounding boxes if needed, and update the object's size in the
+    // octree
+    genBBoxes(FALSE, should_update_octree_bounds);
+
 	// Update face flags
 	updateFaceFlags();
 	
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 4cb7a5481c6ff856fd55357d75da7419fca9d710..4136c13315aa0a82a39967a4cf738e78f9d4bf05 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -232,7 +232,7 @@ class LLVOVolume : public LLViewerObject
 
 				void	updateFaceFlags();
 				void	regenFaces();
-				BOOL	genBBoxes(BOOL force_global);
+                BOOL    genBBoxes(BOOL force_global, BOOL should_update_octree_bounds = TRUE);
 				void	preRebuild();
 	virtual		void	updateSpatialExtents(LLVector4a& min, LLVector4a& max);
 	virtual		F32		getBinRadius();
@@ -386,13 +386,14 @@ class LLVOVolume : public LLViewerObject
 	static S32 mRenderComplexity_last;
 	static S32 mRenderComplexity_current;
 
+    void onDrawableUpdateFromServer();
 	void requestMediaDataUpdate(bool isNew);
 	void cleanUpMediaImpls();
 	void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
 	void removeMediaImpl(S32 texture_index) ;
 
 private:
-	bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled);
+    bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &shouldUpdateOctreeBounds);
 
 public:
 
@@ -424,6 +425,7 @@ class LLVOVolume : public LLViewerObject
 	LLPointer<LLViewerFetchedTexture> mLightTexture;
 	media_list_t mMediaImplList;
 	S32			mLastFetchedMediaVersion; // as fetched from the server, starts as -1
+    U32         mServerDrawableUpdateCount;
 	S32 mIndexInTex[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
 	S32 mMDCImplCount;
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index c297f0f080cb11a263eb09fb19dd4e4a76770644..54e6c6fc6ec5dd41c14430a13025903a790d0687 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3939,7 +3939,7 @@ void LLPipeline::postSort(LLCamera& camera)
 	}
 	LL_PUSH_CALLSTACKS();
 	// If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
-	if (LLFloaterTelehub::renderBeacons())
+	if (LLFloaterTelehub::renderBeacons() && !sShadowRender)
 	{
 		LLFloaterTelehub::addBeacons();
 	}
diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a81c5f94b65713dcac65f5e743639162bcb8481
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png
new file mode 100644
index 0000000000000000000000000000000000000000..88012cf8d124c6a6cb083d597fb92c689f1f9c5f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab02e7d42d798f997296e721023759f7e6600d1f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png
new file mode 100644
index 0000000000000000000000000000000000000000..63b4bd212739ec9a9c54b782beb31a7b70a63c73
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png
new file mode 100644
index 0000000000000000000000000000000000000000..4200182b0cec4c7ff7aea2bf60232207640aad9f
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png differ
diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png
new file mode 100644
index 0000000000000000000000000000000000000000..e12887f4891a587ad029d994844bb9c0ac766022
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png differ
diff --git a/indra/newview/skins/default/textures/map_ui_collapse_icon.png b/indra/newview/skins/default/textures/map_ui_collapse_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4de49d4af82e3a4a0952eedf81f0c58782dd0ae
Binary files /dev/null and b/indra/newview/skins/default/textures/map_ui_collapse_icon.png differ
diff --git a/indra/newview/skins/default/textures/map_ui_expand_icon.png b/indra/newview/skins/default/textures/map_ui_expand_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..08734b4cc096d3aeec81ca89e205814c94dc676c
Binary files /dev/null and b/indra/newview/skins/default/textures/map_ui_expand_icon.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 804fae45e2d90a24f6d1948915f3eae657811b8f..d563b1b31e376d5ca109b2d5c5a3bfd30ff4564c 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -445,6 +445,13 @@ with the same filename but different name
   <texture name="OptionsMenu_Off" file_name="icons/OptionsMenu_Off.png" preload="false" />
   <texture name="OptionsMenu_Press" file_name="icons/OptionsMenu_Press.png" preload="false" />
 
+  <texture name="ClipboardSmallMenu_Disabled" file_name="icons/ClipboardSmallMenu_Disabled.png" preload="false" />
+  <texture name="ClipboardSmallMenu_Off" file_name="icons/ClipboardSmallMenu_Off.png" preload="false" />
+  <texture name="ClipboardSmallMenu_Press" file_name="icons/ClipboardSmallMenu_Press.png" preload="false" />
+  <texture name="ClipboardMenu_Disabled" file_name="icons/ClipboardMenu_Disabled.png" preload="false" />
+  <texture name="ClipboardMenu_Off" file_name="icons/ClipboardMenu_Off.png" preload="false" />
+  <texture name="ClipboardMenu_Press" file_name="icons/ClipboardMenu_Press.png" preload="false" />
+
   <texture name="OutboxStatus_Success" file_name="green_checkmark.png" preload="false" />
   <texture name="OutboxStatus_Warning" file_name="icons/pop_up_caution.png" preload="false" />
   <texture name="OutboxStatus_Error" file_name="red_x.png" preload="false" />
@@ -801,6 +808,8 @@ with the same filename but different name
   <texture name="map_infohub.tga" />
   <texture name="map_telehub.tga" />
   <texture name="map_track_16.tga" />
+  <texture name="map_ui_collapse_icon.png" />
+  <texture name="map_ui_expand_icon.png" />
 
   <texture name="notify_caution_icon.tga" />
 
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 46f05fd7bbcc08c3c8a86d24960e4a7f631b613f..ade79b8884af31f4b5b0ec4e2b664d0c2051bdda 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2,7 +2,7 @@
 <floater
  positioning="cascading"
  legacy_header_height="18"
- height="600"
+ height="609"
  layout="topleft"
  bg_opaque_image="Window_NoTitle_Foreground"
  bg_alpha_image="Window_NoTitle_Background"
@@ -68,7 +68,7 @@
     </floater.string>
     <floater.string
      name="status_selectcount">
-        [OBJ_COUNT] objects selected, land impact [LAND_IMPACT]
+        [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] [secondlife:///app/openfloater/object_weights More info]
     </floater.string>
     <floater.string
      name="status_remaining_capacity">
@@ -763,11 +763,12 @@
 	  font="SansSerifSmall"
 	  layout="topleft"
 	  left="10"
-	  name="selection_count"
+	  name="selection_faces"
 	  top_delta="0"
 	  visible="false"
 	  width="280">
-	</text>
+    Faces selected: [FACES_STRING]
+  </text>
 	<text
 	 text_color="LtGray_50"
 	  type="string"
@@ -777,11 +778,10 @@
 	  font="SansSerifSmall"
 	  layout="topleft"
 	  left="10"
-	  name="remaining_capacity"
+	  name="selection_count"
 	  top_pad="0"
 	  visible="false"
 	  width="280">
-	  [CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info]
 	</text>
     <!-- <text -->
     <!-- text_color="LtGray_50" -->
@@ -820,7 +820,7 @@
     width="282"/>
     <tab_container
      follows="left|top"
-     height="410"
+     height="426"
      halign="center"
      left="0"
      name="Object Info Tabs"
@@ -1430,16 +1430,40 @@ even though the user gets a free copy.
              tool_tip="Causes object to not collide with other objects or avatars"
              top_pad="0"
              width="123" />
-        <text
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             height="0"
+             layout="topleft"
+             left_delta="0"
+             name="object_horizontal"
+             top_pad="10"
+             width="95" />
+            <menu_button
+             menu_filename="menu_copy_paste_pos.xml"
+             follows="top|left"
+             height="11"
+             image_disabled="ClipboardSmallMenu_Disabled"
+             image_selected="ClipboardSmallMenu_Press"
+             image_unselected="ClipboardSmallMenu_Off"
+             layout="topleft"
+             left_delta="0"
+             top_pad="13"
+             name="clipboard_pos_btn"
+             tool_tip="Paste options"
+             width="19"/>
+            <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
              name="label position"
-             top_pad="10"
+             tool_tip="Position (meters)"
+             left_pad="8"
+             top_delta="0"
              width="121">
-                Position (meters)
+                Position (m)
             </text>
             <spinner
              follows="left|top"
@@ -1449,12 +1473,12 @@ even though the user gets a free copy.
              label="X"
              label_width="10"
              layout="topleft"
-             left_delta="0"
+             left_delta="-27"
              max_val="512"
              min_val="-256"
              name="Pos X"
              text_enabled_color="1 0 0.3 .7"
-             top_pad="5"
+             top_pad="8"
              width="87" />
             <spinner
              follows="left|top"
@@ -1486,17 +1510,31 @@ even though the user gets a free copy.
              text_enabled_color="0 0.8 1 .65"
              top_pad="3"
              width="87" />
+            <menu_button
+             menu_filename="menu_copy_paste_size.xml"
+             follows="top|left"
+             height="11"
+             image_disabled="ClipboardSmallMenu_Disabled"
+             image_selected="ClipboardSmallMenu_Press"
+             image_unselected="ClipboardSmallMenu_Off"
+             layout="topleft"
+             left_delta="0"
+             top_pad="13"
+             name="clipboard_size_btn"
+             tool_tip="Paste options"
+             width="19"/>
             <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
-             left_delta="0"
+             left_pad="8"
+             top_delta="0"
              name="label size"
-             top_pad="6"
+             tool_tip="Size (meters)"
              width="121">
-                Size (meters)
+                Size (m)
             </text>
             <spinner
              follows="left|top"
@@ -1506,12 +1544,12 @@ even though the user gets a free copy.
              label="X"
              label_width="10"
              layout="topleft"
-             left_delta="0"
+             left_delta="-27"
              max_val="64"
              min_val="0.01"
              name="Scale X"
              text_enabled_color="1 1 1 1"
-             top_pad="5"
+             top_pad="8"
              width="87" />
             <spinner
              follows="left|top"
@@ -1543,17 +1581,31 @@ even though the user gets a free copy.
              text_enabled_color="1 1 1 1"
              top_pad="3"
              width="87" />
+            <menu_button
+             menu_filename="menu_copy_paste_rot.xml"
+             follows="top|left"
+             height="11"
+             image_disabled="ClipboardSmallMenu_Disabled"
+             image_selected="ClipboardSmallMenu_Press"
+             image_unselected="ClipboardSmallMenu_Off"
+             layout="topleft"
+             left_delta="0"
+             top_pad="13"
+             name="clipboard_rot_btn"
+             tool_tip="Paste options"
+             width="19"/>
             <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
-             left_delta="0"
+             left_pad="8"
+             top_delta="0"
              name="label rotation"
-             top_pad="10"
+             tool_tip="Rotation (degrees)"
              width="121">
-                Rotation (degrees)
+                Rotation (°)
             </text>
             <spinner
              decimal_digits="2"
@@ -1564,12 +1616,12 @@ even though the user gets a free copy.
              label="X"
              label_width="10"
              layout="topleft"
-             left_delta="0"
+             left_delta="-27"
              max_val="9999"
              min_val="-9999"
              name="Rot X"
              text_enabled_color="1 1 1 1"
-             top_pad="5"
+             top_pad="8"
              width="87" />
             <spinner
              decimal_digits="2"
@@ -1615,13 +1667,23 @@ even though the user gets a free copy.
              width="150">
                 Prim Type
             </text>-->
+
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             layout="topleft"
+             name="object_vertical"
+             left="117"
+             top="6"
+             height="500"
+             width="0"/>
             <combo_box
              height="19"
              layout="topleft"
              name="comboBaseType"
              top="6"
              left="125"
-             width="150">
+             width="125">
                 <combo_box.item
                  label="Box"
                  name="Box"
@@ -1655,13 +1717,26 @@ even though the user gets a free copy.
                  name="Sculpted"
                  value="Sculpted" />
             </combo_box>
+            <menu_button
+              menu_filename="menu_copy_paste_object.xml"
+              follows="top|left"
+              height="15"
+              image_disabled="ClipboardMenu_Disabled"
+              image_selected="ClipboardMenu_Press"
+              image_unselected="ClipboardMenu_Off"
+              layout="topleft"
+              left_pad="8"
+              top_delta="2"
+              name="clipboard_obj_params_btn"
+              tool_tip="Paste options"
+              width="22"/>
             <text
              type="string"
              length="1"
              follows="left|top"
              height="10"
              layout="topleft"
-             left_delta="0"
+             left="125"
              name="text cut"
              top_pad="5"
              width="150">
@@ -1701,7 +1776,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text hollow"
-             top_pad="6"
+             top_pad="7"
              width="68">
                 Hollow
             </text>
@@ -1749,7 +1824,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="Hollow Shape"
-             top_pad="4"
+             top_pad="7"
              width="150">
                 Hollow Shape
             </text>
@@ -1785,7 +1860,7 @@ even though the user gets a free copy.
              layout="topleft"
              left_delta="0"
              name="text twist"
-             top_pad="5"
+             top_pad="7"
              width="150">
                 Twist (begin/end)
             </text>
@@ -1827,12 +1902,12 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="scale_taper"
-             top_pad="3"
+             top_pad="7"
              width="150">
                 Taper
             </text>
             <text
-			 visible="false"
+             visible="false"
              type="string"
              length="1"
              follows="left|top"
@@ -1880,7 +1955,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text topshear"
-             top_pad="3"
+             top_pad="5"
              width="141">
                 Top Shear
             </text>
@@ -1923,12 +1998,12 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="advanced_cut"
-             top_pad="3"
+             top_pad="7"
              width="150">
                 Profile Cut (begin/end)
             </text>
             <text
-			 visible="false"
+             visible="false"
              type="string"
              length="1"
              follows="left|top"
@@ -1987,7 +2062,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text taper2"
-             top_pad="3"
+             top_pad="7"
              width="150">
                 Taper
             </text>
@@ -2030,7 +2105,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="125"
              name="text radius delta"
-             top_pad="2"
+             top_pad="7"
              width="78">
                 Radius
             </text>
@@ -2158,6 +2233,19 @@ even though the user gets a free copy.
 	<panel.string name="None">None</panel.string>
 	<panel.string name="Prim">Prim</panel.string>
 	<panel.string name="Convex Hull">Convex Hull</panel.string>
+            <menu_button
+              menu_filename="menu_copy_paste_features.xml"
+              follows="top|left"
+              height="15"
+              image_disabled="ClipboardMenu_Disabled"
+              image_selected="ClipboardMenu_Press"
+              image_unselected="ClipboardMenu_Off"
+              layout="topleft"
+              left="258"
+              top="8"
+              name="clipboard_features_params_btn"
+              tool_tip="Paste options"
+              width="22"/>
             <text
              type="string"
              length="1"
@@ -2310,6 +2398,15 @@ even though the user gets a free copy.
              name="FlexForceZ"
              top_pad="4"
              width="128" />
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             height="0"
+             layout="topleft"
+             left="8"
+             name="object_horizontal"
+             top_pad="10"
+             width="278" />
 
             <check_box
              height="16"
@@ -2318,7 +2415,7 @@ even though the user gets a free copy.
              left="10"
              name="Light Checkbox Ctrl"
              tool_tip="Causes object to emit light"
-             top_pad="15"
+             top_pad="8"
              width="60" />
             <color_swatch
              can_apply_immediately="true"
@@ -2345,6 +2442,19 @@ even though the user gets a free copy.
             name="light texture control"
             tool_tip="Click to choose a projection image (only has effect with deferred rendering enabled)"
             width="32" />
+         <menu_button
+              menu_filename="menu_copy_paste_light.xml"
+              follows="top|left"
+              height="15"
+              image_disabled="ClipboardMenu_Disabled"
+              image_selected="ClipboardMenu_Press"
+              image_unselected="ClipboardMenu_Off"
+              layout="topleft"
+              left="258"
+              top_delta="0"
+              name="clipboard_light_params_btn"
+              tool_tip="Paste options"
+              width="22"/>
           <spinner
              follows="left|top"
              height="19"
@@ -2354,7 +2464,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="10"
              name="Light Intensity"
-             top_pad="3"
+             top_pad="26"
              width="128" />
           <spinner bottom_delta="0"
                    decimal_digits="3"
@@ -2576,7 +2686,7 @@ even though the user gets a free copy.
              border_visible="true"
              bevel_style="in"
              follows="left|top|right"
-             height="325"
+             height="335"
              layout="topleft"
              left="10"
              name="contents_inventory"
diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml
index 83407069d2eee1ab962a8d3381a9c897bd9c746a..45e11fc836629599c07ea5364089710036300155 100644
--- a/indra/newview/skins/default/xui/en/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_world_map.xml
@@ -14,6 +14,31 @@
  single_instance="true"
  title="WORLD MAP"
  width="650">
+  <string
+   name="collapse_icon"
+   value="map_ui_collapse_icon.png"/>
+  <string
+   name="expand_icon"
+   value="map_ui_expand_icon.png"/>
+  <string
+   name="collapse_tooltip"
+   value="Hide map controls"/>
+  <string
+   name="expand_tooltip"
+   value="Show map controls"/>
+  <layout_stack
+   animate="false"
+   follows="all"
+   name="floater_map_stack"
+   tab_group="1"
+   top="16"
+   left="0"
+   right="-1"
+   bottom="-1">
+    <layout_panel
+     name="map_lp"
+     width="385"
+     height="575">
     <panel
      filename="panel_world_map.xml"
      follows="all"
@@ -21,17 +46,48 @@
      layout="topleft"
      left="10"
      name="objects_mapview"
-     top="25"
+     top="6"
      width="375" />
+      <panel
+       follows="top|right"
+       height="30"
+       layout="topleft"
+       left_pad="-29"
+       name="expand_btn_panel"
+       background_visible="true"
+       bg_opaque_color="FloaterFocusBackgroundColor"
+       bg_alpha_color="FloaterDefaultBackgroundColor"
+       background_opaque="true"
+       tool_tip="Hide map controls"
+       top="350"
+       width="30">
+        <icon
+         follows="top|right"
+         height="16"
+         width="16"
+         top="7"
+         left="7"
+         scale_image="false"
+         image_name="map_ui_collapse_icon.png"
+         layout="topleft"
+         mouse_opaque="true"
+         name="expand_collapse_icon"
+         tool_tip="Hide map controls" />
+      </panel>
+      </layout_panel>
+    <layout_panel
+      height="575"
+      width="265"
+      expanded_min_dim="265"
+      name="controls_lp">
      <panel
-     name="layout_panel_1"
-     height="22"
-     width="238"
-     follows="right|top"
-     top="25"
-     left_pad="5"
-  background_visible="true"
-  bg_alpha_color="DkGray2">
+      name="layout_panel_1"
+      height="22"
+      width="238"
+      follows="right|top"
+      top="6"     
+      background_visible="true"
+      bg_alpha_color="DkGray2">
     <text
      text_color="White"
      font="SansSerifLarge"
@@ -43,17 +99,17 @@
      layout="topleft"
      left="15"
      name="events_label"
-     top="3"
      width="215">
         Legend
     </text>
     </panel>
-<panel
- follows="right|top"
-  height="126"
-  top_pad="0"
-  width="238"
-  name="layout_panel_2">
+    <panel
+     follows="right|top"
+     height="126"
+     top_pad="4"
+     width="238"
+     left="1"
+     name="layout_panel_2">
 <button
      follows="right|top"
      height="22"
@@ -690,4 +746,6 @@
      show_text="false"
      width="200" />
      </panel>
+      </layout_panel>
+    </layout_stack>
 </floater>
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 26b1c86c53bab1be966053fcf0432e338eb5310f..3b91b9df7ab33c2e63e87050ca848f2682843504 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
@@ -33,6 +33,13 @@
          function="Object.EnableTouch"
          name="EnableTouch"/>
     </menu_item_call>
+    <menu_item_call
+     label="Show in inventory"
+     layout="topleft"
+     name="Show original">
+      <menu_item_call.on_click
+       function="Object.ShowOriginal" />
+    </menu_item_call>
     <menu_item_separator
      layout="topleft" />
 
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4c12180daf32f53bc78324a03f636e3f449118fb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Color Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="color_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="color_paste" />
+       <on_enable function="PanelFace.menuEnable" parameter="color_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4823d74a261c2ecb57d359a05b4af5708610cf53
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Features Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="features_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="features_paste" />
+       <on_enable function="PanelVolume.menuEnable" parameter="features_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5de23dfee3f9bdd0a4d57d7ea8a4ca9aa7585c22
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Light Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="light_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelVolume.menuDoToSelected" parameter="light_paste" />
+       <on_enable function="PanelVolume.menuEnable" parameter="light_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bdc4537a9dc0d39c0ace17aec056fe448c589ee0
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Object Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="params_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="params_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="params_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3ea95b281f08d6e64d558cb1301d3b6b205a819d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Position Menu">
+    <menu_item_call
+     label="Copy all"
+     layout="topleft"
+     name="psr_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy position"
+     layout="topleft"
+     name="pos_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="pos_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste all"
+     layout="topleft"
+     name="psr_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste position"
+     layout="topleft"
+     name="pos_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="pos_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="pos_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml
new file mode 100644
index 0000000000000000000000000000000000000000..06ce80f8977c32488cd7b58d5f3a9cdfe09562e5
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Rotation Menu">
+    <menu_item_call
+     label="Copy all"
+     layout="topleft"
+     name="psr_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
+       <on_enable function="PanelObject.menuEnable" parameter="rot_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy rotation"
+     layout="topleft"
+     name="rot_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="rot_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste all"
+     layout="topleft"
+     name="psr_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste rotation"
+     layout="topleft"
+     name="rot_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="rot_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="rot_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7082a0e65b37c10df8cf24a7bf3c9f392dcb24b9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Size Menu">
+    <menu_item_call
+     label="Copy all"
+     layout="topleft"
+     name="psr_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy size"
+     layout="topleft"
+     name="size_copy"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="size_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste all"
+     layout="topleft"
+     name="psr_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste size"
+     layout="topleft"
+     name="size_paste"
+     visible="true">
+       <on_click function="PanelObject.menuDoToSelected" parameter="size_paste" />
+       <on_enable function="PanelObject.menuEnable" parameter="size_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f358affc23d2e32d512e8646abaa3ade304e66eb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Copy Paste Texture Menu">
+    <menu_item_call
+     label="Copy"
+     layout="topleft"
+     name="params_copy"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="texture_copy" />
+    </menu_item_call>
+    <menu_item_call
+     label="Paste"
+     layout="topleft"
+     name="params_paste"
+     visible="true">
+       <on_click function="PanelFace.menuDoToSelected" parameter="texture_paste" />
+       <on_enable function="PanelFace.menuEnable" parameter="texture_paste" />
+    </menu_item_call>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 78ca1708132e602bb09997a8f471fe0ab3c1a47c..aa3d0ae071f466bf2a1fa598530ed787ed584517 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -912,6 +912,25 @@
                 function="Inventory.DoToSelected"
                 parameter="apply_settings_parcel" />
     </menu_item_call>
+  <menu_item_separator
+   layout="topleft"
+   name="Subfolder Separator" />
+  <menu_item_call
+   label="Create folder from selected"
+   layout="topleft"
+   name="New folder from selected">
+    <menu_item_call.on_click
+     function="Inventory.DoToSelected"
+     parameter="new_folder_from_selected" />
+  </menu_item_call>
+  <menu_item_call
+   label="Ungroup folder items"
+   layout="topleft"
+   name="Ungroup folder items">
+    <menu_item_call.on_click
+     function="Inventory.DoToSelected"
+     parameter="ungroup_folder_items" />
+  </menu_item_call>
 	<menu_item_separator
 	 layout="topleft"
 	 name="Marketplace Separator" />
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index ec7b4c46f9d04a8ab3e20869258f5ed84855a622..5cee6eb9a6003d85d276a78fc68a3f9dd1f283f7 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -9038,6 +9038,29 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran
     yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="FacePasteFailed"
+   type="alertmodal">
+Paste failed. [REASON]
+   <usetemplate
+    name="okbutton"
+    yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="FacePasteTexturePermissions"
+   type="alertmodal">
+    You applied a texture with limited permissions, object will inherit permissions from texture.
+    <usetemplate
+     ignoretext="Paste: You applied a texture with limited permissions"
+     name="notifyignore"/>
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="ConfirmLeaveCall"
@@ -11640,7 +11663,7 @@ This Region does not support environmental settings.
  
   <notification
    icon="alertmodal.tga"
-   label="Save Outfit"
+   label="Save Environmental Settings"
    name="SaveSettingAs"
    type="alertmodal">
     <unique/>
@@ -11819,4 +11842,38 @@ Unpacking: [UNPACK_TIME]s [USIZE]KB
     </form>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   label="Create subfolder"
+   name="CreateSubfolder"
+   type="alertmodal">
+    <unique/>
+    Name the new folder:
+    <tag>confirm</tag>
+    <form name="form">
+      <input name="message" type="text">
+        [DESC]
+      </input>
+      <button
+       default="true"
+       index="0"
+       name="OK"
+       text="OK"/>
+      <button
+       index="1"
+       name="Cancel"
+       text="Cancel"/>
+    </form>
+  </notification>
+  <notification
+   icon="alertmodal.tga"
+   name="SameFolderRequired"
+   type="alert">
+    Selected items must be in the same folder.
+    <tag>fail</tag>
+    <usetemplate
+      name="okbutton"
+      yestext="OK"/>
+  </notification>
+
 </notifications>
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
index 594ca08a38e55b6f51f0b98da3bbb7b1e7b22ad7..c7052bb7371e93bdd9240bc2bdb0acb606079f9c 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -11,6 +11,36 @@
          name="Texture"
          top="0"
          width="295">
+            <panel.string
+             name="paste_error_face_selection_mismatch">
+              When multiple faces are copied, the target object must have the same number of faces selected.
+            </panel.string>
+            <panel.string
+             name="paste_error_object_face_count_mismatch">
+              When all faces of an object are copied, the target object must have the same number of faces.
+            </panel.string>
+            <panel.string
+             name="paste_error_inventory_not_found">
+              One or more texture not found in inventory.
+            </panel.string>
+            <panel.string
+             name="paste_options">
+              Paste options
+            </panel.string>
+
+            <menu_button
+             menu_filename="menu_copy_paste_color.xml"
+             follows="top|left"
+             height="15"
+             image_disabled="ClipboardMenu_Disabled"
+             image_selected="ClipboardMenu_Press"
+             image_unselected="ClipboardMenu_Off"
+             layout="topleft"
+             left="258"
+             top="8"
+             name="clipboard_color_params_btn"
+             tool_tip="Paste options"
+             width="22"/>
             <text
              type="string"
              length="1"
@@ -36,7 +66,7 @@
              name="colorswatch"
              tool_tip="Click to open color picker"
              top="20"
-             width="64" />
+             width="54" />
             <text
              type="string"
              length="1"
@@ -84,7 +114,7 @@
              left_delta="0"
              name="glow"
              top_pad="4"
-             width="80" />
+             width="77" />
             <check_box
              height="19"
              label="Full Bright"
@@ -93,13 +123,22 @@
              name="checkbox fullbright"
              top_pad="4"
              width="81" />
+            <view_border
+             bevel_style="none"
+             follows="top|left"
+             height="0"
+             layout="topleft"
+             left="8"
+             name="object_horizontal"
+             top_pad="4"
+             width="278" />
             <combo_box
              height="23"
              layout="topleft"
              left="10"
              name="combobox matmedia"
-             top_pad="5"
-             width="100">
+             top_pad="17"
+             width="90">
                 <combo_box.item
                  label="Materials"
                  name="Materials"
@@ -113,7 +152,7 @@
             control_name="ComboMaterialType"
             height="50"
             layout="topleft"
-            left_pad="20"
+            left_pad="5"
             top_delta="-10"
             width="150"
             visible = "false"
@@ -139,7 +178,20 @@
                 layout="topleft"
                 top_pad="1"
                 value="2"/>
-            </radio_group> 
+            </radio_group>
+            <menu_button
+                menu_filename="menu_copy_paste_texture.xml"
+                follows="top|left"
+                height="15"
+                image_disabled="ClipboardMenu_Disabled"
+                image_selected="ClipboardMenu_Press"
+                image_unselected="ClipboardMenu_Off"
+                layout="topleft"
+                left="258"
+                top_delta="0"
+                name="clipboard_texture_params_btn"
+                tool_tip="Paste options"
+                width="22"/>
             <check_box
              control_name="SyncMaterialSettings"
              follows="top|left"
@@ -150,7 +202,7 @@
              left="8"
              name="checkbox_sync_settings"
              tool_tip="Adjust all maps repeats simultaneously"
-             top_pad="-16"
+             top_pad="19"
              width="160" />
             <texture_picker
              can_apply_immediately="true"
@@ -765,14 +817,14 @@
              top_delta="16"
              width="260" />
 			<button
-			 left="10"
-			 top="222"
+       follows="left|top"
+       layout="topleft"
+			 left="9"
+			 top="204"
 			 height="20"
 			 label="Align"
 			 label_selected="Align current texture layers"
-			 layout="topleft"
 			 name="button align textures"
-			 top_delta="0"
 			 tool_tip="Align current texture layers"
 			 width="66" />
             <web_browser
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index 8a3e18707fc03a265b42f6a9ecafb2b2418bbfbf..1c9d750aa638cd4b8cc2f480157248b46f22eb07 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -459,7 +459,7 @@
         label="Price: L$"
         label_width="73"				
         width="150"
-        min_val="1"
+        min_val="0"
         height="20"
         max_val="999999999"
         tool_tip="Object cost." />