diff --git a/.hgtags b/.hgtags
index cc88ee166434416ad0bee95a8a0cea1fec514a62..8db85d96117298f2ebf89e2f100fda5915c30b23 100755
--- a/.hgtags
+++ b/.hgtags
@@ -501,3 +501,4 @@ d3d0101e980ec95043e0af9b7903045d3bc447e4 3.7.24-release
 000e9dda4162cbf0a83ba88558b19473654a09a9 3.7.26-release
 afd8d4756e8eda3c8f760625d1c17a2ad40ad6c8 3.7.27-release
 566874eb5ab26c003ef7fb0e22ce40c5fa0013f4 3.7.28-release
+d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
index 3d27b4a5b548c6e699917e15b6888132e60631e0..f4dba16a944076e5e0cb784573b427323b7738c9 100755
--- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
@@ -42,6 +42,7 @@
 #include "lldiriterator.h"
 #include "v4coloru.h"
 #include "llsdserialize.h"
+#include "llcleanup.h"
 
 // system libraries
 #include <iostream>
@@ -634,7 +635,7 @@ int main(int argc, char** argv)
 	}
 	
 	// Cleanup and exit
-	LLImage::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLImage);
 	if (fast_timer_log_thread)
 	{
 		fast_timer_log_thread->shutdown();
diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp
index 5dfb201fc4e4e4094d0d7ee13f937c42559b372e..2bf3b9085b813e75a2992ede703ab60b7502954a 100755
--- a/indra/llappearance/llwearabledata.cpp
+++ b/indra/llappearance/llwearabledata.cpp
@@ -92,7 +92,7 @@ void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LL
 	}
 }
 
-U32 LLWearableData::pushWearable(const LLWearableType::EType type, 
+void LLWearableData::pushWearable(const LLWearableType::EType type, 
 								   LLWearable *wearable,
 								   bool trigger_updated /* = true */)
 {
@@ -100,9 +100,8 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type,
 	{
 		// no null wearables please!
 		LL_WARNS() << "Null wearable sent for type " << type << LL_ENDL;
-		return MAX_CLOTHING_PER_TYPE;
 	}
-	if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE)
+	if (canAddWearable(type))
 	{
 		mWearableDatas[type].push_back(wearable);
 		if (trigger_updated)
@@ -110,9 +109,7 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type,
 			const BOOL removed = FALSE;
 			wearableUpdated(wearable, removed);
 		}
-		return mWearableDatas[type].size()-1;
 	}
-	return MAX_CLOTHING_PER_TYPE;
 }
 
 // virtual
@@ -125,7 +122,7 @@ void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed)
 	}
 }
 
-void LLWearableData::popWearable(LLWearable *wearable)
+void LLWearableData::eraseWearable(LLWearable *wearable)
 {
 	if (wearable == NULL)
 	{
@@ -133,16 +130,16 @@ void LLWearableData::popWearable(LLWearable *wearable)
 		return;
 	}
 
-	U32 index = getWearableIndex(wearable);
 	const LLWearableType::EType type = wearable->getType();
 
-	if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type))
+	U32 index;
+	if (getWearableIndex(wearable,index))
 	{
-		popWearable(type, index);
+		eraseWearable(type, index);
 	}
 }
 
-void LLWearableData::popWearable(const LLWearableType::EType type, U32 index)
+void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index)
 {
 	LLWearable *wearable = getWearable(type, index);
 	if (wearable)
@@ -204,11 +201,11 @@ void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type)
 }
 
 
-U32	LLWearableData::getWearableIndex(const LLWearable *wearable) const
+BOOL LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_found) const
 {
 	if (wearable == NULL)
 	{
-		return MAX_CLOTHING_PER_TYPE;
+		return FALSE;
 	}
 
 	const LLWearableType::EType type = wearable->getType();
@@ -216,18 +213,50 @@ U32	LLWearableData::getWearableIndex(const LLWearable *wearable) const
 	if (wearable_iter == mWearableDatas.end())
 	{
 		LL_WARNS() << "tried to get wearable index with an invalid type!" << LL_ENDL;
-		return MAX_CLOTHING_PER_TYPE;
+		return FALSE;
 	}
 	const wearableentry_vec_t& wearable_vec = wearable_iter->second;
 	for(U32 index = 0; index < wearable_vec.size(); index++)
 	{
 		if (wearable_vec[index] == wearable)
 		{
-			return index;
+			index_found = index;
+			return TRUE;
 		}
 	}
 
-	return MAX_CLOTHING_PER_TYPE;
+	return FALSE;
+}
+
+U32 LLWearableData::getClothingLayerCount() const
+{
+	U32 count = 0;
+	for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
+	{
+		LLWearableType::EType type = (LLWearableType::EType)i;
+		if (LLWearableType::getAssetType(type)==LLAssetType::AT_CLOTHING)
+		{
+			count += getWearableCount(type);
+		}
+	}
+	return count;
+}
+
+BOOL LLWearableData::canAddWearable(const LLWearableType::EType type) const
+{
+	LLAssetType::EType a_type = LLWearableType::getAssetType(type);
+	if (a_type==LLAssetType::AT_CLOTHING)
+	{
+		return (getClothingLayerCount() < MAX_CLOTHING_LAYERS);
+	}
+	else if (a_type==LLAssetType::AT_BODYPART)
+	{
+		return (getWearableCount(type) < 1);
+	}
+	else
+	{
+		return FALSE;
+	}
 }
 
 BOOL LLWearableData::isOnTop(LLWearable* wearable) const
diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h
old mode 100644
new mode 100755
index 03bd179f258812a1fdac747fd5404f41f7d2cd2a..a0c446ea9e2bc6810ff85e8249c0251e0efd7e15
--- a/indra/llappearance/llwearabledata.h
+++ b/indra/llappearance/llwearabledata.h
@@ -60,11 +60,13 @@ class LLWearableData
 	const LLWearable*	getBottomWearable(const LLWearableType::EType type) const;
 	U32				getWearableCount(const LLWearableType::EType type) const;
 	U32				getWearableCount(const U32 tex_index) const;
-	U32				getWearableIndex(const LLWearable *wearable) const;
+	BOOL			getWearableIndex(const LLWearable *wearable, U32& index) const;
+	U32				getClothingLayerCount() const;
+	BOOL			canAddWearable(const LLWearableType::EType type) const;
 
 	BOOL			isOnTop(LLWearable* wearable) const;
-
-	static const U32 MAX_CLOTHING_PER_TYPE = 5; 
+	
+	static const U32 MAX_CLOTHING_LAYERS = 60;
 
 	//--------------------------------------------------------------------
 	// Setters
@@ -72,11 +74,11 @@ class LLWearableData
 protected:
 	// Low-level data structure setter - public access is via setWearableItem, etc.
 	void 			setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable);
-	U32 			pushWearable(const LLWearableType::EType type, LLWearable *wearable, 
+	void 			pushWearable(const LLWearableType::EType type, LLWearable *wearable, 
 								 bool trigger_updated = true);
 	virtual void	wearableUpdated(LLWearable *wearable, BOOL removed);
-	void 			popWearable(LLWearable *wearable);
-	void			popWearable(const LLWearableType::EType type, U32 index);
+	void 			eraseWearable(LLWearable *wearable);
+	void			eraseWearable(const LLWearableType::EType type, U32 index);
 	void			clearWearableType(const LLWearableType::EType type);
 	bool			swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b);
 
diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp
old mode 100644
new mode 100755
index 618e2a1941bc8768765a0d91c61159bf87fd0e02..87109a5906ec7263b5d1957f4c6bcbe2781fc476
--- a/indra/llappearance/llwearabletype.cpp
+++ b/indra/llappearance/llwearabletype.cpp
@@ -27,6 +27,7 @@
 #include "linden_common.h"
 #include "llwearabletype.h"
 #include "llinventorytype.h"
+#include "llinventorydefines.h"
 
 static LLTranslationBridge* sTrans = NULL;
 
@@ -160,7 +161,7 @@ BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
 	return entry->mDisableCameraSwitch;
 }
 
-// static 
+// static
 BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type)
 {
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
@@ -169,3 +170,9 @@ BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type)
 	return entry->mAllowMultiwear;
 }
 
+// static
+LLWearableType::EType LLWearableType::inventoryFlagsToWearableType(U32 flags)
+{
+    return  (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK);
+}
+
diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h
old mode 100644
new mode 100755
index 7c9594644dbe0bfd78a2496dd2f22bb61a9dc8db..519d5b92a2a46496cc32e09f2409b8d010aa97bf
--- a/indra/llappearance/llwearabletype.h
+++ b/indra/llappearance/llwearabletype.h
@@ -80,6 +80,7 @@ class LLWearableType
 	static LLInventoryType::EIconName 	getIconName(EType type);
 	static BOOL 						getDisableCameraSwitch(EType type);
 	static BOOL 						getAllowMultiwear(EType type);
+    static EType						inventoryFlagsToWearableType(U32 flags);
 
 protected:
 	LLWearableType() {}
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 1459b9ada2785be76b7a8183123832be4895a2b1..de5aa0fde449ce9ba60b48ccd1bf2781b9e47253 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -162,6 +162,7 @@ set(llcommon_HEADER_FILES
     llhash.h
     llheartbeat.h
     llindexedvector.h
+    llinitdestroyclass.h
     llinitparam.h
     llinstancetracker.h
     llkeythrottle.h
@@ -178,6 +179,7 @@ set(llcommon_HEADER_FILES
     llmortician.h
     llnametable.h
     llpointer.h
+    llpounceable.h
     llpredicate.h
     llpreprocessor.h
     llpriqueuemap.h
@@ -310,6 +312,7 @@ if (LL_TESTS)
   LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llstreamqueue "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(llpounceable "" "${test_libs}")
 
   # *TODO - reenable these once tcmalloc libs no longer break the build.
   #ADD_BUILD_TEST(llallocator llcommon)
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 5a40845e7d739209255b73b529448b73d2986ccd..2c52b11594b66b165735d2c6cbf4733f974e409e 100755
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -48,6 +48,7 @@
 #include "lleventtimer.h"
 #include "google_breakpad/exception_handler.h"
 #include "stringize.h"
+#include "llcleanup.h"
 
 //
 // Signal handling
@@ -177,7 +178,7 @@ LLApp::~LLApp()
 	
 	if(mExceptionHandler != 0) delete mExceptionHandler;
 
-	LLCommon::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLCommon);
 }
 
 // static
diff --git a/indra/llcommon/llcleanup.h b/indra/llcommon/llcleanup.h
new file mode 100644
index 0000000000000000000000000000000000000000..8eda9a7fb35205c912958af865834dcad043d05f
--- /dev/null
+++ b/indra/llcommon/llcleanup.h
@@ -0,0 +1,30 @@
+/**
+ * @file   llcleanup.h
+ * @author Nat Goodspeed
+ * @date   2015-05-20
+ * @brief  Mechanism for cleaning up subsystem resources
+ * 
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Copyright (c) 2015, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLCLEANUP_H)
+#define LL_LLCLEANUP_H
+
+#include "llerror.h"
+
+// Instead of directly calling SomeClass::cleanupClass(), use
+// SUBSYSTEM_CLEANUP(SomeClass);
+// This logs the call as well as performing it. That gives us a baseline
+// subsystem shutdown order against which to compare subsequent dynamic
+// shutdown schemes.
+#define SUBSYSTEM_CLEANUP(CLASSNAME)                                    \
+    do {                                                                \
+        LL_INFOS("Cleanup") << "Calling " #CLASSNAME "::cleanupClass()" << LL_ENDL; \
+        CLASSNAME::cleanupClass();                                      \
+    } while (0)
+// Use ancient do { ... } while (0) macro trick to permit a block of
+// statements with the same syntax as a single statement.
+
+#endif /* ! defined(LL_LLCLEANUP_H) */
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 19642b0982f4680f7ea459580fb28566e86d54f5..439ff4e628e965da33163f1592d9b432eb16f331 100755
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -31,6 +31,7 @@
 #include "llthread.h"
 #include "lltrace.h"
 #include "lltracethreadrecorder.h"
+#include "llcleanup.h"
 
 //static
 BOOL LLCommon::sAprInitialized = FALSE;
@@ -63,11 +64,11 @@ void LLCommon::cleanupClass()
 	sMasterThreadRecorder = NULL;
 	LLTrace::set_master_thread_recorder(NULL);
 	LLThreadSafeRefCount::cleanupThreadSafeRefCount();
-	LLTimer::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLTimer);
 	if (sAprInitialized)
 	{
 		ll_cleanup_apr();
 		sAprInitialized = FALSE;
 	}
