diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index d2d507d676613316a9ac6f174df6259a28417da6..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
diff --git a/indra/llcommon/llinitdestroyclass.h b/indra/llcommon/llinitdestroyclass.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca5c3f07de82213a097ea569fd2544abe1a6f2e8
--- /dev/null
+++ b/indra/llcommon/llinitdestroyclass.h
@@ -0,0 +1,134 @@
+/**
+ * @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>
+
+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);
+
+#endif /* ! defined(LL_LLINITDESTROYCLASS_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.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/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/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/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/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/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/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.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