-	LLMemory::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLMemory);
 }
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index f2c647c2d98fdf39b4a4b5a81c5f74a14a5e8351..b662a2c2be034601b492b368685086f522c1dfad 100755
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -413,6 +413,11 @@ namespace
 
 namespace LLError
 {
+	bool is_available()
+	{
+		return Globals::instanceExists();
+	}
+
 	class SettingsConfig : public LLRefCount
 	{
 		friend class Settings;
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 56ac52e5de4edfbb8b5a17c8c34abf4bef779823..56e84f71720fb4537f2c985d72d6160b5b2e0989 100755
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -189,6 +189,11 @@ namespace LLError
 
 	LL_COMMON_API std::string abbreviateFile(const std::string& filePath);
 	LL_COMMON_API int shouldLogCallCount();
+
+	// Check whether Globals exists. This should only be used by LLSingleton
+	// infrastructure to avoid trying to log when our internal LLSingleton is
+	// unavailable -- circularity ensues.
+	LL_COMMON_API bool is_available();
 };
 
 #endif // LL_LLERRORCONTROL_H
diff --git a/indra/llcommon/llinitdestroyclass.h b/indra/llcommon/llinitdestroyclass.h
new file mode 100644
index 0000000000000000000000000000000000000000..49bcefc33d73c6167d65396ecc52efa422aaabfb
--- /dev/null
+++ b/indra/llcommon/llinitdestroyclass.h
@@ -0,0 +1,190 @@
+/**
+ * @file   llinitdestroyclass.h
+ * @author Nat Goodspeed
+ * @date   2015-05-27
+ * @brief  LLInitClass / LLDestroyClass mechanism
+ *
+ * The LLInitClass template, extracted from llui.h, ensures that control will
+ * reach a static initClass() method. LLDestroyClass does the same for a
+ * static destroyClass() method.
+ *
+ * The distinguishing characteristics of these templates are:
+ *
+ * - All LLInitClass<T>::initClass() methods are triggered by an explicit call
+ *   to LLInitClassList::instance().fireCallbacks(). Presumably this call
+ *   happens sometime after all static objects in the program have been
+ *   initialized. In other words, each LLInitClass<T>::initClass() method
+ *   should be able to make some assumptions about global program state.
+ *
+ * - Similarly, LLDestroyClass<T>::destroyClass() methods are triggered by
+ *   LLDestroyClassList::instance().fireCallbacks(). Again, presumably this
+ *   happens at a well-defined moment in the program's shutdown sequence.
+ *
+ * - The initClass() calls happen in an unspecified sequence. You may not rely
+ *   on the relative ordering of LLInitClass<T>::initClass() versus another
+ *   LLInitClass<U>::initClass() method. If you need such a guarantee, use
+ *   LLSingleton instead and make the dependency explicit.
+ *
+ * - Similarly, LLDestroyClass<T>::destroyClass() may happen either before or
+ *   after LLDestroyClass<U>::destroyClass(). You cannot rely on that order.
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Copyright (c) 2015, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLINITDESTROYCLASS_H)
+#define LL_LLINITDESTROYCLASS_H
+
+#include "llerror.h"
+#include "llsingleton.h"
+#include <boost/function.hpp>
+#include <boost/signals2/signal.hpp>
+#include <typeinfo>
+
+/**
+ * LLCallbackRegistry is an implementation detail base class for
+ * LLInitClassList and LLDestroyClassList. It's a very thin wrapper around a
+ * Boost.Signals2 signal object.
+ */
+class LLCallbackRegistry
+{
+public:
+	typedef boost::signals2::signal<void()> callback_signal_t;
+	
+	void registerCallback(const callback_signal_t::slot_type& slot)
+	{
+		mCallbacks.connect(slot);
+	}
+
+	void fireCallbacks()
+	{
+		mCallbacks();
+	}
+
+private:
+	callback_signal_t mCallbacks;
+};
+
+/**
+ * LLInitClassList is the LLCallbackRegistry for LLInitClass. It stores the
+ * registered initClass() methods. It must be an LLSingleton because
+ * LLInitClass registers its initClass() method at static construction time
+ * (before main()), requiring LLInitClassList to be fully constructed on
+ * demand regardless of module initialization order.
+ */
+class LLInitClassList : 
+	public LLCallbackRegistry, 
+	public LLSingleton<LLInitClassList>
+{
+	friend class LLSingleton<LLInitClassList>;
+private:
+	LLInitClassList() {}
+};
+
+/**
+ * LLDestroyClassList is the LLCallbackRegistry for LLDestroyClass. It stores
+ * the registered destroyClass() methods. It must be an LLSingleton because
+ * LLDestroyClass registers its destroyClass() method at static construction
+ * time (before main()), requiring LLDestroyClassList to be fully constructed
+ * on demand regardless of module initialization order.
+ */
+class LLDestroyClassList : 
+	public LLCallbackRegistry, 
+	public LLSingleton<LLDestroyClassList>
+{
+	friend class LLSingleton<LLDestroyClassList>;
+private:
+	LLDestroyClassList() {}
+};
+
+/**
+ * LLRegisterWith is an implementation detail for LLInitClass and
+ * LLDestroyClass. It is intended to be used as a static class member whose
+ * constructor registers the specified callback with the LLMumbleClassList
+ * singleton registry specified as the template argument.
+ */
+template<typename T>
+class LLRegisterWith
+{
+public:
+	LLRegisterWith(boost::function<void ()> func)
+	{
+		T::instance().registerCallback(func);
+	}
+
+	// this avoids a MSVC bug where non-referenced static members are "optimized" away
+	// even if their constructors have side effects
+	S32 reference()
+	{
+		S32 dummy;
+		dummy = 0;
+		return dummy;
+	}
+};
+
+/**
+ * Derive MyClass from LLInitClass<MyClass> (the Curiously Recurring Template
+ * Pattern) to ensure that the static method MyClass::initClass() will be
+ * called (along with all other LLInitClass<T> subclass initClass() methods)
+ * when someone calls LLInitClassList::instance().fireCallbacks(). This gives
+ * the application specific control over the timing of all such
+ * initializations, without having to insert calls for every such class into
+ * generic application code.
+ */
+template<typename T>
+class LLInitClass
+{
+public:
+	LLInitClass() { sRegister.reference(); }
+
+	// When this static member is initialized, the subclass initClass() method
+	// is registered on LLInitClassList. See sRegister definition below.
+	static LLRegisterWith<LLInitClassList> sRegister;
+private:
+
+	// Provide a default initClass() method in case subclass misspells (or
+	// omits) initClass(). This turns a potential build error into a fatal
+	// runtime error.
+	static void initClass()
+	{
+		LL_ERRS() << "No static initClass() method defined for " << typeid(T).name() << LL_ENDL;
+	}
+};
+
+/**
+ * Derive MyClass from LLDestroyClass<MyClass> (the Curiously Recurring
+ * Template Pattern) to ensure that the static method MyClass::destroyClass()
+ * will be called (along with other LLDestroyClass<T> subclass destroyClass()
+ * methods) when someone calls LLDestroyClassList::instance().fireCallbacks().
+ * This gives the application specific control over the timing of all such
+ * cleanup calls, without having to insert calls for every such class into
+ * generic application code.
+ */
+template<typename T>
+class LLDestroyClass
+{
+public:
+	LLDestroyClass() { sRegister.reference(); }
+
+	// When this static member is initialized, the subclass destroyClass()
+	// method is registered on LLInitClassList. See sRegister definition
+	// below.
+	static LLRegisterWith<LLDestroyClassList> sRegister;
+private:
+
+	// Provide a default destroyClass() method in case subclass misspells (or
+	// omits) destroyClass(). This turns a potential build error into a fatal
+	// runtime error.
+	static void destroyClass()
+	{
+		LL_ERRS() << "No static destroyClass() method defined for " << typeid(T).name() << LL_ENDL;
+	}
+};
+
+// Here's where LLInitClass<T> specifies the subclass initClass() method.
+template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister(&T::initClass);
+// Here's where LLDestroyClass<T> specifies the subclass destroyClass() method.
+template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(&T::destroyClass);
+
+#endif /* ! defined(LL_LLINITDESTROYCLASS_H) */
diff --git a/indra/llcommon/llpounceable.h b/indra/llcommon/llpounceable.h
new file mode 100644
index 0000000000000000000000000000000000000000..77b711bdc6d1cca135cbc59affdab6f8d91505b9
--- /dev/null
+++ b/indra/llcommon/llpounceable.h
@@ -0,0 +1,215 @@
+/**
+ * @file   llpounceable.h
+ * @author Nat Goodspeed
+ * @date   2015-05-22
+ * @brief  LLPounceable is tangentially related to a future: it's a holder for
+ *         a value that may or may not exist yet. Unlike a future, though,
+ *         LLPounceable freely allows reading the held value. (If the held
+ *         type T does not have a distinguished "empty" value, consider using
+ *         LLPounceable<boost::optional<T>>.)
+ *
+ *         LLPounceable::callWhenReady() is this template's claim to fame. It
+ *         allows its caller to "pounce" on the held value as soon as it
+ *         becomes non-empty. Call callWhenReady() with any C++ callable
+ *         accepting T. If the held value is already non-empty, callWhenReady()
+ *         will immediately call the callable with the held value. If the held
+ *         value is empty, though, callWhenReady() will enqueue the callable
+ *         for later. As soon as LLPounceable is assigned a non-empty held
+ *         value, it will flush the queue of deferred callables.
+ *
+ *         Consider a global LLMessageSystem* gMessageSystem. Message system
+ *         initialization happens at a very specific point during viewer
+ *         initialization. Other subsystems want to register callbacks on the
+ *         LLMessageSystem instance as soon as it's initialized, but their own
+ *         initialization may precede that. If we define gMessageSystem to be
+ *         an LLPounceable<LLMessageSystem*>, a subsystem can use
+ *         callWhenReady() to either register immediately (if gMessageSystem
+ *         is already up and runnning) or register as soon as gMessageSystem
+ *         is set with a new, initialized instance.
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Copyright (c) 2015, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLPOUNCEABLE_H)
+#define LL_LLPOUNCEABLE_H
+
+#include "llsingleton.h"
+#include <boost/noncopyable.hpp>
+#include <boost/call_traits.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
+#include <boost/utility/value_init.hpp>
+#include <boost/unordered_map.hpp>
+#include <boost/signals2/signal.hpp>
+
+// Forward declare the user template, since we want to be able to point to it
+// in some of its implementation classes.
+template <typename T, class TAG>
+class LLPounceable;
+
+template <typename T, typename TAG>
+struct LLPounceableTraits
+{
+    // Our "queue" is a signal object with correct signature.
+    typedef boost::signals2::signal<void (typename boost::call_traits<T>::param_type)> signal_t;
+    // Call callWhenReady() with any callable accepting T.
+    typedef typename signal_t::slot_type func_t;
+    // owner pointer type
+    typedef LLPounceable<T, TAG>* owner_ptr;
+};
+
+// Tag types distinguish the two different implementations of LLPounceable's
+// queue.
+struct LLPounceableQueue {};
+struct LLPounceableStatic {};
+
+// generic LLPounceableQueueImpl deliberately omitted: only the above tags are
+// legal
+template <typename T, class TAG>
+class LLPounceableQueueImpl;
+
+// The implementation selected by LLPounceableStatic uses an LLSingleton
+// because we can't count on a data member queue being initialized at the time
+// we start getting callWhenReady() calls. This is that LLSingleton.
+template <typename T>
+class LLPounceableQueueSingleton:
+    public LLSingleton<LLPounceableQueueSingleton<T> >
+{
+private:
+    typedef LLPounceableTraits<T, LLPounceableStatic> traits;
+    typedef typename traits::owner_ptr owner_ptr;
+    typedef typename traits::signal_t signal_t;
+
+    // For a given held type T, every LLPounceable<T, LLPounceableStatic>
+    // instance will call on the SAME LLPounceableQueueSingleton instance --
+    // given how class statics work. We must keep a separate queue for each
+    // LLPounceable instance. Use a hash map for that.
+    typedef boost::unordered_map<owner_ptr, signal_t> map_t;
+
+public:
+    // Disambiguate queues belonging to different LLPounceables.
+    signal_t& get(owner_ptr owner)
+    {
+        // operator[] has find-or-create semantics -- just what we want!
+        return mMap[owner];
+    }
+
+private:
+    map_t mMap;
+};
+
+// LLPounceableQueueImpl that uses the above LLSingleton
+template <typename T>
+class LLPounceableQueueImpl<T, LLPounceableStatic>
+{
+public:
+    typedef LLPounceableTraits<T, LLPounceableStatic> traits;
+    typedef typename traits::owner_ptr owner_ptr;
+    typedef typename traits::signal_t signal_t;
+
+    signal_t& get(owner_ptr owner) const
+    {
+        // this Impl contains nothing; it delegates to the Singleton
+        return LLPounceableQueueSingleton<T>::instance().get(owner);
+    }
+};
+
+// The implementation selected by LLPounceableQueue directly contains the
+// queue of interest, suitable for an LLPounceable we can trust to be fully
+// initialized when it starts getting callWhenReady() calls.
+template <typename T>
+class LLPounceableQueueImpl<T, LLPounceableQueue>
+{
+public:
+    typedef LLPounceableTraits<T, LLPounceableQueue> traits;
+    typedef typename traits::owner_ptr owner_ptr;
+    typedef typename traits::signal_t signal_t;
+
+    signal_t& get(owner_ptr)
+    {
+        return mQueue;
+    }
+
+private:
+    signal_t mQueue;
+};
+
+// LLPounceable<T> is for an LLPounceable instance on the heap or the stack.
+// LLPounceable<T, LLPounceableStatic> is for a static LLPounceable instance.
+template <typename T, class TAG=LLPounceableQueue>
+class LLPounceable: public boost::noncopyable
+{
+private:
+    typedef LLPounceableTraits<T, TAG> traits;
+    typedef typename traits::owner_ptr owner_ptr;
+    typedef typename traits::signal_t signal_t;
+
+public:
+    typedef typename traits::func_t func_t;
+
+    // By default, both the initial value and the distinguished empty value
+    // are a default-constructed T instance. However you can explicitly
+    // specify each.
+    LLPounceable(typename boost::call_traits<T>::value_type init =boost::value_initialized<T>(),
+                 typename boost::call_traits<T>::param_type empty=boost::value_initialized<T>()):
+        mHeld(init),
+        mEmpty(empty)
+    {}
+
+    // make read access to mHeld as cheap and transparent as possible
+    operator T () const { return mHeld; }
+    typename boost::remove_pointer<T>::type operator*() const { return *mHeld; }
+    typename boost::call_traits<T>::value_type operator->() const { return mHeld; }
+    // uncomment 'explicit' as soon as we allow C++11 compilation
+    /*explicit*/ operator bool() const { return bool(mHeld); }
+    bool operator!() const { return ! mHeld; }
+
+    // support both assignment (dumb ptr idiom) and reset() (smart ptr)
+    void operator=(typename boost::call_traits<T>::param_type value)
+    {
+        reset(value);
+    }
+
+    void reset(typename boost::call_traits<T>::param_type value)
+    {
+        mHeld = value;
+        // If this new value is non-empty, flush anything pending in the queue.
+        if (mHeld != mEmpty)
+        {
+            signal_t& signal(get_signal());
+            signal(mHeld);
+            signal.disconnect_all_slots();
+        }
+    }
+
+    // our claim to fame
+    void callWhenReady(const func_t& func)
+    {
+        if (mHeld != mEmpty)
+        {
+            // If the held value is already non-empty, immediately call func()
+            func(mHeld);
+        }
+        else
+        {
+            // Held value still empty, queue func() for later. By default,
+            // connect() enqueues slots in FIFO order.
+            get_signal().connect(func);
+        }
+    }
+
+private:
+    signal_t& get_signal() { return mQueue.get(this); }
+
+    // Store both the current and the empty value.
+    // MAYBE: Might be useful to delegate to LLPounceableTraits the meaning of
+    // testing for "empty." For some types we want operator!(); for others we
+    // want to compare to a distinguished value.
+    typename boost::call_traits<T>::value_type mHeld, mEmpty;
+    // This might either contain the queue (LLPounceableQueue) or delegate to
+    // an LLSingleton (LLPounceableStatic).
+    LLPounceableQueueImpl<T, TAG> mQueue;
+};
+
+#endif /* ! defined(LL_LLPOUNCEABLE_H) */
diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h
index 29950c108dbe104a54f5eb42e41583e25cb8787e..fde729f8f93e0655fc3233c287637fb828175458 100755
--- a/indra/llcommon/llregistry.h
+++ b/indra/llcommon/llregistry.h
@@ -269,7 +269,7 @@ class LLRegistrySingleton
 
 		~ScopedRegistrar()
 		{
-			if (!singleton_t::destroyed())
+			if (singleton_t::instanceExists())
 			{
 				popScope();
 			}
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index 9b49e5237717234ae6ba2179ff053e3a39cf8934..2813814ae14f759bb838d2b8e448f82254079fc8 100755
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -25,7 +25,326 @@
  */
 
 #include "linden_common.h"
-
 #include "llsingleton.h"
 
+#include "llerror.h"
+#include "llerrorcontrol.h"         // LLError::is_available()
+#include "lldependencies.h"
+#include <boost/foreach.hpp>
+#include <algorithm>
+#include <iostream>                 // std::cerr in dire emergency
+#include <sstream>
+#include <stdexcept>
+
+// Our master list of all LLSingletons is itself an LLSingleton. We used to
+// store it in a function-local static, but that could get destroyed before
+// the last of the LLSingletons -- and ~LLSingletonBase() definitely wants to
+// remove itself from the master list. Since the whole point of this master
+// list is to help track inter-LLSingleton dependencies, and since we have
+// this implicit dependency from every LLSingleton to the master list, make it
+// an LLSingleton.
+class LLSingletonBase::MasterList:
+    public LLSingleton<LLSingletonBase::MasterList>
+{
+private:
+    friend class LLSingleton<LLSingletonBase::MasterList>;
+
+public:
+    // No need to make this private with accessors; nobody outside this source
+    // file can see it.
+    LLSingletonBase::list_t mList;
+};
+
+//static
+LLSingletonBase::list_t& LLSingletonBase::get_master()
+{
+    return LLSingletonBase::MasterList::instance().mList;
+}
+
+void LLSingletonBase::add_master()
+{
+    // As each new LLSingleton is constructed, add to the master list.
+    get_master().push_back(this);
+}
+
+void LLSingletonBase::remove_master()
+{
+    // When an LLSingleton is destroyed, remove from master list.
+    // add_master() used to capture the iterator to the newly-added list item
+    // so we could directly erase() it from the master list. Unfortunately
+    // that runs afoul of destruction-dependency order problems. So search the
+    // master list, and remove this item IF FOUND. We have few enough
+    // LLSingletons, and they are so rarely destroyed (once per run), that the
+    // cost of a linear search should not be an issue.
+    get_master().remove(this);
+}
+
+// Wrapping our initializing list in a static method ensures that it will be
+// constructed on demand. This list doesn't also need to be in an LLSingleton
+// because (a) it should be empty by program shutdown and (b) none of our
+// destructors reference it.
+//static
+LLSingletonBase::list_t& LLSingletonBase::get_initializing()
+{
+    static list_t sList;
+    return sList;
+}
+
+LLSingletonBase::LLSingletonBase():
+    mCleaned(false),
+    mDeleteSingleton(NULL)
+{
+    // Make this the currently-initializing LLSingleton.
+    push_initializing();
+}
+
+LLSingletonBase::~LLSingletonBase() {}
+
+void LLSingletonBase::push_initializing()
+{
+    get_initializing().push_back(this);
+}
+
+void LLSingletonBase::pop_initializing()
+{
+    list_t& list(get_initializing());
+    if (list.empty())
+    {
+        logerrs("Underflow in stack of currently-initializing LLSingletons at ",
+                typeid(*this).name(), "::getInstance()");
+    }
+    if (list.back() != this)
+    {
+        logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ",
+                typeid(*this).name(), "::getInstance() trying to pop ",
+                typeid(*list.back()).name());
+    }
+    // Here we're sure that list.back() == this. Whew, pop it.
+    list.pop_back();
+}
+
+void LLSingletonBase::capture_dependency(EInitState initState)
+{
+    // Did this getInstance() call come from another LLSingleton, or from
+    // vanilla application code? Note that although this is a nontrivial
+    // method, the vast majority of its calls arrive here with initializing
+    // empty().
+    list_t& initializing(get_initializing());
+    if (! initializing.empty())
+    {
+        // getInstance() is being called by some other LLSingleton. But -- is
+        // this a circularity? That is, does 'this' already appear in the
+        // initializing stack?
+        // For what it's worth, normally 'initializing' should contain very
+        // few elements.
+        list_t::const_iterator found =
+            std::find(initializing.begin(), initializing.end(), this);
+        if (found != initializing.end())
+        {
+            // Report the circularity. Requiring the coder to dig through the
+            // logic to diagnose exactly how we got here is less than helpful.
+            std::ostringstream out;
+            for ( ; found != initializing.end(); ++found)
+            {
+                // 'found' is an iterator; *found is an LLSingletonBase*; **found
+                // is the actual LLSingletonBase instance.
+                out << typeid(**found).name() << " -> ";
+            }
+            // We promise to capture dependencies from both the constructor
+            // and the initSingleton() method, so an LLSingleton's instance
+            // pointer is on the initializing list during both. Now that we've
+            // detected circularity, though, we must distinguish the two. If
+            // the recursive call is from the constructor, we CAN'T honor it:
+            // otherwise we'd be returning a pointer to a partially-
+            // constructed object! But from initSingleton() is okay: that
+            // method exists specifically to support circularity.
+            // Decide which log helper to call based on initState. They have
+            // identical signatures.
+            ((initState == CONSTRUCTING)? logerrs : logwarns)
+                ("LLSingleton circularity: ", out.str().c_str(), typeid(*this).name(), "");
+        }
+        else
+        {
+            // Here 'this' is NOT already in the 'initializing' stack. Great!
+            // Record the dependency.
+            // initializing.back() is the LLSingletonBase* currently being
+            // initialized. Store 'this' in its mDepends set.
+            initializing.back()->mDepends.insert(this);
+        }
+    }
+}
+
+//static
+LLSingletonBase::vec_t LLSingletonBase::dep_sort()
+{
+    // While it would theoretically be possible to maintain a static
+    // SingletonDeps through the life of the program, dynamically adding and
+    // removing LLSingletons as they are created and destroyed, in practice
+    // it's less messy to construct it on demand. The overhead of doing so
+    // should happen basically twice: once for cleanupAll(), once for
+    // deleteAll().
+    typedef LLDependencies<LLSingletonBase*> SingletonDeps;
+    SingletonDeps sdeps;
+    list_t& master(get_master());
+    BOOST_FOREACH(LLSingletonBase* sp, master)
+    {
+        // Build the SingletonDeps structure by adding, for each
+        // LLSingletonBase* sp in the master list, sp itself. It has no
+        // associated value type in our SingletonDeps, hence the 0. We don't
+        // record the LLSingletons it must follow; rather, we record the ones
+        // it must precede. Copy its mDepends to a KeyList to express that.
+        sdeps.add(sp, 0,
+                  SingletonDeps::KeyList(),
+                  SingletonDeps::KeyList(sp->mDepends.begin(), sp->mDepends.end()));
+    }
+    vec_t ret;
+    ret.reserve(master.size());
+    // We should be able to effect this with a transform_iterator that
+    // extracts just the first (key) element from each sorted_iterator, then
+    // uses vec_t's range constructor... but frankly this is more
+    // straightforward, as long as we remember the above reserve() call!
+    BOOST_FOREACH(SingletonDeps::sorted_iterator::value_type pair, sdeps.sort())
+    {
+        ret.push_back(pair.first);
+    }
+    // The master list is not itself pushed onto the master list. Add it as
+    // the very last entry -- it is the LLSingleton on which ALL others
+    // depend! -- so our caller will process it.
+    ret.push_back(MasterList::getInstance());
+    return ret;
+}
+
+//static
+void LLSingletonBase::cleanupAll()
+{
+    // It's essential to traverse these in dependency order.
+    BOOST_FOREACH(LLSingletonBase* sp, dep_sort())
+    {
+        // Call cleanupSingleton() only if we haven't already done so for this
+        // instance.
+        if (! sp->mCleaned)
+        {
+            sp->mCleaned = true;
+
+            try
+            {
+                sp->cleanupSingleton();
+            }
+            catch (const std::exception& e)
+            {
+                logwarns("Exception in ", typeid(*sp).name(),
+                         "::cleanupSingleton(): ", e.what());
+            }
+            catch (...)
+            {
+                logwarns("Unknown exception in ", typeid(*sp).name(),
+                         "::cleanupSingleton()");
+            }
+        }
+    }
+}
+
+//static
+void LLSingletonBase::deleteAll()
+{
+    // It's essential to traverse these in dependency order.
+    BOOST_FOREACH(LLSingletonBase* sp, dep_sort())
+    {
+        // Capture the class name first: in case of exception, don't count on
+        // being able to extract it later.
+        const char* name = typeid(*sp).name();
+        try
+        {
+            // Call static method through instance function pointer.
+            if (! sp->mDeleteSingleton)
+            {
+                // This Should Not Happen... but carry on.
+                logwarns(name, "::mDeleteSingleton not initialized!");
+            }
+            else
+            {
+                // properly initialized: call it.
+                // From this point on, DO NOT DEREFERENCE sp!
+                sp->mDeleteSingleton();
+            }
+        }
+        catch (const std::exception& e)
+        {
+            logwarns("Exception in ", name, "::deleteSingleton(): ", e.what());
+        }
+        catch (...)
+        {
+            logwarns("Unknown exception in ", name, "::deleteSingleton()");
+        }
+    }
+}
+
+/*------------------------ Final cleanup management ------------------------*/
+class LLSingletonBase::MasterRefcount
+{
+public:
+    // store a POD int so it will be statically initialized to 0
+    int refcount;
+};
+static LLSingletonBase::MasterRefcount sMasterRefcount;
+
+LLSingletonBase::ref_ptr_t LLSingletonBase::get_master_refcount()
+{
+    // Calling this method constructs a new ref_ptr_t, which implicitly calls
+    // intrusive_ptr_add_ref(MasterRefcount*).
+    return &sMasterRefcount;
+}
+
+void intrusive_ptr_add_ref(LLSingletonBase::MasterRefcount* mrc)
+{
+    // Count outstanding SingletonLifetimeManager instances.
+    ++mrc->refcount;
+}
+
+void intrusive_ptr_release(LLSingletonBase::MasterRefcount* mrc)
+{
+    // Notice when each SingletonLifetimeManager instance is destroyed.
+    if (! --mrc->refcount)
+    {
+        // The last instance was destroyed. Time to kill any remaining
+        // LLSingletons -- but in dependency order.
+        LLSingletonBase::deleteAll();
+    }
+}
+
+/*---------------------------- Logging helpers -----------------------------*/
+//static
+void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, const char* p4)
+{
+    // Check LLError::is_available() because some of LLError's infrastructure
+    // is itself an LLSingleton. If that LLSingleton has not yet been
+    // initialized, trying to log will engage LLSingleton machinery... and
+    // around and around we go.
+    if (LLError::is_available())
+    {
+        LL_ERRS() << p1 << p2 << p3 << p4 << LL_ENDL;
+    }
+    else
+    {
+        // Caller may be a test program, or something else whose stderr is
+        // visible to the user.
+        std::cerr << p1 << p2 << p3 << p4 << std::endl;
+        // The other important side effect of LL_ERRS() is
+        // https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG)
+        LLError::crashAndLoop(std::string());
+    }
+}
 
+//static
+void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3, const char* p4)
+{
+    // See logerrs() remarks about is_available().
+    if (LLError::is_available())
+    {
+        LL_WARNS() << p1 << p2 << p3 << p4 << LL_ENDL;
+    }
+    else
+    {
+        std::cerr << p1 << p2 << p3 << p4 << std::endl;
+    }
+}
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 6e6291a1653c97ac014a4913b937747898697542..a82101c367da87c517bce904a5d5c6b004e03919 100755
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -25,185 +25,385 @@
 #ifndef LLSINGLETON_H
 #define LLSINGLETON_H
 
-#include "llerror.h"	// *TODO: eliminate this
-
-#include <typeinfo>
 #include <boost/noncopyable.hpp>
+#include <boost/unordered_set.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <list>
+#include <vector>
+#include <typeinfo>
+
+// TODO:
+// Tests for all this!
+class LLSingletonBase: private boost::noncopyable
+{
+public:
+    class MasterList;
+    class MasterRefcount;
+    typedef boost::intrusive_ptr<MasterRefcount> ref_ptr_t;
+
+private:
+    // All existing LLSingleton instances are tracked in this master list.
+    typedef std::list<LLSingletonBase*> list_t;
+    static list_t& get_master();
+    // This, on the other hand, is a stack whose top indicates the LLSingleton
+    // currently being initialized.
+    static list_t& get_initializing();
+    // Produce a vector<LLSingletonBase*> of master list, in dependency order.
+    typedef std::vector<LLSingletonBase*> vec_t;
+    static vec_t dep_sort();
+
+    bool mCleaned;                  // cleanupSingleton() has been called
+    // we directly depend on these other LLSingletons
+    typedef boost::unordered_set<LLSingletonBase*> set_t;
+    set_t mDepends;
+
+protected:
+    typedef enum e_init_state
+    {
+        UNINITIALIZED = 0,          // must be default-initialized state
+        CONSTRUCTING,
+        INITIALIZING,
+        INITIALIZED,
+        DELETED
+    } EInitState;
+
+    // Base-class constructor should only be invoked by the DERIVED_TYPE
+    // constructor.
+    LLSingletonBase();
+    virtual ~LLSingletonBase();
+
+    // Every new LLSingleton should be added to/removed from the master list
+    void add_master();
+    void remove_master();
+    // with a little help from our friends.
+    template <class T> friend struct LLSingleton_manage_master;
+
+    // Maintain a stack of the LLSingleton subclass instance currently being
+    // initialized. We use this to notice direct dependencies: we want to know
+    // if A requires B. We deduce that if while initializing A, control
+    // reaches B::getInstance().
+    // We want &A to be at the top of that stack during both A::A() and
+    // A::initSingleton(), since a call to B::getInstance() might occur during
+    // either.
+    // Unfortunately the desired timespan does not correspond neatly with a
+    // single C++ scope, else we'd use RAII to track it. But we do know that
+    // LLSingletonBase's constructor definitely runs just before
+    // LLSingleton's, which runs just before the specific subclass's.
+    void push_initializing();
+    // LLSingleton is, and must remain, the only caller to initSingleton().
+    // That being the case, we control exactly when it happens -- and we can
+    // pop the stack immediately thereafter.
+    void pop_initializing();
+    // If a given call to B::getInstance() happens during either A::A() or
+    // A::initSingleton(), record that A directly depends on B.
+    void capture_dependency(EInitState);
+
+    // delegate LL_ERRS() logging to llsingleton.cpp
+    static void logerrs(const char* p1, const char* p2="",
+                        const char* p3="", const char* p4="");
+    // delegate LL_WARNS() logging to llsingleton.cpp
+    static void logwarns(const char* p1, const char* p2="",
+                         const char* p3="", const char* p4="");
+
+    // obtain canonical ref_ptr_t
+    static ref_ptr_t get_master_refcount();
+
+    // Default methods in case subclass doesn't declare them.
+    virtual void initSingleton() {}
+    virtual void cleanupSingleton() {}
+
+    // deleteSingleton() isn't -- and shouldn't be -- a virtual method. It's a
+    // class static. However, given only Foo*, deleteAll() does need to be
+    // able to reach Foo::deleteSingleton(). Make LLSingleton (which declares
+    // deleteSingleton()) store a pointer here. Since we know it's a static
+    // class method, a classic-C function pointer will do.
+    void (*mDeleteSingleton)();
 
-// LLSingleton implements the getInstance() method part of the Singleton
-// pattern. It can't make the derived class constructors protected, though, so
-// you have to do that yourself.
-//
-// There are two ways to use LLSingleton. The first way is to inherit from it
-// while using the typename that you'd like to be static as the template
-// parameter, like so:
-//
-//   class Foo: public LLSingleton<Foo>{};
-//
-//   Foo& instance = Foo::instance();
-//
-// The second way is to use the singleton class directly, without inheritance:
-//
-//   typedef LLSingleton<Foo> FooSingleton;
-//
-//   Foo& instance = FooSingleton::instance();
-//
-// In this case, the class being managed as a singleton needs to provide an
-// initSingleton() method since the LLSingleton virtual method won't be
-// available
-//
-// As currently written, it is not thread-safe.
+public:
+    /**
+     * Call this to call the cleanupSingleton() method for every LLSingleton
+     * constructed since the start of the last cleanupAll() call. (Any
+     * LLSingleton constructed DURING a cleanupAll() call won't be cleaned up
+     * until the next cleanupAll() call.) cleanupSingleton() neither deletes
+     * nor destroys its LLSingleton; therefore it's safe to include logic that
+     * might take significant realtime or even throw an exception.
+     *
+     * The most important property of cleanupAll() is that cleanupSingleton()
+     * methods are called in dependency order, leaf classes last. Thus, given
+     * two LLSingleton subclasses A and B, if A's dependency on B is properly
+     * expressed as a B::getInstance() or B::instance() call during either
+     * A::A() or A::initSingleton(), B will be cleaned up after A.
+     *
+     * If a cleanupSingleton() method throws an exception, the exception is
+     * logged, but cleanupAll() attempts to continue calling the rest of the
+     * cleanupSingleton() methods.
+     */
+    static void cleanupAll();
+    /**
+     * Call this to call the deleteSingleton() method for every LLSingleton
+     * constructed since the start of the last deleteAll() call. (Any
+     * LLSingleton constructed DURING a deleteAll() call won't be cleaned up
+     * until the next deleteAll() call.) deleteSingleton() deletes and
+     * destroys its LLSingleton. Any cleanup logic that might take significant
+     * realtime -- or throw an exception -- must not be placed in your
+     * LLSingleton's destructor, but rather in its cleanupSingleton() method.
+     *
+     * The most important property of deleteAll() is that deleteSingleton()
+     * methods are called in dependency order, leaf classes last. Thus, given
+     * two LLSingleton subclasses A and B, if A's dependency on B is properly
+     * expressed as a B::getInstance() or B::instance() call during either
+     * A::A() or A::initSingleton(), B will be cleaned up after A.
+     *
+     * If a deleteSingleton() method throws an exception, the exception is
+     * logged, but deleteAll() attempts to continue calling the rest of the
+     * deleteSingleton() methods.
+     */
+    static void deleteAll();
+};
+
+// support ref_ptr_t
+void intrusive_ptr_add_ref(LLSingletonBase::MasterRefcount*);
+void intrusive_ptr_release(LLSingletonBase::MasterRefcount*);
+
+// Most of the time, we want LLSingleton_manage_master() to forward its
+// methods to LLSingletonBase::add_master() and remove_master().
+template <class T>
+struct LLSingleton_manage_master
+{
+    void add(LLSingletonBase* sb) { sb->add_master(); }
+    void remove(LLSingletonBase* sb) { sb->remove_master(); }
+};
+
+// But for the specific case of LLSingletonBase::MasterList, don't.
+template <>
+struct LLSingleton_manage_master<LLSingletonBase::MasterList>
+{
+    void add(LLSingletonBase*) {}
+    void remove(LLSingletonBase*) {}
+};
 
+/**
+ * LLSingleton implements the getInstance() method part of the Singleton
+ * pattern. It can't make the derived class constructors protected, though, so
+ * you have to do that yourself.
+ *
+ * Derive your class from LLSingleton, passing your subclass name as
+ * LLSingleton's template parameter, like so:
+ *
+ *   class Foo: public LLSingleton<Foo>{};
+ *
+ *   Foo& instance = Foo::instance();
+ *
+ * LLSingleton recognizes a couple special methods in your derived class.
+ *
+ * If you override LLSingleton<T>::initSingleton(), your method will be called
+ * immediately after the instance is constructed. This is useful for breaking
+ * circular dependencies: if you find that your LLSingleton subclass
+ * constructor references other LLSingleton subclass instances in a chain
+ * leading back to yours, move the instance reference from your constructor to
+ * your initSingleton() method.
+ *
+ * If you override LLSingleton<T>::cleanupSingleton(), your method will be
+ * called if someone calls LLSingletonBase::cleanupAll(). The significant part
+ * of this promise is that cleanupAll() will call individual
+ * cleanupSingleton() methods in reverse dependency order.
+ *
+ * That is, consider LLSingleton subclasses C, B and A. A depends on B, which
+ * in turn depends on C. These dependencies are expressed as calls to
+ * B::instance() or B::getInstance(), and C::instance() or C::getInstance().
+ * It shouldn't matter whether these calls appear in A::A() or
+ * A::initSingleton(), likewise B::B() or B::initSingleton().
+ *
+ * We promise that if you later call LLSingletonBase::cleanupAll():
+ * 1. A::cleanupSingleton() will be called before
+ * 2. B::cleanupSingleton(), which will be called before
+ * 3. C::cleanupSingleton().
+ * Put differently, if your LLSingleton subclass constructor or
+ * initSingleton() method explicitly depends on some other LLSingleton
+ * subclass, you may continue to rely on that other subclass in your
+ * cleanupSingleton() method.
+ *
+ * We introduce a special cleanupSingleton() method because cleanupSingleton()
+ * operations can involve nontrivial realtime, or might throw an exception. A
+ * destructor should do neither!
+ *
+ * If your cleanupSingleton() method throws an exception, we log that
+ * exception but proceed with the remaining cleanupSingleton() calls.
+ *
+ * Similarly, if at some point you call LLSingletonBase::deleteAll(), all
+ * remaining LLSingleton instances will be destroyed in dependency order. (Or
+ * call MySubclass::deleteSingleton() to specifically destroy the canonical
+ * MySubclass instance.)
+ *
+ * As currently written, LLSingleton is not thread-safe.
+ */
 template <typename DERIVED_TYPE>
-class LLSingleton : private boost::noncopyable
+class LLSingleton : public LLSingletonBase
 {
-	
 private:
-	typedef enum e_init_state
-	{
-		UNINITIALIZED,
-		CONSTRUCTING,
-		INITIALIZING,
-		INITIALIZED,
-		DELETED
-	} EInitState;
-    
     static DERIVED_TYPE* constructSingleton()
     {
         return new DERIVED_TYPE();
     }
-	
-	// stores pointer to singleton instance
-	struct SingletonLifetimeManager
-	{
-		SingletonLifetimeManager()
-		{
-			construct();
-		}
-
-		static void construct()
-		{
-			sData.mInitState = CONSTRUCTING;
-			sData.mInstance = constructSingleton();
-			sData.mInitState = INITIALIZING;
-		}
-
-		~SingletonLifetimeManager()
-		{
-			if (sData.mInitState != DELETED)
-			{
-				deleteSingleton();
-			}
-		}
-	};
-	
+
+    // stores pointer to singleton instance
+    struct SingletonLifetimeManager
+    {
+        SingletonLifetimeManager():
+            mMasterRefcount(LLSingletonBase::get_master_refcount())
+        {
+            construct();
+        }
+
+        static void construct()
+        {
+            sData.mInitState = CONSTRUCTING;
+            sData.mInstance = constructSingleton();
+            sData.mInitState = INITIALIZING;
+        }
+
+        ~SingletonLifetimeManager()
+        {
+            // The dependencies between LLSingletons, and the arbitrary order
+            // of static-object destruction, mean that we DO NOT WANT this
+            // destructor to delete this LLSingleton. This destructor will run
+            // without regard to any other LLSingleton whose cleanup might
+            // depend on its existence. What we really want is to count the
+            // runtime's attempts to cleanup LLSingleton static data -- and on
+            // the very last one, call LLSingletonBase::deleteAll(). That
+            // method will properly honor cross-LLSingleton dependencies. This
+            // is why we store an intrusive_ptr to a MasterRefcount: our
+            // ref_ptr_t member counts SingletonLifetimeManager instances.
+            // Once the runtime destroys the last of these, THEN we can delete
+            // every remaining LLSingleton.
+        }
+
+        LLSingletonBase::ref_ptr_t mMasterRefcount;
+    };
+
+protected:
+    LLSingleton()
+    {
+        // populate base-class function pointer with the static
+        // deleteSingleton() function for this particular specialization
+        mDeleteSingleton = &deleteSingleton;
+
+        // add this new instance to the master list
+        LLSingleton_manage_master<DERIVED_TYPE>().add(this);
+    }
+
 public:
-	virtual ~LLSingleton()
-	{
-		sData.mInstance = NULL;
-		sData.mInitState = DELETED;
-	}
-
-	/**
-	 * @brief Immediately delete the singleton.
-	 *
-	 * A subsequent call to LLProxy::getInstance() will construct a new
-	 * instance of the class.
-	 *
-	 * LLSingletons are normally destroyed after main() has exited and the C++
-	 * runtime is cleaning up statically-constructed objects. Some classes
-	 * derived from LLSingleton have objects that are part of a runtime system
-	 * that is terminated before main() exits. Calling the destructor of those
-	 * objects after the termination of their respective systems can cause
-	 * crashes and other problems during termination of the project. Using this
-	 * method to destroy the singleton early can prevent these crashes.
-	 *
-	 * An example where this is needed is for a LLSingleton that has an APR
-	 * object as a member that makes APR calls on destruction. The APR system is
-	 * shut down explicitly before main() exits. This causes a crash on exit.
-	 * Using this method before the call to apr_terminate() and NOT calling
-	 * getInstance() again will prevent the crash.
-	 */
-	static void deleteSingleton()
-	{
-		delete sData.mInstance;
-		sData.mInstance = NULL;
-		sData.mInitState = DELETED;
-	}
-
-
-	static DERIVED_TYPE* getInstance()
-	{
-		static SingletonLifetimeManager sLifeTimeMgr;
-
-		switch (sData.mInitState)
-		{
-		case UNINITIALIZED:
-			// should never be uninitialized at this point
-			llassert(false);
-			return NULL;
-		case CONSTRUCTING:
-			LL_ERRS() << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << LL_ENDL;
-			return NULL;
-		case INITIALIZING:
-			// go ahead and flag ourselves as initialized so we can be reentrant during initialization
-			sData.mInitState = INITIALIZED;	
-			// initialize singleton after constructing it so that it can reference other singletons which in turn depend on it,
-			// thus breaking cyclic dependencies
-			sData.mInstance->initSingleton(); 
-			return sData.mInstance;
-		case INITIALIZED:
-			return sData.mInstance;
-		case DELETED:
-			LL_WARNS() << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << LL_ENDL;
-			SingletonLifetimeManager::construct();
-			// same as first time construction
-			sData.mInitState = INITIALIZED;	
-			sData.mInstance->initSingleton(); 
-			return sData.mInstance;
-		}
-
-		return NULL;
-	}
-
-	static DERIVED_TYPE* getIfExists()
-	{
-		return sData.mInstance;
-	}
-
-	// Reference version of getInstance()
-	// Preferred over getInstance() as it disallows checking for NULL
-	static DERIVED_TYPE& instance()
-	{
-		return *getInstance();
-	}
-	
-	// Has this singleton been created uet?
-	// Use this to avoid accessing singletons before the can safely be constructed
-	static bool instanceExists()
-	{
-		return sData.mInitState == INITIALIZED;
-	}
-	
-	// Has this singleton already been deleted?
-	// Use this to avoid accessing singletons from a static object's destructor
-	static bool destroyed()
-	{
-		return sData.mInitState == DELETED;
-	}
+    virtual ~LLSingleton()
+    {
+        // remove this instance from the master list
+        LLSingleton_manage_master<DERIVED_TYPE>().remove(this);
+        sData.mInstance = NULL;
+        sData.mInitState = DELETED;
+    }
 
-private:
+    /**
+     * @brief Immediately delete the singleton.
+     *
+     * A subsequent call to LLProxy::getInstance() will construct a new
+     * instance of the class.
+     *
+     * Without an explicit call to LLSingletonBase::deleteAll(), LLSingletons
+     * are implicitly destroyed after main() has exited and the C++ runtime is
+     * cleaning up statically-constructed objects. Some classes derived from
+     * LLSingleton have objects that are part of a runtime system that is
+     * terminated before main() exits. Calling the destructor of those objects
+     * after the termination of their respective systems can cause crashes and
+     * other problems during termination of the project. Using this method to
+     * destroy the singleton early can prevent these crashes.
+     *
+     * An example where this is needed is for a LLSingleton that has an APR
+     * object as a member that makes APR calls on destruction. The APR system is
+     * shut down explicitly before main() exits. This causes a crash on exit.
+     * Using this method before the call to apr_terminate() and NOT calling
+     * getInstance() again will prevent the crash.
+     */
+    static void deleteSingleton()
+    {
+        delete sData.mInstance;
+        sData.mInstance = NULL;
+        sData.mInitState = DELETED;
+    }
+
+    static DERIVED_TYPE* getInstance()
+    {
+        static SingletonLifetimeManager sLifeTimeMgr;
+
+        switch (sData.mInitState)
+        {
+        case UNINITIALIZED:
+            // should never be uninitialized at this point
+            logerrs("Uninitialized singleton ", typeid(DERIVED_TYPE).name());
+            return NULL;
+
+        case CONSTRUCTING:
+            logerrs("Tried to access singleton ", typeid(DERIVED_TYPE).name(),
+                    " from singleton constructor!");
+            return NULL;
 
-	virtual void initSingleton() {}
+        case INITIALIZING:
+            // go ahead and flag ourselves as initialized so we can be
+            // reentrant during initialization
+            sData.mInitState = INITIALIZED; 
+            // initialize singleton after constructing it so that it can
+            // reference other singletons which in turn depend on it, thus
+            // breaking cyclic dependencies
+            sData.mInstance->initSingleton();
+            // pop this off stack of initializing singletons
+            sData.mInstance->pop_initializing();
+            break;
+
+        case INITIALIZED:
+            break;
+
+        case DELETED:
+            logwarns("Trying to access deleted singleton ", typeid(DERIVED_TYPE).name(),
+                     " -- creating new instance");
+            SingletonLifetimeManager::construct();
+            // same as first time construction
+            sData.mInitState = INITIALIZED; 
+            sData.mInstance->initSingleton(); 
+            // pop this off stack of initializing singletons
+            sData.mInstance->pop_initializing();
+            break;
+        }
+
+        // By this point, if DERIVED_TYPE was pushed onto the initializing
+        // stack, it has been popped off. So the top of that stack, if any, is
+        // an LLSingleton that directly depends on DERIVED_TYPE. If this call
+        // came from another LLSingleton, rather than from vanilla application
+        // code, record the dependency.
+        sData.mInstance->capture_dependency(sData.mInitState);
+        return sData.mInstance;
+    }
 
-	struct SingletonData
-	{
-		// explicitly has a default constructor so that member variables are zero initialized in BSS
-		// and only changed by singleton logic, not constructor running during startup
-		EInitState		mInitState;
-		DERIVED_TYPE*	mInstance;
-	};
-	static SingletonData sData;
+    // Reference version of getInstance()
+    // Preferred over getInstance() as it disallows checking for NULL
+    static DERIVED_TYPE& instance()
+    {
+        return *getInstance();
+    }
+
+    // Has this singleton been created yet?
+    // Use this to avoid accessing singletons before they can safely be constructed.
+    static bool instanceExists()
+    {
+        return sData.mInitState == INITIALIZED;
+    }
+
+private:
+    struct SingletonData
+    {
+        // explicitly has a default constructor so that member variables are zero initialized in BSS
+        // and only changed by singleton logic, not constructor running during startup
+        EInitState      mInitState;
+        DERIVED_TYPE*   mInstance;
+    };
+    static SingletonData sData;
 };
 
 template<typename T>
diff --git a/indra/llcommon/tests/llpounceable_test.cpp b/indra/llcommon/tests/llpounceable_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2f4915ce11a4eb7f4f76cc032dd12890e370dd19
--- /dev/null
+++ b/indra/llcommon/tests/llpounceable_test.cpp
@@ -0,0 +1,230 @@
+/**
+ * @file   llpounceable_test.cpp
+ * @author Nat Goodspeed
+ * @date   2015-05-22
+ * @brief  Test for llpounceable.
+ * 
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Copyright (c) 2015, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llpounceable.h"
+// STL headers
+// std headers
+// external library headers
+#include <boost/bind.hpp>
+// other Linden headers
+#include "../test/lltut.h"
+
+/*----------------------------- string testing -----------------------------*/
+void append(std::string* dest, const std::string& src)
+{
+    dest->append(src);
+}
+
+/*-------------------------- Data-struct testing ---------------------------*/
+struct Data
+{
+    Data(const std::string& data):
+        mData(data)
+    {}
+    const std::string mData;
+};
+
+void setter(Data** dest, Data* ptr)
+{
+    *dest = ptr;
+}
+
+static Data* static_check = 0;
+
+// Set up an extern pointer to an LLPounceableStatic so the linker will fill
+// in the forward reference from below, before runtime.
+extern LLPounceable<Data*, LLPounceableStatic> gForward;
+
+struct EnqueueCall
+{
+    EnqueueCall()
+    {
+        // Intentionally use a forward reference to an LLPounceableStatic that
+        // we believe is NOT YET CONSTRUCTED. This models the scenario in
+        // which a constructor in another translation unit runs before
+        // constructors in this one. We very specifically want callWhenReady()
+        // to work even in that case: we need the LLPounceableQueueImpl to be
+        // initialized even if the LLPounceable itself is not.
+        gForward.callWhenReady(boost::bind(setter, &static_check, _1));
+    }
+} nqcall;
+// When this declaration is processed, we should enqueue the
+// setter(&static_check, _1) call for when gForward is set non-NULL. Needless
+// to remark, we want this call not to crash.
+
+// Now declare gForward. Its constructor should not run until after nqcall's.
+LLPounceable<Data*, LLPounceableStatic> gForward;
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct llpounceable_data
+    {
+    };
+    typedef test_group<llpounceable_data> llpounceable_group;
+    typedef llpounceable_group::object object;
+    llpounceable_group llpounceablegrp("llpounceable");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("LLPounceableStatic out-of-order test");
+        // LLPounceable<T, LLPounceableStatic>::callWhenReady() must work even
+        // before LLPounceable's constructor runs. That's the whole point of
+        // implementing it with an LLSingleton queue. This models (say)
+        // LLPounceableStatic<LLMessageSystem*, LLPounceableStatic>.
+        ensure("static_check should still be null", ! static_check);
+        Data myData("test<1>");
+        gForward = &myData;         // should run setter
+        ensure_equals("static_check should be &myData", static_check, &myData);
+    }
+
+    template<> template<>
+    void object::test<2>()
+    {
+        set_test_name("LLPounceableQueue different queues");
+        // We expect that LLPounceable<T, LLPounceableQueue> should have
+        // different queues because that specialization stores the queue
+        // directly in the LLPounceable instance.
+        Data *aptr = 0, *bptr = 0;
+        LLPounceable<Data*> a, b;
+        a.callWhenReady(boost::bind(setter, &aptr, _1));
+        b.callWhenReady(boost::bind(setter, &bptr, _1));
+        ensure("aptr should be null", ! aptr);
+        ensure("bptr should be null", ! bptr);
+        Data adata("a"), bdata("b");
+        a = &adata;
+        ensure_equals("aptr should be &adata", aptr, &adata);
+        // but we haven't yet set b
+        ensure("bptr should still be null", !bptr);
+        b = &bdata;
+        ensure_equals("bptr should be &bdata", bptr, &bdata);
+    }
+
+    template<> template<>
+    void object::test<3>()
+    {
+        set_test_name("LLPounceableStatic different queues");
+        // LLPounceable<T, LLPounceableStatic> should also have a distinct
+        // queue for each instance, but that engages an additional map lookup
+        // because there's only one LLSingleton for each T.
+        Data *aptr = 0, *bptr = 0;
+        LLPounceable<Data*, LLPounceableStatic> a, b;
+        a.callWhenReady(boost::bind(setter, &aptr, _1));
+        b.callWhenReady(boost::bind(setter, &bptr, _1));
+        ensure("aptr should be null", ! aptr);
+        ensure("bptr should be null", ! bptr);
+        Data adata("a"), bdata("b");
+        a = &adata;
+        ensure_equals("aptr should be &adata", aptr, &adata);
+        // but we haven't yet set b
+        ensure("bptr should still be null", !bptr);
+        b = &bdata;
+        ensure_equals("bptr should be &bdata", bptr, &bdata);
+    }
+
+    template<> template<>
+    void object::test<4>()
+    {
+        set_test_name("LLPounceable<T> looks like T");
+        // We want LLPounceable<T, TAG> to be drop-in replaceable for a plain
+        // T for read constructs. In particular, it should behave like a dumb
+        // pointer -- and with zero abstraction cost for such usage.
+        Data* aptr = 0;
+        Data a("a");
+        // should be able to initialize a pounceable (when its constructor
+        // runs)
+        LLPounceable<Data*> pounceable(&a);
+        // should be able to pass LLPounceable<T> to function accepting T
+        setter(&aptr, pounceable);
+        ensure_equals("aptr should be &a", aptr, &a);
+        // should be able to dereference with *
+        ensure_equals("deref with *", (*pounceable).mData, "a");
+        // should be able to dereference with ->
+        ensure_equals("deref with ->", pounceable->mData, "a");
+        // bool operations
+        ensure("test with operator bool()", pounceable);
+        ensure("test with operator !()", ! (! pounceable));
+    }
+
+    template<> template<>
+    void object::test<5>()
+    {
+        set_test_name("Multiple callWhenReady() queue items");
+        Data *p1 = 0, *p2 = 0, *p3 = 0;
+        Data a("a");
+        LLPounceable<Data*> pounceable;
+        // queue up a couple setter() calls for later
+        pounceable.callWhenReady(boost::bind(setter, &p1, _1));
+        pounceable.callWhenReady(boost::bind(setter, &p2, _1));
+        // should still be pending
+        ensure("p1 should be null", !p1);
+        ensure("p2 should be null", !p2);
+        ensure("p3 should be null", !p3);
+        pounceable = 0;
+        // assigning a new empty value shouldn't flush the queue
+        ensure("p1 should still be null", !p1);
+        ensure("p2 should still be null", !p2);
+        ensure("p3 should still be null", !p3);
+        // using whichever syntax
+        pounceable.reset(0);
+        // try to make ensure messages distinct... tough to pin down which
+        // ensure() failed if multiple ensure() calls in the same test<n> have
+        // the same message!
+        ensure("p1 should again be null", !p1);
+        ensure("p2 should again be null", !p2);
+        ensure("p3 should again be null", !p3);
+        pounceable.reset(&a);       // should flush queue
+        ensure_equals("p1 should be &a", p1, &a);
+        ensure_equals("p2 should be &a", p2, &a);
+        ensure("p3 still not set", !p3);
+        // immediate call
+        pounceable.callWhenReady(boost::bind(setter, &p3, _1));
+        ensure_equals("p3 should be &a", p3, &a);
+    }
+
+    template<> template<>
+    void object::test<6>()
+    {
+        set_test_name("queue order");
+        std::string data;
+        LLPounceable<std::string*> pounceable;
+        pounceable.callWhenReady(boost::bind(append, _1, "a"));
+        pounceable.callWhenReady(boost::bind(append, _1, "b"));
+        pounceable.callWhenReady(boost::bind(append, _1, "c"));
+        pounceable = &data;
+        ensure_equals("callWhenReady() must preserve chronological order",
+                      data, "abc");
+
+        std::string data2;
+        pounceable = NULL;
+        pounceable.callWhenReady(boost::bind(append, _1, "d"));
+        pounceable.callWhenReady(boost::bind(append, _1, "e"));
+        pounceable.callWhenReady(boost::bind(append, _1, "f"));
+        pounceable = &data2;
+        ensure_equals("LLPounceable must reset queue when fired",
+                      data2, "def");
+    }
+
+    template<> template<>
+    void object::test<7>()
+    {
+        set_test_name("compile-fail test, uncomment to check");
+        // The following declaration should fail: only LLPounceableQueue and
+        // LLPounceableStatic should work as tags.
+//      LLPounceable<Data*, int> pounceable;
+    }
+} // namespace tut
diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp
index 385289aefef69b16997148840929fe7b94963c3f..bed436283a501dc9e0ce0a1d2dfbd092bd894e1b 100755
--- a/indra/llcommon/tests/llsingleton_test.cpp
+++ b/indra/llcommon/tests/llsingleton_test.cpp
@@ -65,7 +65,6 @@ namespace tut
 
 		//Delete the instance
 		LLSingletonTest::deleteSingleton();
-		ensure(LLSingletonTest::destroyed());
 		ensure(!LLSingletonTest::instanceExists());
 
 		//Construct it again.
diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp
index e863ddd13ff75939d3cf4aa4988b065ae79983ed..19a20e663ccc12137c0c05c775f5271efd28a217 100755
--- a/indra/llcorehttp/tests/llcorehttp_test.cpp
+++ b/indra/llcorehttp/tests/llcorehttp_test.cpp
@@ -46,6 +46,7 @@
 #include "test_httprequestqueue.hpp"
 
 #include "llproxy.h"
+#include "llcleanup.h"
 
 unsigned long ssl_thread_id_callback(void);
 void ssl_locking_callback(int mode, int type, const char * file, int line);
@@ -101,7 +102,7 @@ void init_curl()
 
 void term_curl()
 {
-	LLProxy::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLProxy);
 	
 	CRYPTO_set_locking_callback(NULL);
 	for (int i(0); i < ssl_mutex_count; ++i)
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index 7a97c16ea7048c6a0b1c86ccc64352795f2b8c7b..0d239c9435a2de969e9ea8dec71f02586e47044c 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -45,6 +45,7 @@
 #include "llhttpclient.h"
 #include "llsdserialize.h"
 #include "llproxy.h"
+#include "llcleanup.h"
  
 LLPumpIO* gServicePump = NULL;
 BOOL gBreak = false;
@@ -587,5 +588,5 @@ bool LLCrashLogger::init()
 void LLCrashLogger::commonCleanup()
 {
 	LLError::logToFile("");   //close crashreport.log
-	LLProxy::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLProxy);
 }
diff --git a/indra/llinventory/lleconomy.h b/indra/llinventory/lleconomy.h
index 47fcf688a26d66e9b61b70f119288d1ceb5c5303..83836b7ce1d83b95467d58ab859acbec52c7a811 100755
--- a/indra/llinventory/lleconomy.h
+++ b/indra/llinventory/lleconomy.h
@@ -42,19 +42,12 @@ class LLEconomyObserver
 	virtual void onEconomyDataChange() = 0;
 };
 
-class LLGlobalEconomy
+class LLGlobalEconomy: public LLSingleton<LLGlobalEconomy>
 {
 public:
 	LLGlobalEconomy();
 	virtual ~LLGlobalEconomy();
 
-	// This class defines its singleton internally as a typedef instead of inheriting from
-	// LLSingleton like most others because the LLRegionEconomy sub-class might also
-	// become a singleton and this pattern will more easily disambiguate them.
-	typedef LLSingleton<LLGlobalEconomy> Singleton;
-
-	void initSingleton() { }
-
 	virtual void print();
 
 	void	addObserver(LLEconomyObserver* observer);
diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h
index 270282c66fb43ed6ee2a516d7572e744e226e6ed..ab0d2191551aac5bc7bb64cc6d1f227f16a271bd 100755
--- a/indra/llmessage/llhttpclientadapter.h
+++ b/indra/llmessage/llhttpclientadapter.h
@@ -28,9 +28,8 @@
 #define LL_HTTPCLIENTADAPTER_H
 
 #include "llhttpclientinterface.h"
-#include "llsingleton.h"	// LLSingleton<>
 
-class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLHTTPClientAdapter>
+class LLHTTPClientAdapter : public LLHTTPClientInterface
 {
 public:
 	virtual ~LLHTTPClientAdapter();
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index e9ce94ab3b62c1f97a404b7ac4d03cc0488bee39..3c3683f12a6a8691893f34bce8a2f9225206ce24 100755
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -77,6 +77,7 @@
 #include "v3math.h"
 #include "v4math.h"
 #include "lltransfertargetvfile.h"
+#include "llpounceable.h"
 
 // Constants
 //const char* MESSAGE_LOG_FILENAME = "message.log";
@@ -1776,7 +1777,9 @@ std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg)
 	return s;
 }
 
-LLMessageSystem	*gMessageSystem = NULL;
+// LLPounceable supports callWhenReady(), to permit clients to queue up (e.g.)
+// callback registrations for when gMessageSystem is first assigned
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
 
 // update appropriate ping info
 void	process_complete_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/)
@@ -2693,7 +2696,7 @@ void end_messaging_system(bool print_summary)
 			LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL;
 		}
 
-		delete gMessageSystem;
+		delete static_cast<LLMessageSystem*>(gMessageSystem);
 		gMessageSystem = NULL;
 	}
 }
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index 348b09b9923bbde5fe023c4d2df7a478af0969e5..a6fabf2126ecc39a3697bed103c6fe0f73d8dc35 100755
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -60,6 +60,7 @@
 #include "llmessagesenderinterface.h"
 
 #include "llstoredmessage.h"
+#include "llpounceable.h"
 
 const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
 const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
@@ -830,7 +831,7 @@ class LLMessageSystem : public LLMessageSenderInterface
 
 
 // external hook into messaging system
-extern LLMessageSystem	*gMessageSystem;
+extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
 
 // Must specific overall system version, which is used to determine
 // if a patch is available in the message template checksum verification.
diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp
index a32bfa59ce8d046bf443c85d1e49cbd519e3a0d3..9356a14f1f89fd24a5ee6bc0047bf763c4744002 100755
--- a/indra/llmessage/tests/llhttpclient_test.cpp
+++ b/indra/llmessage/tests/llhttpclient_test.cpp
@@ -42,6 +42,7 @@
 
 #include "lliosocket.h"
 #include "stringize.h"
+#include "llcleanup.h"
 
 namespace tut
 {
@@ -66,7 +67,7 @@ namespace tut
 		~HTTPClientTestData()
 		{
 			delete mClientPump;
-			LLProxy::cleanupClass();
+			SUBSYSTEM_CLEANUP(LLProxy);
 			apr_pool_destroy(mPool);
 		}
 
diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp
index 3b04530c1ac9e5bd98e596a4e9360c144a9f6d09..e20f61b73f8fddadfff14eaf397907ec8bc162e0 100755
--- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp
+++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp
@@ -31,11 +31,12 @@
 #include "llhost.h"
 #include "message.h"
 #include "llsd.h"
+#include "llpounceable.h"
 
 #include "llhost.cpp" // Needed for copy operator
 #include "net.cpp" // Needed by LLHost.
 
-LLMessageSystem * gMessageSystem = NULL;
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
 
 // sensor test doubles
 bool gClearRecvWasCalled = false;
diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp
index 55748ad27e36d2c4fc0c34fea63bea8bd6995f09..41f982a7e22668c70f5312e74967e64dddd1d210 100755
--- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp
+++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp
@@ -33,8 +33,9 @@
 #include "message.h"
 #include "llmessageconfig.h"
 #include "llhttpnode_stub.cpp"
+#include "llpounceable.h"
 
-LLMessageSystem* gMessageSystem = NULL;
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
 
 LLMessageConfig::SenderTrust
 LLMessageConfig::getSenderTrustedness(const std::string& msg_name)
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index f60129e601ce6c6606d7110504c6ea42063ad15b..4c05d001a07c681de4f7c8ef8a0810718ca4098a 100755
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -170,7 +170,8 @@ LLFolderView::LLFolderView(const Params& p)
 	mDraggingOverItem(NULL),
 	mStatusTextBox(NULL),
 	mShowItemLinkOverlays(p.show_item_link_overlays),
-	mViewModel(p.view_model)
+	mViewModel(p.view_model),
+    mGroupedItemModel(p.grouped_item_model)
 {
 	claimMem(mViewModel);
     LLPanel* panel = p.parent_panel;
@@ -1810,7 +1811,6 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu)
 	}
 
 	// Successively filter out invalid options
-
 	U32 multi_select_flag = (mSelectedItems.size() > 1 ? ITEM_IN_MULTI_SELECTION : 0x0);
 	U32 flags = multi_select_flag | FIRST_SELECTED_ITEM;
 	for (selected_items_t::iterator item_itor = mSelectedItems.begin();
@@ -1822,6 +1822,14 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu)
 		flags = multi_select_flag;
 	}
 
+	// This adds a check for restrictions based on the entire
+	// selection set - for example, any one wearable may not push you
+	// over the limit, but all wearables together still might.
+    if (getFolderViewGroupedItemModel())
+    {
+        getFolderViewGroupedItemModel()->groupFilterContextMenu(mSelectedItems,*menu);
+    }
+
 	addNoOptions(menu);
 }
 
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 08e0a6220a7fcf30f84fccd32c61bfb958e46737..114dd7bd2fd682298864571c305c395a5acd0ef8 100755
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -45,6 +45,7 @@
 #include "llscrollcontainer.h"
 
 class LLFolderViewModelInterface;
+class LLFolderViewGroupedItemModel;
 class LLFolderViewFolder;
 class LLFolderViewItem;
 class LLFolderViewFilter;
@@ -93,6 +94,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 								use_ellipses,
 								show_item_link_overlays;
 		Mandatory<LLFolderViewModelInterface*>	view_model;
+		Optional<LLFolderViewGroupedItemModel*> grouped_item_model;
         Mandatory<std::string>   options_menu;
 
 
@@ -100,7 +102,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	};
 
 	friend class LLFolderViewScrollContainer;
-    typedef std::deque<LLFolderViewItem*> selected_items_t;
+    typedef folder_view_item_deque selected_items_t;
 
 	LLFolderView(const Params&);
 	virtual ~LLFolderView( void );
@@ -113,6 +115,9 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	LLFolderViewModelInterface* getFolderViewModel() { return mViewModel; }
 	const LLFolderViewModelInterface* getFolderViewModel() const { return mViewModel; }
 
+    LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() { return mGroupedItemModel; }
+    const LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() const { return mGroupedItemModel; }
+    
 	typedef boost::signals2::signal<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)> signal_t;
 	void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); }
 	void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); }
@@ -300,6 +305,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	LLHandle<LLPanel>               mParentPanel;
 	
 	LLFolderViewModelInterface*		mViewModel;
+    LLFolderViewGroupedItemModel*   mGroupedItemModel;
 
 	/**
 	 * Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll.
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
old mode 100644
new mode 100755
index 0cd20a0f2d9a7047d39f23c641452cfe9bab4a7c..5ad5731cadf8b289e563597b53b98f18f6ddebaf
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -454,5 +454,12 @@ class LLFolderViewFolder : public LLFolderViewItem
 	template<typename SORT_FUNC> void sortItems(const SORT_FUNC& func) { mItems.sort(func); }
 };
 
+typedef std::deque<LLFolderViewItem*> folder_view_item_deque;
+
+class LLFolderViewGroupedItemModel: public LLRefCount
+{
+public:
+    virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu) = 0;
+};
 
 #endif  // LLFOLDERVIEWITEM_H
diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h
index 4ab80195ead318f7f586563474d0f9fb5706d10d..5ecc9aa110648529ae0fb60752f79582c3ceb867 100755
--- a/indra/llui/llspellcheck.h
+++ b/indra/llui/llspellcheck.h
@@ -29,6 +29,7 @@
 
 #include "llsingleton.h"
 #include "llui.h"
+#include "llinitdestroyclass.h"
 #include <boost/signals2.hpp>
 
 class Hunspell;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index aabc7ed2e423b61fc6cbff0a63b7f5cfeb4fd121..cc186f4997393e41e9fd9c086c6754fd223f3137 100755
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -60,6 +60,7 @@
 #include "llflyoutbutton.h"
 #include "llsearcheditor.h"
 #include "lltoolbar.h"
+#include "llcleanup.h"
 
 // for XUIParse
 #include "llquaternion.h"
@@ -208,7 +209,7 @@ void LLUI::initClass(const settings_map_t& settings,
 
 void LLUI::cleanupClass()
 {
-	LLRender2D::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLRender2D);
 }
 
 void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup,  const clear_popups_t& clear_popups)
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index c727f75c4fa6a953f8abdc244ef05225f4c764e7..d7151dbee9939fd0ecf9af5d65e5646394e00833 100755
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -344,95 +344,6 @@ class LLUI
 
 // Moved LLLocalClipRect to lllocalcliprect.h
 
-class LLCallbackRegistry
-{
-public:
-	typedef boost::signals2::signal<void()> callback_signal_t;
-	
-	void registerCallback(const callback_signal_t::slot_type& slot)
-	{
-		mCallbacks.connect(slot);
-	}
-
-	void fireCallbacks()
-	{
-		mCallbacks();
-	}
-
-private:
-	callback_signal_t mCallbacks;
-};
-
-class LLInitClassList : 
-	public LLCallbackRegistry, 
-	public LLSingleton<LLInitClassList>
-{
-	friend class LLSingleton<LLInitClassList>;
-private:
-	LLInitClassList() {}
-};
-
-class LLDestroyClassList : 
-	public LLCallbackRegistry, 
-	public LLSingleton<LLDestroyClassList>
-{
-	friend class LLSingleton<LLDestroyClassList>;
-private:
-	LLDestroyClassList() {}
-};
-
-template<typename T>
-class LLRegisterWith
-{
-public:
-	LLRegisterWith(boost::function<void ()> func)
-	{
-		T::instance().registerCallback(func);
-	}
-
-	// this avoids a MSVC bug where non-referenced static members are "optimized" away
-	// even if their constructors have side effects
-	S32 reference()
-	{
-		S32 dummy;
-		dummy = 0;
-		return dummy;
-	}
-};
-
-template<typename T>
-class LLInitClass
-{
-public:
-	LLInitClass() { sRegister.reference(); }
-
-	static LLRegisterWith<LLInitClassList> sRegister;
-private:
-
-	static void initClass()
-	{
-		LL_ERRS() << "No static initClass() method defined for " << typeid(T).name() << LL_ENDL;
-	}
-};
-
-template<typename T>
-class LLDestroyClass
-{
-public:
-	LLDestroyClass() { sRegister.reference(); }
-
-	static LLRegisterWith<LLDestroyClassList> sRegister;
-private:
-
-	static void destroyClass()
-	{
-		LL_ERRS() << "No static destroyClass() method defined for " << typeid(T).name() << LL_ENDL;
-	}
-};
-
-template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister(&T::initClass);
-template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(&T::destroyClass);
-
 // useful parameter blocks
 struct TimeIntervalParam : public LLInitParam::ChoiceBlock<TimeIntervalParam>
 {
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index 5d3f9ac327be6352eeb877da19519ddc0dac443c..d28f601009a8d2b75dee847b89093e0014f52ff2 100755
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -31,6 +31,7 @@
 #include "llcachename.h"
 #include "lluuid.h"
 #include "message.h"
+#include "llpounceable.h"
 
 #include <string>
 
@@ -167,7 +168,7 @@ char const* const _PREHASH_AgentID = (char *)"AgentID";
 
 LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS);
 
-LLMessageSystem* gMessageSystem = NULL;
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
 
 //
 // Stub implementation for LLMessageSystem
diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l
index 7772c95609269cc3a19c64749ef630a776fc15d2..d5c71d9987d5ebffcd4bb6e90c4002d1789e59ff 100755
--- a/indra/lscript/lscript_compile/indra.l
+++ b/indra/lscript/lscript_compile/indra.l
@@ -102,7 +102,7 @@ int yyerror(const char *fmt, ...);
 "event"				{ count(); return(EVENT); }
 "jump"				{ count(); return(JUMP); }
 "return"			{ count(); return(RETURN); }
-"if"				{ count(); return(IF); }
+"if"				{ count(); return(IFF); }
 "else"				{ count(); return(ELSE); }
 "for"				{ count(); return(FOR); }
 "do"				{ count(); return(DO); }
diff --git a/indra/lscript/lscript_compile/indra.y b/indra/lscript/lscript_compile/indra.y
index a0a034d21c2251a9035825f72e2781c80ced719c..604b5b6b9208ca35736043ac5f53db548bf23b84 100755
--- a/indra/lscript/lscript_compile/indra.y
+++ b/indra/lscript/lscript_compile/indra.y
@@ -117,7 +117,7 @@
 %token					SHIFT_LEFT
 %token					SHIFT_RIGHT
 
-%token					IF
+%token					IFF         /* IF used by a helper library */
 %token					ELSE
 %token					FOR
 %token					DO
@@ -1312,13 +1312,13 @@ statement
 	{ 
 		$$ = $1;
 	}
-	| IF '(' expression ')' statement	%prec LOWER_THAN_ELSE			
+	| IFF '(' expression ')' statement	%prec LOWER_THAN_ELSE			
 	{  
 		$$ = new LLScriptIf(gLine, gColumn, $3, $5);
 		$5->mAllowDeclarations = FALSE;
 		gAllocationManager->addAllocation($$);
 	}
-	| IF '(' expression ')' statement ELSE statement					
+	| IFF '(' expression ')' statement ELSE statement					
 	{  
 		$$ = new LLScriptIfElse(gLine, gColumn, $3, $5, $7);
 		$5->mAllowDeclarations = FALSE;
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 1523336b0db452afe6d11a9e14ff3cb5dd516f71..ef239df8cdca0dc0685a38d9c90ad9caa62fb6fb 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.7.29
+3.7.30
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index f06ffb4fb39e6c334f18603a1d6e58ae613caaa7..5589ab4aa7075d9a76c1fafe87140c4d463228db 100755
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -633,10 +633,13 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
 		// the versions themselves are compatible. This code can be removed before release.
 		if( wearable->getDefinitionVersion() == 24 )
 		{
-			wearable->setDefinitionVersion(22);
-			U32 index = getWearableIndex(wearable);
-			LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL;
-			saveWearable(wearable->getType(),index);
+			U32 index;
+			if (getWearableIndex(wearable,index))
+			{
+				LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL;
+				wearable->setDefinitionVersion(22);
+				saveWearable(wearable->getType(),index);
+			}
 		}
 
 		checkWearableAgainstInventory(viewer_wearable);
@@ -949,7 +952,7 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
 			LLViewerWearable* old_wearable = getViewerWearable(type,i);
 			if (old_wearable)
 			{
-				popWearable(old_wearable);
+				eraseWearable(old_wearable);
 				old_wearable->removeFromAvatar();
 			}
 		}
@@ -961,7 +964,7 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
 
 		if (old_wearable)
 		{
-			popWearable(old_wearable);
+			eraseWearable(old_wearable);
 			old_wearable->removeFromAvatar();
 		}
 	}
@@ -1163,7 +1166,13 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&
 {
 	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 	LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
-	U32 index = gAgentWearables.getWearableIndex(wearable);
+	U32 index;
+	if (!gAgentWearables.getWearableIndex(wearable,index))
+	{
+		LL_WARNS() << "Wearable not found" << LL_ENDL;
+		delete wearable;
+		return false;
+	}
 	if (!new_item)
 	{
 		delete wearable;
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 100448202080c8a2f6ecdfae5dd086e01dc4a5b5..7dc23c6402bb728e1207b46487218d222dcb7757 100755
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -38,6 +38,7 @@
 #include "llviewerinventory.h"
 #include "llavatarappearancedefines.h"
 #include "llwearabledata.h"
+#include "llinitdestroyclass.h"
 
 class LLInventoryItem;
 class LLVOAvatarSelf;
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index a64d5b50b36fafdf5c64be18533bf7141a29f252..b3317e937ec7905a7139c71ff83ad73328b1e3b4 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1338,90 +1338,113 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false)
 	}
 }
 
-bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear,
+void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
+                                        bool do_update,
+                                        bool replace,
+                                        LLPointer<LLInventoryCallback> cb)
+{
+    bool first = true;
+
+    LLInventoryObject::const_object_list_t items_to_link;
+
+    for (uuid_vec_t::const_iterator it = item_ids_to_wear.begin();
+         it != item_ids_to_wear.end();
+         ++it)
+    {
+        replace = first && replace;
+        first = false;
+
+        const LLUUID& item_id_to_wear = *it;
+
+        if (item_id_to_wear.isNull()) continue;
+
+        LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
+        if (!item_to_wear) continue;
+
+        if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
+        {
+            LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
+            copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
+            continue;
+        } 
+        else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
+        {
+            continue; // not in library and not in agent's inventory
+        }
+        else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
+        {
+            LLNotificationsUtil::add("CannotWearTrash");
+            continue;
+        }
+        else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911
+        {
+            continue;
+        }
+
+        switch (item_to_wear->getType())
+        {
+            case LLAssetType::AT_CLOTHING:
+            {
+                if (gAgentWearables.areWearablesLoaded())
+                {
+                    if (!cb && do_update)
+                    {
+                        cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
+                    }
+                    LLWearableType::EType type = item_to_wear->getWearableType();
+                    S32 wearable_count = gAgentWearables.getWearableCount(type);
+                    if ((replace && wearable_count != 0) || !gAgentWearables.canAddWearable(type))
+                    {
+                        LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
+                                                                           wearable_count-1);
+                        removeCOFItemLinks(item_id, cb);
+                    }
+                    
+                    items_to_link.push_back(item_to_wear);
+                } 
+            }
+            break;
+
+            case LLAssetType::AT_BODYPART:
+            {
+                // TODO: investigate wearables may not be loaded at this point EXT-8231
+                
+                // Remove the existing wearables of the same type.
+                // Remove existing body parts anyway because we must not be able to wear e.g. two skins.
+                removeCOFLinksOfType(item_to_wear->getWearableType());
+                if (!cb && do_update)
+                {
+                    cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
+                }
+                items_to_link.push_back(item_to_wear);
+            }
+            break;
+                
+            case LLAssetType::AT_OBJECT:
+            {
+                rez_attachment(item_to_wear, NULL, replace);
+            }
+            break;
+
+            default: continue;
+        }
+    }
+
+    // Batch up COF link creation - more efficient if using AIS.
+    if (items_to_link.size())
+    {
+        link_inventory_array(getCOF(), items_to_link, cb); 
+    }
+}
+
+void LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear,
 									   bool do_update,
 									   bool replace,
 									   LLPointer<LLInventoryCallback> cb)
 {
-
-	if (item_id_to_wear.isNull()) return false;
-
-	// *TODO: issue with multi-wearable should be fixed:
-	// in this case this method will be called N times - loading started for each item
-	// and than N times will be called - loading completed for each item.
-	// That means subscribers will be notified that loading is done after first item in a batch is worn.
-	// (loading indicator disappears for example before all selected items are worn)
-	// Have not fix this issue for 2.1 because of stability reason. EXT-7777.
-
-	// Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times
-//	gAgentWearables.notifyLoadingStarted();
-
-	LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
-	if (!item_to_wear) return false;
-
-	if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
-	{
-		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
-		copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
-		return false;
-	} 
-	else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
-	{
-		return false; // not in library and not in agent's inventory
-	}
-	else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
-	{
-		LLNotificationsUtil::add("CannotWearTrash");
-		return false;
-	}
-	else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911
-	{
-		return false;
-	}
-
-	switch (item_to_wear->getType())
-	{
-		case LLAssetType::AT_CLOTHING:
-		if (gAgentWearables.areWearablesLoaded())
-		{
-			if (!cb && do_update)
-			{
-				cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
-			}
-			S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType());
-			if ((replace && wearable_count != 0) ||
-				(wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) )
-			{
-				LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
-																   wearable_count-1);
-				removeCOFItemLinks(item_id, cb);
-			}
-
-			addCOFItemLink(item_to_wear, cb);
-		} 
-		break;
-
-		case LLAssetType::AT_BODYPART:
-		// TODO: investigate wearables may not be loaded at this point EXT-8231
-		
-		// Remove the existing wearables of the same type.
-		// Remove existing body parts anyway because we must not be able to wear e.g. two skins.
-		removeCOFLinksOfType(item_to_wear->getWearableType());
-		if (!cb && do_update)
-		{
-			cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
-		}
-		addCOFItemLink(item_to_wear, cb);
-		break;
-
-		case LLAssetType::AT_OBJECT:
-		rez_attachment(item_to_wear, NULL, replace);
-		break;
-
-		default: return false;;
-	}
-
-	return true;
+    uuid_vec_t ids;
+    ids.push_back(item_id_to_wear);
+    wearItemsOnAvatar(ids, do_update, replace, cb);
 }
 
 // Update appearance from outfit folder.
@@ -1782,6 +1805,49 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
 	return items.size() > 0;
 }
 
+// Moved from LLWearableList::ContextMenu for wider utility.
+bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids)
+{
+	// TODO: investigate wearables may not be loaded at this point EXT-8231
+
+	U32 n_objects = 0;
+	U32 n_clothes = 0;
+
+	// Count given clothes (by wearable type) and objects.
+	for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it)
+	{
+		LLViewerInventoryItem* item = gInventory.getItem(*it);
+		if (!item)
+		{
+			return false;
+		}
+
+		if (item->getType() == LLAssetType::AT_OBJECT)
+		{
+			++n_objects;
+		}
+		else if (item->getType() == LLAssetType::AT_CLOTHING)
+		{
+			++n_clothes;
+		}
+		else
+		{
+			LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
+			return false;
+		}
+	}
+
+	// Check whether we can add all the objects.
+	if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects))
+	{
+		return false;
+	}
+
+	// Check whether we can add all the clothes.
+    U32 sum_clothes = n_clothes + gAgentWearables.getClothingLayerCount();
+    return sum_clothes <= LLAgentWearables::MAX_CLOTHING_LAYERS;
+}
+
 void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb)
 {
 	LLInventoryModel::cat_array_t cats;
@@ -1804,25 +1870,39 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLIn
 // Keep the last N wearables of each type.  For viewer 2.0, N is 1 for
 // both body parts and clothing items.
 void LLAppearanceMgr::filterWearableItems(
-	LLInventoryModel::item_array_t& items, S32 max_per_type)
-{
-	// Divvy items into arrays by wearable type.
-	std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT);
-	divvyWearablesByType(items, items_by_type);
-
-	// rebuild items list, retaining the last max_per_type of each array
-	items.clear();
-	for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
-	{
-		S32 size = items_by_type[i].size();
-		if (size <= 0)
-			continue;
-		S32 start_index = llmax(0,size-max_per_type);
-		for (S32 j = start_index; j<size; j++)
-		{
-			items.push_back(items_by_type[i][j]);
-		}
-	}
+	LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total)
+{
+    // Restrict by max total items first.
+    if ((max_total > 0) && (items.size() > max_total))
+    {
+        LLInventoryModel::item_array_t items_to_keep;
+        for (S32 i=0; i<max_total; i++)
+        {
+            items_to_keep.push_back(items[i]);
+        }
+        items = items_to_keep;
+    }
+
+    if (max_per_type > 0)
+    {
+        // Divvy items into arrays by wearable type.
+        std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT);
+        divvyWearablesByType(items, items_by_type);
+
+        // rebuild items list, retaining the last max_per_type of each array
+        items.clear();
+        for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
+        {
+            S32 size = items_by_type[i].size();
+            if (size <= 0)
+                continue;
+            S32 start_index = llmax(0,size-max_per_type);
+            for (S32 j = start_index; j<size; j++)
+            {
+                items.push_back(items_by_type[i][j]);
+            }
+        }
+    }
 }
 
 void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
@@ -1864,7 +1944,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 		reverse(body_items.begin(), body_items.end());
 	// Reduce body items to max of one per type.
 	removeDuplicateItems(body_items);
-	filterWearableItems(body_items, 1);
+	filterWearableItems(body_items, 1, 0);
 
 	// - Wearables: include COF contents only if appending.
 	LLInventoryModel::item_array_t wear_items;
@@ -1873,7 +1953,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING);
 	// Reduce wearables to max of one per type.
 	removeDuplicateItems(wear_items);
-	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
+	filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS);
 
 	// - Attachments: include COF contents only if appending.
 	LLInventoryModel::item_array_t obj_items;
@@ -2062,7 +2142,8 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list,
 
 S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
 												 LLAssetType::EType type,
-												 S32 max_items,
+												 S32 max_items_per_type,
+												 S32 max_items_total,
 												 LLInventoryObject::object_list_t& items_to_kill)
 {
 	S32 to_kill_count = 0;
@@ -2071,9 +2152,9 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
 	getDescendentsOfAssetType(cat_id, items, type);
 	LLInventoryModel::item_array_t curr_items = items;
 	removeDuplicateItems(items);
-	if (max_items > 0)
+	if (max_items_per_type > 0 || max_items_total > 0)
 	{
-		filterWearableItems(items, max_items);
+		filterWearableItems(items, max_items_per_type, max_items_total);
 	}
 	LLInventoryModel::item_array_t kill_items;
 	item_array_diff(curr_items,items,kill_items);
@@ -2092,11 +2173,11 @@ void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id,
 													LLInventoryObject::object_list_t& items_to_kill)
 {
 	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART,
-							   1, items_to_kill);
+							   1, 0, items_to_kill);
 	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING,
-							   LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
+							   0, LLAgentWearables::MAX_CLOTHING_LAYERS, items_to_kill);
 	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT,
-							   -1, items_to_kill);
+							   0, 0, items_to_kill);
 }
 
 void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb)
@@ -2588,7 +2669,6 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
 								  item_array,
 								  LLInventoryModel::EXCLUDE_TRASH);
 	bool linked_already = false;
-	U32 count = 0;
 	for (S32 i=0; i<item_array.size(); i++)
 	{
 		// Are these links to the same object?
@@ -2608,14 +2688,13 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
 		// type? If so, new item will replace old.
 		else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type))
 		{
-			++count;
-			if (is_body_part && inv_item->getIsLinkType()  && (vitem->getWearableType() == wearable_type))
+			if (is_body_part && inv_item->getIsLinkType())
 			{
 				remove_inventory_item(inv_item->getUUID(), cb);
 			}
-			else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
+			else if (!gAgentWearables.canAddWearable(wearable_type))
 			{
-				// MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE
+				// MULTI-WEARABLES: make sure we don't go over clothing limits
 				remove_inventory_item(inv_item->getUUID(), cb);
 			}
 		}
@@ -4071,16 +4150,7 @@ void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
 void wear_multiple(const uuid_vec_t& ids, bool replace)
 {
 	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
-	
-	bool first = true;
-	uuid_vec_t::const_iterator it;
-	for (it = ids.begin(); it != ids.end(); ++it)
-	{
-		// if replace is requested, the first item worn will replace the current top
-		// item, and others will be added.
-		LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb);
-		first = false;
-	}
+    LLAppearanceMgr::instance().wearItemsOnAvatar(ids, false, replace, cb);
 }
 
 // SLapp for easy-wearing of a stock (library) avatar
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 7742a19c07f2bc0636405f8bb5b022d3c1b1d02b..ee9d3b7209b85ec3c884581b2649067267063f90 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -67,7 +67,8 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 	void addCategoryToCurrentOutfit(const LLUUID& cat_id);
 	S32 findExcessOrDuplicateItems(const LLUUID& cat_id,
 								   LLAssetType::EType type,
-								   S32 max_items,
+								   S32 max_items_per_type,
+								   S32 max_items_total,
 								   LLInventoryObject::object_list_t& items_to_kill);
 	void findAllExcessOrDuplicateItems(const LLUUID& cat_id,
 									  LLInventoryObject::object_list_t& items_to_kill);
@@ -99,6 +100,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 	// Determine whether we can replace current outfit with the given one.
 	bool getCanReplaceCOF(const LLUUID& outfit_cat_id);
 
+    // Can we add all referenced items to the avatar?
+    bool canAddWearables(const uuid_vec_t& item_ids);
+    
 	// Copy all items in a category.
 	void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
 									 LLPointer<LLInventoryCallback> cb);
@@ -117,8 +121,13 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 	// find the UUID of the currently worn outfit (Base Outfit)
 	const LLUUID getBaseOutfitUUID();
 
+    void wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
+                           bool do_update,
+                           bool replace,
+                           LLPointer<LLInventoryCallback> cb = NULL);
+
 	// Wear/attach an item (from a user's inventory) on the agent
-	bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false,
+	void wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false,
 						  LLPointer<LLInventoryCallback> cb = NULL);
 
 	// Update the displayed outfit name in UI.
@@ -235,7 +244,7 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 
 private:
 
-	void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type);
+	void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total);
 	
 	void getDescendentsOfAssetType(const LLUUID& category, 
 										  LLInventoryModel::item_array_t& items,
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 6dc71bc94e3bf00c4f8a174ab2d506e260658ea5..6a64f67f9c1a944a7a4af8c68ea8c0af3173be45 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -226,6 +226,7 @@
 #include "llsecapi.h"
 #include "llmachineid.h"
 #include "llmainlooprepeater.h"
+#include "llcleanup.h"
 
 
 #include "llviewereventrecorder.h"
@@ -1764,7 +1765,7 @@ bool LLAppViewer::cleanup()
 	gTransferManager.cleanup();
 #endif
 
-	LLLocalBitmapMgr::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLLocalBitmapMgr);
 
 	// Note: this is where gWorldMap used to be deleted.
 
@@ -1872,11 +1873,11 @@ bool LLAppViewer::cleanup()
 	
 	LLViewerObject::cleanupVOClasses();
 
-	LLAvatarAppearance::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLAvatarAppearance);
 	
-	LLAvatarAppearance::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLAvatarAppearance);
 	
-	LLPostProcess::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLPostProcess);
 
 	LLTracker::cleanupInstance();
 	
@@ -1902,12 +1903,12 @@ bool LLAppViewer::cleanup()
 
  	//end_messaging_system();
 
-	LLFollowCamMgr::cleanupClass();
-	//LLVolumeMgr::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLFollowCamMgr);
+	//SUBSYSTEM_CLEANUP(LLVolumeMgr);
 	LLPrimitive::cleanupVolumeManager();
-	LLWorldMapView::cleanupClass();
-	LLFolderViewItem::cleanupClass();
-	LLUI::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLWorldMapView);
+	SUBSYSTEM_CLEANUP(LLFolderViewItem);
+	SUBSYSTEM_CLEANUP(LLUI);
 	
 	//
 	// Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles).
@@ -1916,7 +1917,7 @@ bool LLAppViewer::cleanup()
 
 	//
 	LL_INFOS() << "Cleaning up VFS" << LL_ENDL;
-	LLVFile::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLVFile);
 
 	LL_INFOS() << "Saving Data" << LL_ENDL;
 	
@@ -2020,7 +2021,7 @@ bool LLAppViewer::cleanup()
 
 	// *NOTE:Mani - The following call is not thread safe. 
 	LL_CHECK_MEMORY
-	LLCurl::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLCurl);
 	LL_CHECK_MEMORY
 
 	// Non-LLCurl libcurl library
@@ -2029,9 +2030,9 @@ bool LLAppViewer::cleanup()
 	// NOTE The following call is not thread safe. 
 	ll_cleanup_ares();
 
-	LLFilePickerThread::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLFilePickerThread);
 
-	//MUST happen AFTER LLCurl::cleanupClass
+	//MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl)
 	delete sTextureCache;
     sTextureCache = NULL;
 	delete sTextureFetch;
@@ -2060,17 +2061,17 @@ bool LLAppViewer::cleanup()
 	LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL;
 
 	//Note:
-	//LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown()
+	//SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown()
 	//because some new image might be generated during cleaning up media. --bao
-	LLViewerMedia::cleanupClass();
-	LLViewerParcelMedia::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLViewerMedia);
+	SUBSYSTEM_CLEANUP(LLViewerParcelMedia);
 	gTextureList.shutdown(); // shutdown again in case a callback added something
 	LLUIImageList::getInstance()->cleanUp();
 	
 	// This should eventually be done in LLAppViewer
-	LLImage::cleanupClass();
-	LLVFSThread::cleanupClass();
-	LLLFSThread::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLImage);
+	SUBSYSTEM_CLEANUP(LLVFSThread);
+	SUBSYSTEM_CLEANUP(LLLFSThread);
 
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 	LL_INFOS() << "Auditing VFS" << LL_ENDL;
@@ -2113,9 +2114,9 @@ bool LLAppViewer::cleanup()
 		LL_INFOS() << "File launched." << LL_ENDL;
 	}
 	LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL;
-	LLProxy::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLProxy);
 
-	LLWearableType::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLWearableType);
 
 	LLMainLoopRepeater::instance().stop();
 
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index d2b1dcbf359d3365263d8720934067be261d95c4..620274c1a5c051ec92a6ddea2ebafe9262c0de1e 100755
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -334,7 +334,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content)
 	// deal with L$ errors
 	if (reason == "insufficient funds")
 	{
-		S32 price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+		S32 price = LLGlobalEconomy::getInstance()->getPriceUpload();
 		LLStringUtil::format_map_t args;
 		args["AMOUNT"] = llformat("%d", price);
 		LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("uploading_costs", args), price );
@@ -405,7 +405,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 		asset_type == LLAssetType::AT_MESH)
 	{
 		expected_upload_cost = 
-			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+			LLGlobalEconomy::getInstance()->getPriceUpload();
 	}
 
 	on_new_single_inventory_upload_complete(
@@ -467,7 +467,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 			everyone_perms,
 			display_name,
 			callback,
-			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(),
+			LLGlobalEconomy::getInstance()->getPriceUpload(),
 			userdata);
 	}
 
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index a370724947d6823c3f58d5b66f4904b0e6350d01..574617fa6315f56e6eafe77f45beb3eac05c5fcc 100755
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -34,6 +34,7 @@
 #include "llinventoryobserver.h"
 #include "llinventorymodel.h"
 #include "llviewerinventory.h"
+#include "llinitdestroyclass.h"
 
 class LLMenuItemCallGL;
 class LLToggleableMenu;
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index 669ffa7c599814253c6324b38128463aa9a5b55f..75cbc6561a0d0501f26971178633ba501c6ab69c 100755
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -993,7 +993,7 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata)
 				std::string name = floaterp->getChild<LLUICtrl>("name_form")->getValue().asString();
 				std::string desc = floaterp->getChild<LLUICtrl>("description_form")->getValue().asString();
 				LLAssetStorage::LLStoreAssetCallback callback = NULL;
-				S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+				S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload();
 				void *userdata = NULL;
 				upload_new_resource(floaterp->mTransactionID, // tid
 						    LLAssetType::AT_ANIMATION,
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index ab57e8c170a8b4e43ddd26fb75803ce5e69d2e53..cacd66aee9cdbb9346c9fbf29fe9487e7e17255b 100755
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -101,7 +101,7 @@ LLFloaterIMContainer::~LLFloaterIMContainer()
 	gSavedPerAccountSettings.setBOOL("ConversationsMessagePaneCollapsed", mMessagesPane->isCollapsed());
 	gSavedPerAccountSettings.setBOOL("ConversationsParticipantListCollapsed", !isParticipantListExpanded());
 
-	if (!LLSingleton<LLIMMgr>::destroyed())
+	if (LLIMMgr::instanceExists())
 	{
 		LLIMMgr::getInstance()->removeSessionObserver(this);
 	}
diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp
index 0cca715fe25d94ebd2673c37f010d838ffb80df5..a889ca2545fa2f29e2f442808d4c333994f4ba8e 100755
--- a/indra/newview/llfloaternamedesc.cpp
+++ b/indra/newview/llfloaternamedesc.cpp
@@ -121,7 +121,7 @@ BOOL LLFloaterNameDesc::postBuild()
 	// Cancel button
 	getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnCancel, this));
 
-	getChild<LLUICtrl>("ok_btn")->setLabelArg("[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() ));
+	getChild<LLUICtrl>("ok_btn")->setLabelArg("[AMOUNT]", llformat("%d", LLGlobalEconomy::getInstance()->getPriceUpload() ));
 	
 	setDefaultBtn("ok_btn");
 	
@@ -160,7 +160,7 @@ void LLFloaterNameDesc::onBtnOK( )
 	getChildView("ok_btn")->setEnabled(FALSE); // don't allow inadvertent extra uploads
 	
 	LLAssetStorage::LLStoreAssetCallback callback = NULL;
-	S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass).
+	S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass).
 	void *nruserdata = NULL;
 	std::string display_name = LLStringUtil::null;
 
diff --git a/indra/newview/llhints.h b/indra/newview/llhints.h
index ebffe561b9513d1d8fbe92c3640129d10d74e00b..dd6195a9ce37e782287df50b334dd7e61a5f8be4 100755
--- a/indra/newview/llhints.h
+++ b/indra/newview/llhints.h
@@ -29,6 +29,7 @@
 
 #include "llpanel.h"
 #include "llnotifications.h"
+#include "llinitdestroyclass.h"
 
 
 class LLHints :  public LLInitClass<LLHints>
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index f92eff48458167219cdbd574f9587edad5d3bf69..79be6fd9d3ae59dad32509c3b5df753be55bd173 100755
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -33,6 +33,7 @@
 
 #include "lllogchat.h"
 #include "llvoicechannel.h"
+#include "llinitdestroyclass.h"
 
 class LLAvatarName;
 class LLFriendObserver;
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 1dc555855509fdef2678e49d6e4e03df41143c84..a047ed6feed027450465f28999fd26a8d0c64ff6 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -74,6 +74,7 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llwearablelist.h"
+#include "llwearableitemslist.h"
 #include "lllandmarkactions.h"
 #include "llpanellandmarks.h"
 
@@ -557,6 +558,46 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
 	return TRUE;
 }
 
+void disable_context_entries_if_present(LLMenuGL& menu,
+                                        const menuentry_vec_t &disabled_entries)
+{
+	const LLView::child_list_t *list = menu.getChildList();
+	for (LLView::child_list_t::const_iterator itor = list->begin(); 
+		 itor != list->end(); 
+		 ++itor)
+	{
+		LLView *menu_item = (*itor);
+		std::string name = menu_item->getName();
+
+		// descend into split menus:
+		LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item);
+		if ((name == "More") && branchp)
+		{
+			disable_context_entries_if_present(*branchp->getBranch(), disabled_entries);
+		}
+
+		bool found = false;
+		menuentry_vec_t::const_iterator itor2;
+		for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2)
+		{
+			if (*itor2 == name)
+			{
+				found = true;
+				break;
+			}
+		}
+
+        if (found)
+        {
+			menu_item->setVisible(TRUE);
+			// A bit of a hack so we can remember that some UI element explicitly set this to be visible
+			// so that some other UI element from multi-select doesn't later set this invisible.
+			menu_item->pushVisible(TRUE);
+
+			menu_item->setEnabled(FALSE);
+        }
+    }
+}
 void hide_context_entries(LLMenuGL& menu, 
 						  const menuentry_vec_t &entries_to_show,
 						  const menuentry_vec_t &disabled_entries)
@@ -765,6 +806,31 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 	hide_context_entries(menu, items, disabled_items);
 }
 
+bool get_selection_item_uuids(LLFolderView::selected_items_t& selected_items, uuid_vec_t& ids)
+{
+	uuid_vec_t results;
+    S32 non_item = 0;
+	for(LLFolderView::selected_items_t::iterator it = selected_items.begin(); it != selected_items.end(); ++it)
+	{
+		LLItemBridge *view_model = dynamic_cast<LLItemBridge *>((*it)->getViewModelItem());
+
+		if(view_model && view_model->getUUID().notNull())
+		{
+			results.push_back(view_model->getUUID());
+		}
+        else
+        {
+            non_item++;
+        }
+	}
+	if (non_item == 0)
+	{
+		ids = results;
+		return true;
+	}
+	return false;
+}
+
 void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items,
 											   menuentry_vec_t &disabled_items)
 {
@@ -1120,7 +1186,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
 			{
 				LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
 			}
-			new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags);
+			new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, LLWearableType::inventoryFlagsToWearableType(flags));
 			break;
 		case LLAssetType::AT_CATEGORY:
 			if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
@@ -3585,7 +3651,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 	if(!model) return;
 
 	buildContextMenuOptions(flags, items, disabled_items);
-        hide_context_entries(menu, items, disabled_items);
+    hide_context_entries(menu, items, disabled_items);
 
 	// Reposition the menu, in case we're adding items to an existing menu.
 	menu.needsArrange();
@@ -5770,7 +5836,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 					if (LLWearableType::getAllowMultiwear(mWearableType))
 					{
 						items.push_back(std::string("Wearable Add"));
-						if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
+						if (!gAgentWearables.canAddWearable(mWearableType))
 						{
 							disabled_items.push_back(std::string("Wearable Add"));
 						}
@@ -6439,4 +6505,22 @@ LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge(
 	return new_listener;
 }
 
+LLFolderViewGroupedItemBridge::LLFolderViewGroupedItemBridge()
+{
+}
+
+void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu)
+{
+    uuid_vec_t ids;
+	menuentry_vec_t disabled_items;
+    if (get_selection_item_uuids(selected_items, ids))
+    {
+        if (!LLAppearanceMgr::instance().canAddWearables(ids))
+        {
+			disabled_items.push_back(std::string("Wearable Add"));
+        }
+    }
+	disable_context_entries_if_present(menu, disabled_items);
+}
+
 // EOF
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index f8ef15991d9f9ef5cb74bb8507d2c39f855c902e..300cef7deb21c00afc556ea0f3c045c5719a9144 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -37,6 +37,7 @@
 #include "llviewerwearable.h"
 #include "lltooldraganddrop.h"
 #include "lllandmarklist.h"
+#include "llfolderviewitem.h"
 
 class LLInventoryFilter;
 class LLInventoryPanel;
@@ -689,4 +690,11 @@ void hide_context_entries(LLMenuGL& menu,
 						  const menuentry_vec_t &entries_to_show, 
 						  const menuentry_vec_t &disabled_entries);
 
+class LLFolderViewGroupedItemBridge: public LLFolderViewGroupedItemModel
+{
+public:
+    LLFolderViewGroupedItemBridge();
+    virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu);
+};
+
 #endif // LL_LLINVENTORYBRIDGE_H
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 1abc09bf3b7fc49b7e6b496671048a13ac083034..2546db546bd43eba12e4583f3eb5a9c2ec897b56 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -45,6 +45,7 @@
 // newview includes
 #include "llappearancemgr.h"
 #include "llappviewer.h"
+#include "llavataractions.h"
 #include "llclipboard.h"
 #include "lldonotdisturbnotificationstorage.h"
 #include "llfloaterinventory.h"
@@ -1114,16 +1115,35 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
 		LLFloater::setFloaterHost(multi_propertiesp);
 	}
 
-	std::set<LLFolderViewItem*>::iterator set_iter;
-
-	for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter)
-	{
-		LLFolderViewItem* folder_item = *set_iter;
-		if(!folder_item) continue;
-		LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
-		if(!bridge) continue;
-		bridge->performAction(model, action);
-	}
+    
+	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));
+    // Check for actions that get handled in bulk
+    if (action == "wear")
+    {
+        wear_multiple(ids, true);
+    }
+    else if (action == "wear_add")
+    {
+        wear_multiple(ids, false);
+    }
+    else if (action == "take_off" || action == "detach")
+    {
+        LLAppearanceMgr::instance().removeItemsFromAvatar(ids);
+    }
+    else
+    {
+        std::set<LLFolderViewItem*>::iterator set_iter;
+        for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter)
+        {
+            LLFolderViewItem* folder_item = *set_iter;
+            if(!folder_item) continue;
+            LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
+            if(!bridge) continue;
+            bridge->performAction(model, action);
+        }
+    }
 
 	LLFloater::setFloaterHost(NULL);
 	if (multi_previewp)
diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
index b7c4ec6f8b8132caeddfb5b2dd66bb11c047d26c..013a5a7629afe0e0631d9440d8d76713c662162c 100755
--- a/indra/newview/llinventoryicon.cpp
+++ b/indra/newview/llinventoryicon.cpp
@@ -183,6 +183,6 @@ const std::string& LLInventoryIcon::getIconName(LLInventoryType::EIconName idx)
 
 LLInventoryType::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag)
 {
-	const LLWearableType::EType wearable_type = LLWearableType::EType(LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK & misc_flag);
+	const LLWearableType::EType wearable_type = LLWearableType::inventoryFlagsToWearableType(misc_flag);
 	return LLWearableType::getIconName(wearable_type);
 }
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 3546317471287c980815d3c87271a56ccbc378b8..4a230accb6d62673f92b128a633051e676404e85 100755
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -146,7 +146,8 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
 	mShowEmptyMessage(p.show_empty_message),
 	mViewsInitialized(false),
 	mInvFVBridgeBuilder(NULL),
-	mInventoryViewModel(p.name)
+	mInventoryViewModel(p.name),
+	mGroupedItemBridge(new LLFolderViewGroupedItemBridge)
 {
 	mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
 
@@ -186,6 +187,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
 																	NULL,
 																	root_id);
     p.view_model = &mInventoryViewModel;
+	p.grouped_item_model = mGroupedItemBridge;
     p.use_label_suffix = mParams.use_label_suffix;
     p.allow_multiselect = mAllowMultiSelect;
     p.show_empty_message = mShowEmptyMessage;
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index a490dfce5d985f64ee2240dd2f7860a17d3babcd..bc4c10e4418620a1ae9355fb3ceb2e7ff4540cfd 100755
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -43,6 +43,7 @@ class LLInvFVBridge;
 class LLInventoryFolderViewModelBuilder;
 class LLInvPanelComplObserver;
 class LLFolderViewModelInventory;
+class LLFolderViewGroupedItemBridge;
 
 namespace LLInitParam
 {
@@ -240,6 +241,7 @@ class LLInventoryPanel : public LLPanel
 	LLScrollContainer*			mScroller;
 
 	LLFolderViewModelInventory	mInventoryViewModel;
+    LLPointer<LLFolderViewGroupedItemBridge> mGroupedItemBridge;
 	Params						mParams;	// stored copy of parameter block
 
 	std::map<LLUUID, LLFolderViewItem*> mItemMap;
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 8fb75501690f23402b29360a2348ef8743128513..1380345164d7b3c5b8e8057c2760ee30e9df2335 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -545,12 +545,14 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp
 					LLAvatarAppearanceDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind);
 					if (reg_texind != LLAvatarAppearanceDefines::TEX_NUM_INDICES)
 					{
-						U32 index = gAgentWearables.getWearableIndex(wearable);
-						gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index);
-						gAgentAvatarp->wearableUpdated(type);
-
-						/* telling the manager to rebake once update cycle is fully done */
-						LLLocalBitmapMgr::setNeedsRebake();
+						U32 index;
+						if (gAgentWearables.getWearableIndex(wearable,index))
+						{
+							gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index);
+							gAgentAvatarp->wearableUpdated(type);
+							/* telling the manager to rebake once update cycle is fully done */
+							LLLocalBitmapMgr::setNeedsRebake();
+						}
 					}
 
 				}
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 65ac11092c5d8bd3fa6f0c6e31742ee862f9ab0e..88bfefa8b8bc8e4d4bed464493817768f92a1e10 100755
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -47,6 +47,7 @@
 #include "pipeline.h"
 
 #include <boost/tokenizer.hpp>
+#include <boost/bind.hpp>
 
 #include "lldispatcher.h"
 #include "llxfermanager.h"
@@ -146,22 +147,6 @@ std::string LLMute::getDisplayType() const
 	}
 }
 
-
-/* static */
-LLMuteList* LLMuteList::getInstance()
-{
-	// Register callbacks at the first time that we find that the message system has been created.
-	static BOOL registered = FALSE;
-	if( !registered && gMessageSystem != NULL)
-	{
-		registered = TRUE;
-		// Register our various callbacks
-		gMessageSystem->setHandlerFuncFast(_PREHASH_MuteListUpdate, processMuteListUpdate);
-		gMessageSystem->setHandlerFuncFast(_PREHASH_UseCachedMuteList, processUseCachedMuteList);
-	}
-	return LLSingleton<LLMuteList>::getInstance(); // Call the "base" implementation.
-}
-
 //-----------------------------------------------------------------------------
 // LLMuteList()
 //-----------------------------------------------------------------------------
@@ -169,6 +154,18 @@ LLMuteList::LLMuteList() :
 	mIsLoaded(FALSE)
 {
 	gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
+
+	// Register our callbacks. We may be constructed before gMessageSystem, so
+	// use callWhenReady() to register them as soon as gMessageSystem becomes
+	// available.
+	// When using bind(), must be explicit about default arguments such as
+	// that last NULL.
+	gMessageSystem.callWhenReady(boost::bind(&LLMessageSystem::setHandlerFuncFast, _1,
+											 _PREHASH_MuteListUpdate, processMuteListUpdate,
+											 static_cast<void**>(NULL)));
+	gMessageSystem.callWhenReady(boost::bind(&LLMessageSystem::setHandlerFuncFast, _1,
+											 _PREHASH_UseCachedMuteList, processUseCachedMuteList,
+											 static_cast<void**>(NULL)));
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index 3e998b4f0e2ad852bf37485fdbf122fc1f00786a..d315f225bfb35d6145a6b510063688aa8c5e38b8 100755
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -84,11 +84,6 @@ class LLMuteList : public LLSingleton<LLMuteList>
 	LLMuteList();
 	~LLMuteList();
 
-	// Implemented locally so that we can perform some delayed initialization. 
-	// Callers should be careful to call this one and not LLSingleton<LLMuteList>::getInstance()
-	// which would circumvent that mechanism. -MG
-	static LLMuteList* getInstance();
-
 	void addObserver(LLMuteListObserver* observer);
 	void removeObserver(LLMuteListObserver* observer);
 
diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h
index 7878bab24ed0640c251d4b7222642c16362a0d56..de12a39547c2883238354ac2b9bab535571b94a5 100755
--- a/indra/newview/llnavigationbar.h
+++ b/indra/newview/llnavigationbar.h
@@ -29,6 +29,7 @@
 
 #include "llpanel.h"
 #include "llbutton.h"
+#include "llinitdestroyclass.h"
 
 class LLLocationInputCtrl;
 class LLMenuGL;
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 19a86cdceae1b28972fcbd28cfa14dac7f629f7c..9bd6007772d4b129fae68222c242055759ef4aec 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -925,17 +925,17 @@ void LLPanelEditWearable::onCommitSexChange()
         if (!isAgentAvatarValid()) return;
 
         LLWearableType::EType type = mWearablePtr->getType();
-        U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
-
-        if( !gAgentWearables.isWearableModifiable(type, index))
+        U32 index;
+        if( !gAgentWearables.getWearableIndex(mWearablePtr, index) ||
+			!gAgentWearables.isWearableModifiable(type, index))
         {
-                return;
+			return;
         }
 
         LLViewerVisualParam* param = static_cast<LLViewerVisualParam*>(gAgentAvatarp->getVisualParam( "male" ));
         if( !param )
         {
-                return;
+			return;
         }
 
         bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE;
@@ -978,10 +978,17 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
                         }
                         if (getWearable())
                         {
-                                U32 index = gAgentWearables.getWearableIndex(getWearable());
-                                gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
-                                LLVisualParamHint::requestHintUpdates();
-                                gAgentAvatarp->wearableUpdated(type);
+							U32 index;
+							if (gAgentWearables.getWearableIndex(getWearable(), index))
+							{
+								gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
+								LLVisualParamHint::requestHintUpdates();
+								gAgentAvatarp->wearableUpdated(type);
+							}
+							else
+							{
+								LL_WARNS() << "wearable not found in gAgentWearables" << LL_ENDL;
+							}
                         }
                 }
                 else
@@ -1058,7 +1065,12 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)
                 return;
         }
 
-        U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
+        U32 index;
+		if (!gAgentWearables.getWearableIndex(mWearablePtr, index))
+		{
+			LL_WARNS() << "wearable not found" << LL_ENDL;
+			return;
+		}
 
         std::string new_name = mNameEditor->getText();
 
@@ -1574,6 +1586,12 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
 
         LL_INFOS() << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << LL_ENDL;
 
+		U32 index;
+		if (!gAgentWearables.getWearableIndex(getWearable(),index))
+		{
+			LL_WARNS() << "wearable not found" << LL_ENDL;
+			return;
+		}
         bool new_invis_state = checkbox_ctrl->get();
         if (new_invis_state)
         {
@@ -1581,9 +1599,8 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
                 mPreviousAlphaTexture[te] = lto->getID();
                 
                 LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );
-                U32 index = gAgentWearables.getWearableIndex(getWearable());
-                gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
-                gAgentAvatarp->wearableUpdated(getWearable()->getType());
+				gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
+				gAgentAvatarp->wearableUpdated(getWearable()->getType());
         }
         else
         {
@@ -1598,7 +1615,6 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
                 LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id);
                 if (!image) return;
 
-                U32 index = gAgentWearables.getWearableIndex(getWearable());
                 gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
                 gAgentAvatarp->wearableUpdated(getWearable()->getType());
         }
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 17c0b226d0c2401e8659244febe4a899f1a62a09..06a7346f2aaaf1fb5ef64d09a90c4f1dd0149b7e 100755
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -1278,7 +1278,7 @@ void LLPanelMainInventory::setUploadCostIfNeeded()
 		LLMenuItemBranchGL* upload_menu = mMenuAdd->findChild<LLMenuItemBranchGL>("upload");
 		if(upload_menu)
 		{
-			S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+			S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload();
 			std::string cost_str;
 
 			// getPriceUpload() returns -1 if no data available yet.
diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp
index c8a201a5c85e5bc833b1432057b5fdbaef2f2cd3..48948a7567c00b4a2d1d25c8bde23d15948981f2 100755
--- a/indra/newview/llpanelsnapshotinventory.cpp
+++ b/indra/newview/llpanelsnapshotinventory.cpp
@@ -78,7 +78,7 @@ BOOL LLPanelSnapshotInventory::postBuild()
 // virtual
 void LLPanelSnapshotInventory::onOpen(const LLSD& key)
 {
-	getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()));
+	getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLGlobalEconomy::getInstance()->getPriceUpload()));
 	LLPanelSnapshot::onOpen(key);
 }
 
diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp
index 0fc9ceec8318fc59c02e99998bb5edef0ece2de2..2a446748025ab52f677bf50efd65467dff288fef 100755
--- a/indra/newview/llpanelsnapshotoptions.cpp
+++ b/indra/newview/llpanelsnapshotoptions.cpp
@@ -75,12 +75,12 @@ LLPanelSnapshotOptions::LLPanelSnapshotOptions()
 	mCommitCallbackRegistrar.add("Snapshot.SendToFacebook",		boost::bind(&LLPanelSnapshotOptions::onSendToFacebook, this));
 	mCommitCallbackRegistrar.add("Snapshot.SendToTwitter",		boost::bind(&LLPanelSnapshotOptions::onSendToTwitter, this));
 	mCommitCallbackRegistrar.add("Snapshot.SendToFlickr",		boost::bind(&LLPanelSnapshotOptions::onSendToFlickr, this));
-	LLGlobalEconomy::Singleton::getInstance()->addObserver(this);
+	LLGlobalEconomy::getInstance()->addObserver(this);
 }
 
 LLPanelSnapshotOptions::~LLPanelSnapshotOptions()
 {
-	LLGlobalEconomy::Singleton::getInstance()->removeObserver(this);
+	LLGlobalEconomy::getInstance()->removeObserver(this);
 }
 
 // virtual
@@ -97,7 +97,7 @@ void LLPanelSnapshotOptions::onOpen(const LLSD& key)
 
 void LLPanelSnapshotOptions::updateUploadCost()
 {
-	S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+	S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload();
 	getChild<LLUICtrl>("save_to_inventory_btn")->setLabelArg("[AMOUNT]", llformat("%d", upload_cost));
 }
 
diff --git a/indra/newview/llpaneltopinfobar.h b/indra/newview/llpaneltopinfobar.h
index f37bd9c048823990ffab34a7c02823ff958d5ca9..274d70c6f9d3619a59c78c60e6cd2526ee398621 100755
--- a/indra/newview/llpaneltopinfobar.h
+++ b/indra/newview/llpaneltopinfobar.h
@@ -28,6 +28,7 @@
 #define LLPANELTOPINFOBAR_H_
 
 #include "llpanel.h"
+#include "llinitdestroyclass.h"
 
 class LLButton;
 class LLTextBox;
diff --git a/indra/newview/llsearchhistory.h b/indra/newview/llsearchhistory.h
index 3309a8fcac0d2a0447e4dd88220fe932fc3b461a..ade81675c21ac3560c7645c8ec43d64b9c4e9409 100755
--- a/indra/newview/llsearchhistory.h
+++ b/indra/newview/llsearchhistory.h
@@ -28,6 +28,7 @@
 #define LL_LLSEARCHHISTORY_H
 
 #include "llsingleton.h"
+#include "llinitdestroyclass.h"
 #include "llui.h"
 
 /**
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 64f24cd2912af125215791284db4265b5a04b0ad..ea7cf826746bcef649fe477b5cd5819c109aa896 100755
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -212,7 +212,8 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
 			}
 			if (is_wearable_edit_visible)
 			{
-				if (gAgentWearables.getWearableIndex(wearable_ptr) == LLAgentWearables::MAX_CLOTHING_PER_TYPE)
+				U32 index;
+				if (!gAgentWearables.getWearableIndex(wearable_ptr,index))
 				{
 					// we're no longer wearing the wearable we were last editing, switch back to outfit editor
 					showOutfitEditPanel();
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 0ae8a338e08f5c3f1ad4f219bf475f53ee1dede9..2e9df1f13fe8630439bb2fbf56dab73cef1b4d5b 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -1005,7 +1005,7 @@ void LLSnapshotLivePreview::saveTexture()
 		std::string who_took_it;
 		LLAgentUI::buildFullname(who_took_it);
 		LLAssetStorage::LLStoreAssetCallback callback = NULL;
-		S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+		S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload();
 		void *userdata = NULL;
 		upload_new_resource(tid,	// tid
 			LLAssetType::AT_TEXTURE,
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 42fc3001877d6456f9c527403bbedce6550e7fbb..3a85468bdad4cde51b2ba488966c68ddcb29e482 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -194,6 +194,7 @@
 #include "llevents.h"
 #include "llstartuplistener.h"
 #include "lltoolbarview.h"
+#include "llcleanup.h"
 
 #if LL_WINDOWS
 #include "lldxhardware.h"
@@ -2826,7 +2827,7 @@ void LLStartUp::initNameCache()
 
 void LLStartUp::cleanupNameCache()
 {
-	LLAvatarNameCache::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLAvatarNameCache);
 
 	delete gCacheName;
 	gCacheName = NULL;
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 71b41476f53f62fa0b54afa5b814bcd22c023ff4..cff3711bb9fca566a7e94d418412cc1e115cef19 100755
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -32,6 +32,7 @@
 #include "llscreenchannel.h"
 #include "llsyswellitem.h"
 #include "lltransientdockablefloater.h"
+#include "llinitdestroyclass.h"
 
 class LLAvatarName;
 class LLChiclet;
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index d6c8ba10f6f45cf1079af9642954ad93c681d7cb..d1121180821c4abe08aa75fa88bdcc3897d15dbb 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -2106,7 +2106,7 @@ LLWearableType::EType LLViewerInventoryItem::getWearableType() const
 	{
 		return LLWearableType::WT_INVALID;
 	}
-	return LLWearableType::EType(getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK);
+	return LLWearableType::inventoryFlagsToWearableType(getFlags());
 }
 
 
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index ca925656003be0b167ad8d6b6eb2cf75c4219376..78b61d4fbc62b134228145f0a44055d9042c0a05 100755
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -30,7 +30,7 @@
 #include "llinventory.h"
 #include "llframetimer.h"
 #include "llwearable.h"
-#include "llui.h" //for LLDestroyClass
+#include "llinitdestroyclass.h" //for LLDestroyClass
 
 #include <boost/signals2.hpp>	// boost::signals2::trackable
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 3b0adcf7f4cdb4af4c8ed31ad5de94d1504e3092..ee2abaab4bfba22b0762b1bcc884f05db2cc08d1 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -130,6 +130,7 @@
 #include "llpathfindingmanager.h"
 #include "llstartup.h"
 #include "boost/unordered_map.hpp"
+#include "llcleanup.h"
 
 using namespace LLAvatarAppearanceDefines;
 
@@ -8416,7 +8417,7 @@ class LLWorldPostProcess : public view_listener_t
 
 void handle_flush_name_caches()
 {
-	LLAvatarNameCache::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLAvatarNameCache);
 	if (gCacheName) gCacheName->clear();
 }
 
@@ -8460,7 +8461,7 @@ class LLToggleUIHints : public view_listener_t
 
 void LLUploadCostCalculator::calculateCost()
 {
-	S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+	S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload();
 
 	// getPriceUpload() returns -1 if no data available yet.
 	if(upload_cost >= 0)
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index f8e50ba463e616fff5f09006fdd3eade1967affb..deba6e130ec50575277d3315f2a5370ea94ff5bd 100755
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -83,7 +83,7 @@ class LLFileEnableUpload : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
+		bool new_value = gStatusBar && LLGlobalEconomy::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::getInstance()->getPriceUpload());
 		return new_value;
 	}
 };
@@ -433,7 +433,7 @@ class LLFileUploadBulk : public view_listener_t
 			
 			std::string display_name = LLStringUtil::null;
 			LLAssetStorage::LLStoreAssetCallback callback = NULL;
-			S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+			S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload();
 			void *userdata = NULL;
 
 			upload_new_resource(
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 5cd92c99202f50b7ef531e8179b349496b445470..6f36317265006ca49c2ac9c135f917eaf1d74a95 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -6222,9 +6222,9 @@ void process_frozen_message(LLMessageSystem *msgsystem, void **user_data)
 // do some extra stuff once we get our economy data
 void process_economy_data(LLMessageSystem *msg, void** /*user_data*/)
 {
-	LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::Singleton::getInstance());
+	LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::getInstance());
 
-	S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+	S32 upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload();
 
 	LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL;
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index a2c0a91ea64017a8c638abfaacf1510253e1c084..f463c620d3851b9b303eec67743be215228a6dc6 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -102,6 +102,7 @@
 #include "llmediaentry.h"
 #include "llfloaterperms.h"
 #include "llvocache.h"
+#include "llcleanup.h"
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -527,11 +528,11 @@ void LLViewerObject::initVOClasses()
 
 void LLViewerObject::cleanupVOClasses()
 {
-	LLVOGrass::cleanupClass();
-	LLVOWater::cleanupClass();
-	LLVOTree::cleanupClass();
-	LLVOAvatar::cleanupClass();
-	LLVOVolume::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLVOGrass);
+	SUBSYSTEM_CLEANUP(LLVOWater);
+	SUBSYSTEM_CLEANUP(LLVOTree);
+	SUBSYSTEM_CLEANUP(LLVOAvatar);
+	SUBSYSTEM_CLEANUP(LLVOVolume);
 
 	sObjectDataMap.clear();
 }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index e317989f043e56d32173bfdd69e90572c90ad649..12ff88c517941f20f030059afbf41f3b3fb5ff3e 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -208,6 +208,7 @@
 #include "llwindowlistener.h"
 #include "llviewerwindowlistener.h"
 #include "llpaneltopinfobar.h"
+#include "llcleanup.h"
 
 #if LL_WINDOWS
 #include <tchar.h> // For Unicode conversion methods
@@ -2124,7 +2125,7 @@ void LLViewerWindow::shutdownGL()
 	// Shutdown GL cleanly.  Order is very important here.
 	//--------------------------------------------------------
 	LLFontGL::destroyDefaultFonts();
-	LLFontManager::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLFontManager);
 	stop_glerror();
 
 	gSky.cleanup();
@@ -2147,7 +2148,7 @@ void LLViewerWindow::shutdownGL()
 	LLWorldMapView::cleanupTextures();
 
 	LLViewerTextureManager::cleanup() ;
-	LLImageGL::cleanupClass() ;
+	SUBSYSTEM_CLEANUP(LLImageGL) ;
 
 	LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;
 
@@ -2160,7 +2161,7 @@ void LLViewerWindow::shutdownGL()
 
 	gGL.shutdown();
 
-	LLVertexBuffer::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLVertexBuffer);
 
 	LL_INFOS() << "LLVertexBuffer cleaned." << LL_ENDL ;
 }
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 1e9945b51477a4f5c5a3a777803fab27fdacab36..56997c928ad9a20d11bc8e94112533e0b251b3c2 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1570,8 +1570,16 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t
 		return LLVOAvatar::isTextureVisible(type);
 	}
 
-	U32 index = gAgentWearables.getWearableIndex(wearable);
-	return isTextureVisible(type,index);
+	U32 index;
+	if (gAgentWearables.getWearableIndex(wearable,index))
+	{
+		return isTextureVisible(type,index);
+	}
+	else
+	{
+		LL_WARNS() << "Wearable not found" << LL_ENDL;
+		return FALSE;
+	}
 }
 
 bool LLVOAvatarSelf::areTexturesCurrent() const
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index fac0fd63eeaf26d130d9e7d7fd8385d5ee733325..888ead06137043b19378ebafd11d097e255244a3 100755
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -894,13 +894,13 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
 	setMenuItemVisible(menu, "wear_wear", 			n_already_worn == 0 && n_worn == 0 && can_be_worn);
 	setMenuItemEnabled(menu, "wear_wear", 			n_already_worn == 0 && n_worn == 0);
 	setMenuItemVisible(menu, "wear_add",			wear_add_visible);
-	setMenuItemEnabled(menu, "wear_add",			canAddWearables(ids));
+	setMenuItemEnabled(menu, "wear_add",			LLAppearanceMgr::instance().canAddWearables(ids));
 	setMenuItemVisible(menu, "wear_replace",		n_worn == 0 && n_already_worn != 0 && can_be_worn);
 	//visible only when one item selected and this item is worn
 	setMenuItemVisible(menu, "edit",				!standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1);
 	setMenuItemEnabled(menu, "edit",				n_editable == 1 && n_worn == 1 && n_items == 1);
 	setMenuItemVisible(menu, "create_new",			mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1);
-	setMenuItemEnabled(menu, "create_new",			canAddWearables(ids));
+	setMenuItemEnabled(menu, "create_new",			LLAppearanceMgr::instance().canAddWearables(ids));
 	setMenuItemVisible(menu, "show_original",		!standalone);
 	setMenuItemEnabled(menu, "show_original",		n_items == 1 && n_links == n_items);
 	setMenuItemVisible(menu, "take_off",			mask == MASK_CLOTHING && n_worn == n_items);
@@ -1004,65 +1004,4 @@ void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id)
 	LLAgentWearables::createWearable(item->getWearableType(), true);
 }
 
-// Returns true if all the given objects and clothes can be added.
-// static
-bool LLWearableItemsList::ContextMenu::canAddWearables(const uuid_vec_t& item_ids)
-{
-	// TODO: investigate wearables may not be loaded at this point EXT-8231
-
-	U32 n_objects = 0;
-	boost::unordered_map<LLWearableType::EType, U32> clothes_by_type;
-
-	// Count given clothes (by wearable type) and objects.
-	for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it)
-	{
-		LLViewerInventoryItem* item = gInventory.getItem(*it);
-		if (!item)
-		{
-			return false;
-		}
-
-		if (item->getType() == LLAssetType::AT_OBJECT)
-		{
-			++n_objects;
-		}
-		else if (item->getType() == LLAssetType::AT_CLOTHING)
-		{
-			++clothes_by_type[item->getWearableType()];
-		}
-		else
-		{
-			LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
-			return false;
-		}
-	}
-
-	// Check whether we can add all the objects.
-	if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects))
-	{
-		return false;
-	}
-
-	// Check whether we can add all the clothes.
-	boost::unordered_map<LLWearableType::EType, U32>::const_iterator m_it;
-	for (m_it = clothes_by_type.begin(); m_it != clothes_by_type.end(); ++m_it)
-	{
-		LLWearableType::EType w_type	= m_it->first;
-		U32 n_clothes					= m_it->second;
-
-		U32 wearable_count = gAgentWearables.getWearableCount(w_type);
-		if ((wearable_count > 0) && !LLWearableType::getAllowMultiwear(w_type))
-		{
-			return false;
-		}
-		if ((wearable_count + n_clothes) > LLAgentWearables::MAX_CLOTHING_PER_TYPE)
-		{
-			return false;
-		}
-
-	}
-
-	return true;
-}
-
 // EOF
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index c731a7d6cf2cea53e81648c09ed7a99036f153f3..e6788ab249dafb1bcd5953a488eea084f2fccb43 100755
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -429,7 +429,6 @@ class LLWearableItemsList : public LLInventoryItemsList
 		static void setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val);
 		static void updateMask(U32& mask, LLAssetType::EType at);
 		static void createNewWearable(const LLUUID& item_id);
-		static bool canAddWearables(const uuid_vec_t& item_ids);
 
 		LLWearableItemsList*	mParent;
 	};
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 03712c1065e31c3ed57b6f0682681020e970d690..9c1b78626ff2d504f4dd9740739ec5b78419efd1 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -115,6 +115,7 @@
 #include "llpathfindingpathtool.h"
 #include "llscenemonitor.h"
 #include "llprogressview.h"
+#include "llcleanup.h"
 
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
@@ -7373,7 +7374,7 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 	}
 	LLVOPartGroup::destroyGL();
 
-	LLVertexBuffer::cleanupClass();
+	SUBSYSTEM_CLEANUP(LLVertexBuffer);
 	
 	//delete all name pool caches
 	LLGLNamePool::cleanupPools();
diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp
index c49b0350e9b279925145c3674de7861cbd8a9297..5e3649fdaedb19dfeee0a263e64736f27be634bc 100755
--- a/indra/newview/tests/llremoteparcelrequest_test.cpp
+++ b/indra/newview/tests/llremoteparcelrequest_test.cpp
@@ -33,6 +33,7 @@
 #include "../llagent.h"
 #include "message.h"
 #include "llurlentry.h"
+#include "llpounceable.h"
 
 namespace {
 	const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111");
@@ -61,7 +62,7 @@ void LLMessageSystem::addUUID(char const *,LLUUID const &) { }
 void LLMessageSystem::addUUIDFast(char const *,LLUUID const &) { }
 void LLMessageSystem::nextBlockFast(char const *) { }
 void LLMessageSystem::newMessage(char const *) { }
-LLMessageSystem * gMessageSystem;
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
 char const* const _PREHASH_AgentID = 0;   // never dereferenced during this test
 char const* const _PREHASH_AgentData = 0; // never dereferenced during this test
 LLAgent gAgent;
diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp
index aa23699de07298dedd615cd8b5c1e60b6f216205..b9c025f518f040c0ee172bea6ff5e2f1daf69702 100755
--- a/indra/test/message_tut.cpp
+++ b/indra/test/message_tut.cpp
@@ -103,7 +103,7 @@ namespace tut
 		~LLMessageSystemTestData()
 		{
 			// not end_messaging_system()
-			delete gMessageSystem;
+			delete static_cast<LLMessageSystem*>(gMessageSystem);
 			gMessageSystem = NULL;
 
 			// rm contents of temp dir