diff --git a/.hgpatchinfo/.RLVa.dep b/.hgpatchinfo/.RLVa.dep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/.hgpatchinfo/RLVa.dep b/.hgpatchinfo/RLVa.dep
new file mode 100644
index 0000000000000000000000000000000000000000..f7595c62c565d0106a8bcdcc1cea926dfd1f9055
--- /dev/null
+++ b/.hgpatchinfo/RLVa.dep
@@ -0,0 +1 @@
+54ad5d2837e09f9005b1772f2273b3ce4301ef6a
\ No newline at end of file
diff --git a/.hgtags b/.hgtags
index 2b890cd5f5cccb61aaf1726c1c2ee176dbe230c9..55785ce20e8c9509fb51fcaf05b905905ccc7ac1 100755
--- a/.hgtags
+++ b/.hgtags
@@ -1147,4 +1147,14 @@ e9d350764dfbf5a46229e627547ef5c1b1eeef00 SL-4.0.2
 450de775fff66a011be1a001acd117cc623c445d SL-4.0.5
 4070611edd95eb3a683d1cd97c4c07fe67793812 SL-4.0.6
 33981d8130f031597b4c7f4c981b18359afb61a0 SL-4.0.7
-45eaee56883df7a439ed3300c44d3126f7e3a41e SL-4.0.8
\ No newline at end of file
+45eaee56883df7a439ed3300c44d3126f7e3a41e SL-4.0.8
+89532c8dfd5b6c29f1cb032665b44a74a52452e1 RLVa-1.3.0
+7bc5039ccf0b36eafbf6ce33a52b5e26332aa04c RLVa-1.3.1
+a563f7e215c7883c1cfd20908085687a0ed96284 RLVa-1.4.0
+40644beae9c4a617504163d5c9f195dc7bfff1b4 RLVa-1.4.1
+8787094c309a44ca32b7472acc9217a3c37f00c3 RLVa-1.4.2
+11c6c85ddd223bcbd6b3afc53f9a0f5fd349ba65 RLVa-1.4.3
+53b44208d44a601fe24e78c1a1909dc82356cded RLVa-1.4.4
+6522747820037cc11e5b7d0491a0a9808a958709 RLVa-1.4.5
+0c8f23b2c4cf96d1a08bd527b3ccb6339a9fdb60 RLVa-1.4.6
+674db463770b78f836fc9c87a1b2235e212a576c RLVa-1.4.7
diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp
index a0418f09d50b21867074cb178057b4a7afb1f2d4..36409a6fb7d0b04fd184c99e34d81bc03f4d5874 100644
--- a/indra/integration_tests/llui_libtest/llui_libtest.cpp
+++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp
@@ -52,6 +52,17 @@ LLControlGroup gSavedSettings("Global");	// saved at end of session
 LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session
 LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings
 
+// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+#include "llavatarname.h"
+
+// Stub for rlvGetAnonym
+const std::string& rlvGetAnonym(const LLAvatarName& avName)
+{
+	static std::string strAnonym = "A resident";
+	return strAnonym;
+}
+// [/RLVa:KB]
+
 // We can't create LLImageGL objects because we have no window or rendering 
 // context.  Provide enough of an LLUIImage to test the LLUI library without
 // an underlying image.
diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp
index 2bf3b9085b813e75a2992ede703ab60b7502954a..c826e1ff2471a9b350635afdd387deac4cd87387 100644
--- a/indra/llappearance/llwearabledata.cpp
+++ b/indra/llappearance/llwearabledata.cpp
@@ -103,7 +103,15 @@ void LLWearableData::pushWearable(const LLWearableType::EType type,
 	}
 	if (canAddWearable(type))
 	{
-		mWearableDatas[type].push_back(wearable);
+// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0)
+		// Don't add the same wearable twice
+		U32 idxWearable = 0;
+		if (!getWearableIndex(wearable, idxWearable))
+			mWearableDatas[type].push_back(wearable);
+		else
+			llassert(false); // pushWearable() on an already added wearable is a bug *somewhere*
+// [/RLVa:KB]
+//		mWearableDatas[type].push_back(wearable);		mWearableDatas[type].push_back(wearable);
 		if (trigger_updated)
 		{
 			const BOOL removed = FALSE;
@@ -150,16 +158,16 @@ void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index)
 	}
 }
 
-void LLWearableData::clearWearableType(const LLWearableType::EType type)
-{
-	wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
-	if (wearable_iter == mWearableDatas.end())
-	{
-		return;
-	}
-	wearableentry_vec_t& wearable_vec = wearable_iter->second;
-	wearable_vec.clear();
-}
+//void LLWearableData::clearWearableType(const LLWearableType::EType type)
+//{
+//	wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+//	if (wearable_iter == mWearableDatas.end())
+//	{
+//		return;
+//	}
+//	wearableentry_vec_t& wearable_vec = wearable_iter->second;
+//	wearable_vec.clear();
+//}
 
 bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b)
 {
diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h
index a0c446ea9e2bc6810ff85e8249c0251e0efd7e15..cb274ca52453932f86a5ae34768ccc5b396d539c 100644
--- a/indra/llappearance/llwearabledata.h
+++ b/indra/llappearance/llwearabledata.h
@@ -79,7 +79,7 @@ class LLWearableData
 	virtual void	wearableUpdated(LLWearable *wearable, BOOL removed);
 	void 			eraseWearable(LLWearable *wearable);
 	void			eraseWearable(const LLWearableType::EType type, U32 index);
-	void			clearWearableType(const LLWearableType::EType type);
+//	void			clearWearableType(const LLWearableType::EType type);
 	bool			swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b);
 
 private:
diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp
index 0cc8a6975833e5913ae6b6bb78e7b12131d29701..8df4ff4de661ee3b495a4379f7d951408a98604f 100644
--- a/indra/llappearance/llwearabletype.cpp
+++ b/indra/llappearance/llwearabletype.cpp
@@ -73,6 +73,12 @@ class LLWearableDictionary : public LLSingleton<LLWearableDictionary>,
 {
 public:
 	LLWearableDictionary();
+
+// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+protected:
+	// The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType
+	virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; }
+// [/RLVa:KB]
 };
 
 LLWearableDictionary::LLWearableDictionary()
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 1ca5f58ae2742f568163091757ecd046d49fba0f..9ce75e739083d7faab421dd280155a60027efcea 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -51,6 +51,11 @@ namespace LLAvatarNameCache
 {
 	use_display_name_signal_t mUseDisplayNamesSignal;
 
+// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
+	// RLVa override for display names
+	bool sForceDisplayNames = false;
+// [/RLVa:KB]
+
 	// Cache starts in a paused state until we can determine if the
 	// current region supports display names.
 	bool sRunning = false;
@@ -724,10 +729,30 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag
 	return connection;
 }
 
+// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
+bool LLAvatarNameCache::getForceDisplayNames()
+{
+	return sForceDisplayNames;
+}
+
+void LLAvatarNameCache::setForceDisplayNames(bool force)
+{
+	sForceDisplayNames = force;
+	if ( (!LLAvatarName::useDisplayNames()) && (force) )
+	{
+		LLAvatarName::setUseDisplayNames(true);
+	}
+}
+// [/RLVa:KB]
 
 void LLAvatarNameCache::setUseDisplayNames(bool use)
 {
+// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
+	// We need to force the use of the "display names" cache when @shownames=n restricted (and disallow toggling it)
+	use |= getForceDisplayNames();
+// [/RLVa:KB]
 	if (use != LLAvatarName::useDisplayNames())
+
 	{
 		LLAvatarName::setUseDisplayNames(use);
 		mUseDisplayNamesSignal();
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index bd2715e9567607d7f15d57124c63190dea6d5513..36f2d18d96ec4edfa74bb3a624bf1f783f3279a2 100644
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -82,6 +82,12 @@ namespace LLAvatarNameCache
 	void setUseUsernames(bool use);
 
 	void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
+
+// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
+	bool getForceDisplayNames();
+	void setForceDisplayNames(bool force);
+// [/RLVa:KB]
+
 	void erase(const LLUUID& agent_id);
 
     /// Provide some fallback for agents that return errors.
diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h
index f5b242fdfcddabbbba473dff6b405ad63103d35c..746103b9115590a9cc9400931457848ee79f57f1 100644
--- a/indra/llui/llchat.h
+++ b/indra/llui/llchat.h
@@ -81,6 +81,10 @@ class LLChat
 		mChatType(CHAT_TYPE_NORMAL),
 		mAudible(CHAT_AUDIBLE_FULLY),
 		mMuted(FALSE),
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a
+		mRlvLocFiltered(FALSE),
+		mRlvNamesFiltered(FALSE),
+// [/RLVa:KB]
 		mTime(0.0),
 		mTimeStr(),
 		mPosAgent(),
@@ -98,6 +102,10 @@ class LLChat
 	EChatType		mChatType;
 	EChatAudible	mAudible;
 	BOOL			mMuted;		// pass muted chat to maintain list of chatters
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a
+	BOOL			mRlvLocFiltered;
+	BOOL			mRlvNamesFiltered;
+// [/RLVa:KB]
 	F64				mTime;		// viewer only, seconds from viewer start
 	std::string		mTimeStr;
 	LLVector3		mPosAgent;
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index 92bf429031d216a9a3e85209bb8058816cbe1713..577e4867052ec261bb86279853cf656e3515b777 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -469,6 +469,9 @@ class LLFlatListViewEx : public LLFlatListView
 
 	// *WORKAROUND: two methods to overload appropriate Params due to localization issue:
 	// no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	const std::string& getNoItemsMsg() const { return mNoItemsMsg; }
+// [/RLVa:KB]
 	void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
 	void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
 
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 9ef290abc024cd6629c876d12bad94ad768611b2..8e2dc0338c3590f135992a9d5186ac7b01efa2fd 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -45,6 +45,10 @@ std::set<std::string> LLFloaterReg::sAlwaysShowableList;
 
 static LLFloaterRegListener sFloaterRegListener;
 
+// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a
+LLFloaterReg::validate_signal_t LLFloaterReg::mValidateSignal;
+// [/RLVa:KB]
+
 //*******************************************************
 
 //static
@@ -240,12 +244,23 @@ LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::str
 
 // Visibility Management
 
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+//static
+bool LLFloaterReg::canShowInstance(const std::string& name, const LLSD& key)
+{
+	return mValidateSignal(name, key);
+}
+// [/RLVa:KB]
+
 //static
 LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) 
 {
-	if( sBlockShowFloaters
-			// see EXT-7090
-			&& sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
+//	if( sBlockShowFloaters
+//			// see EXT-7090
+//			&& sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
+// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a
+	if ( (sBlockShowFloaters && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) || (!mValidateSignal(name, key)) )
+// [/RLVa:KB]
 		return 0;//
 	LLFloater* instance = getInstance(name, key); 
 	if (instance) 
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index e3b17dcb4fc7507e8846984b61027732275bb0f4..5bafe6466473634237af880d650eb3e1e85e5a8a 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -32,6 +32,10 @@
 
 #include <list>
 #include <boost/function.hpp>
+// [RLVa:KB] - Checked: 2011-05-25 (RLVa-1.4.0a)
+#include <boost/signals2.hpp>
+#include "llboost.h"
+// [/RLVa:KB]
 
 //*******************************************************
 //
@@ -72,6 +76,15 @@ class LLFloaterReg
 	 */
 	static std::set<std::string> sAlwaysShowableList;
 	
+// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a
+	// Used to determine whether a floater can be shown
+public:
+	typedef boost::signals2::signal<bool(const std::string&, const LLSD&), boost_boolean_combiner> validate_signal_t;
+	static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); }
+private:
+	static validate_signal_t mValidateSignal;
+// [/RLVa:KB]
+
 public:
 	// Registration
 	
@@ -100,6 +113,10 @@ class LLFloaterReg
 	static const_instance_list_t& getFloaterList(const std::string& name);
 
 	// Visibility Management
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	// return false if floater can not be shown (=doesn't pass the validation filter)
+	static bool canShowInstance(const std::string& name, const LLSD& key = LLSD());
+// [/RLVa:KB]
 	// return NULL if instance not found or can't create instance (no builder)
 	static LLFloater* showInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE);
 	// Close a floater (may destroy or set invisible)
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 0cb959a3155a4ba230f7b3b635a3da6f6c95ed77..d02adc0596ac8935511f1d2ef9a18ab7b2ec9ac9 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -918,6 +918,13 @@ std::string LLNotification::getLabel() const
 	return (mTemplatep ? label : "");
 }
 
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
+bool LLNotification::hasLabel() const
+{
+	return !mTemplatep->mLabel.empty();
+}
+// [/SL:KB]
+
 std::string LLNotification::getURL() const
 {
 	if (!mTemplatep)
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 354add0b82a0e022bc8d64f8bb53d49c463bf48e..b50938fd944fa942f36f32d67f91ecf24bff1e9e 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -532,6 +532,10 @@ friend class LLNotifications;
 		return mTimestamp;
 	}
 
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
+	bool hasLabel() const;
+// [/SL:KB]
+
 	bool getOfferFromAgent() const
 	{
 		return mOfferFromAgent;
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index abc2b6e9cac2025efa9983566c81e7d9a81d99d1..978cecc0e362a0665be20a1d171d8f7db07bc108 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -1221,6 +1221,9 @@ void LLToolBarButton::setEnabled(BOOL enabled)
 		mImageOverlayColor = mImageOverlayDisabledColor;
 		mImageOverlaySelectedColor = mImageOverlayDisabledColor;
 	}
+// [RLVa:KB] - Checked: 2011-12-17 (RLVa-1.4.5a) | Added: RLVa-1.4.5a
+	LLButton::setEnabled(enabled);
+// [/RLVa:KB]
 }
 
 const std::string LLToolBarButton::getToolTip() const	
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index aabc7ed2e423b61fc6cbff0a63b7f5cfeb4fd121..cd1572a544957aa5ceadedec472224fa6def2df4 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -201,6 +201,9 @@ void LLUI::initClass(const settings_map_t& settings,
 	// Used by menus along with Floater.Toggle to display visibility as a check-mark
 	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD()));
 	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.IsOpen", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD()));
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.CanShow", boost::bind(&LLFloaterReg::canShowInstance, _2, LLSD()));
+// [/RLVa:KB]
 
 	// Parse the master list of commands
 	LLCommandManager::load();
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index e4848362a76bcfd4ac0edf8f4ee52f9cfb86c798..41b6df8229daa2512b59060b56b60fd6d6808e0c 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -792,6 +792,27 @@ std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name)
 	return avatar_name.getAccountName();
 }
 
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+
+// Defined in rlvcommon.cpp - redirects to RlvStrings::getAnonym() since we can't really get to that class from here
+extern const std::string& rlvGetAnonym(const LLAvatarName& avName);
+
+//
+// LLUrlEntryAgentRLVAnonymizedName Describes an RLV anonymized agent name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym
+//
+LLUrlEntryAgentRLVAnonymizedName::LLUrlEntryAgentRLVAnonymizedName()
+{
+	mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/rlvanonym", boost::regex::perl|boost::regex::icase);
+}
+
+std::string LLUrlEntryAgentRLVAnonymizedName::getName(const LLAvatarName& avatar_name)
+{
+	return rlvGetAnonym(avatar_name);
+}
+// [/RLVa:KB]
+
 //
 // LLUrlEntryGroup Describes a Second Life group Url, e.g.,
 // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 413c20a6577168bd3ff0478625fad6af926c5eed..8316353d2b34d1fa19dff66f44402453bda79634 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -295,6 +295,21 @@ class LLUrlEntryAgentUserName : public LLUrlEntryAgentName
 	/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
 };
 
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+///
+/// LLUrlEntryAgentRLVAnonymizedName Describes an RLV anonymized agent name Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym
+/// that diplays an anonym (based on the display name) for an avatar
+/// such as "An individual"
+class LLUrlEntryAgentRLVAnonymizedName : public LLUrlEntryAgentName
+{
+public:
+	LLUrlEntryAgentRLVAnonymizedName();
+private:
+	/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
+};
+// [/RLVa:KB]
+
 ///
 /// LLUrlEntryExperienceProfile Describes a Second Life experience profile Url, e.g.,
 /// secondlife:///app/experience/0e346d8b-4433-4d66-a6b0-fd37083abc4c/profile
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 23c6d5a954cc89dd4a2eb12bf6dc1ab93baf3166..81910a5dd68b5185144c0cf59070c30ac271a0bd 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -38,7 +38,10 @@ void LLUrlRegistryNullCallback(const std::string &url, const std::string &label,
 
 LLUrlRegistry::LLUrlRegistry()
 {
-	mUrlEntry.reserve(20);
+//	mUrlEntry.reserve(20);
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+	mUrlEntry.reserve(21);
+// [/RLVa:KB]
 
 	// Urls are matched in the order that they were registered
 	mUrlEntryNoLink = new LLUrlEntryNoLink();
@@ -59,6 +62,9 @@ LLUrlRegistry::LLUrlRegistry()
 	registerUrl(new LLUrlEntryAgentCompleteName());
 	registerUrl(new LLUrlEntryAgentDisplayName());
 	registerUrl(new LLUrlEntryAgentUserName());
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+	registerUrl(new LLUrlEntryAgentRLVAnonymizedName());
+// [/RLVa:KB]
 	// LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since 
 	// LLUrlEntryAgent is a less specific (catchall for agent urls)
 	registerUrl(new LLUrlEntryAgent());
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index f01178c374c6fac0c30026c6c9100979e5d7842c..ec6fcf4d75d8f3ff351414411a9ea527b52346cf 100644
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -34,6 +34,15 @@
 
 #include <string>
 
+// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+// Stub for rlvGetAnonym
+const std::string& rlvGetAnonym(const LLAvatarName& avName)
+{
+	static std::string strAnonym = "A resident";
+	return strAnonym;
+}
+// [/RLVa:KB]
+
 // Stub for LLAvatarNameCache
 bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
 {
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 896e87be586e246cd4e025e653798555c249fec3..9b0599435205398499077b2a3a2cde767aa0bf69 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -703,6 +703,15 @@ set(viewer_SOURCE_FILES
     llxmlrpctransaction.cpp
     noise.cpp
     pipeline.cpp
+    rlvactions.cpp
+    rlvhandler.cpp
+    rlvhelper.cpp
+    rlvcommon.cpp
+    rlvlocks.cpp
+    rlvinventory.cpp
+    rlvextensions.cpp
+    rlvfloaters.cpp
+    rlvui.cpp
     )
 
 set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING
@@ -1313,6 +1322,16 @@ set(viewer_HEADER_FILES
     macmain.h
     noise.h
     pipeline.h
+    rlvactions.h
+    rlvdefines.h
+    rlvhandler.h
+    rlvhelper.h
+    rlvcommon.h
+    rlvlocks.h
+    rlvinventory.h
+    rlvextensions.h
+    rlvfloaters.h
+    rlvui.h
     roles_constants.h
     VertexCache.h
     VorbisFramework.h
diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml
index a0d3dc0f998ace803f3c6dbc614f1213e2d7694b..7435bcd412e1affe0d42dcc22a522da4c625a0f3 100644
--- a/indra/newview/app_settings/commands.xml
+++ b/indra/newview/app_settings/commands.xml
@@ -7,6 +7,8 @@
            tooltip_ref="Command_AboutLand_Tooltip"
            execute_function="Floater.ToggleOrBringToFront"
            execute_parameters="about_land"
+           is_enabled_function="Floater.CanShow"
+           is_enabled_parameters="about_land"
            is_running_function="Floater.IsOpen"
            is_running_parameters="about_land"
            />
@@ -98,6 +100,8 @@
            tooltip_ref="Command_Inventory_Tooltip"
            execute_function="Floater.ToggleOrBringToFront"
            execute_parameters="inventory"
+           is_enabled_function="RLV.EnableIfNot"
+           is_enabled_parameters="showinv"
            is_running_function="Floater.IsOpen"
            is_running_parameters="inventory"
            />
@@ -108,6 +112,8 @@
            tooltip_ref="Command_Map_Tooltip"
            execute_function="Floater.ToggleOrBringToFront"
            execute_parameters="world_map"
+           is_enabled_function="RLV.EnableIfNot"
+           is_enabled_parameters="showworldmap"
            is_running_function="Floater.IsOpen"
            is_running_parameters="world_map"
            />
@@ -137,6 +143,8 @@
            tooltip_ref="Command_MiniMap_Tooltip"
            execute_function="Floater.ToggleOrBringToFront"
            execute_parameters="mini_map"
+           is_enabled_function="RLV.EnableIfNot"
+           is_enabled_parameters="showminimap"
            is_running_function="Floater.IsOpen"
            is_running_parameters="mini_map"
            />
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 5f5add75b6010de336518b696443dc6a8762c5c2..bba92ad872193ac027adf33afbd8aed4ebb87766 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2,6 +2,259 @@
 <llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation="llsd.xsd">
 <map>
+    <key>RestrainedLove</key>
+    <map>
+      <key>Comment</key>
+      <string>Toggles RLVa features (requires restart)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RestrainedLoveDebug</key>
+    <map>
+      <key>Comment</key>
+      <string>Toggles RLVa debug mode (displays the commands when in debug mode)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RestrainedLoveCanOOC</key>
+    <map>
+      <key>Comment</key>
+      <string>Allows sending OOC chat when send chat restricted, or seeing OOC chat when receive chat restricted</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RestrainedLoveForbidGiveToRLV</key>
+    <map>
+      <key>Comment</key>
+      <string>When TRUE, forbids to give sub-folders to the #RLV folder</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RestrainedLoveNoSetEnv</key>
+    <map>
+      <key>Comment</key>
+      <string>When TRUE, forbids to set the environment (time of day and Windlight settings) via RLVa. (requires restart)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RestrainedLoveReplaceWhenFolderBeginsWith</key>
+    <map>
+      <key>Comment</key>
+      <string>If a folder name begins with this string, its attach behavior will always be "replace", never "stack". Default is blank (disabled).</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string></string>
+    </map>
+    <key>RestrainedLoveShowEllipsis</key>
+    <map>
+      <key>Comment</key>
+      <string>When TRUE, show "..." when someone speaks, while the avatar is prevented from hearing. When FALSE, don't show anything.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RestrainedLoveStackWhenFolderBeginsWith</key>
+    <map>
+      <key>Comment</key>
+      <string>If a folder name begins with this string, its attach behavior will always be "stack", never "replace". Default is "+".</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string>+</string>
+    </map>
+    <key>RLVaCompatibilityModeList</key>
+    <map>
+      <key>Comment</key>
+      <string>Contains a list of creators or partial items names that require compatibility mode handling (see wiki for more information and syntax)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string></string>
+    </map>
+    <key>RLVaDebugDeprecateExplicitPoint</key>
+    <map>
+      <key>Comment</key>
+      <string>Ignore attachment point names on inventory items and categories (incomplete)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RLVaDebugHideUnsetDuplicate</key>
+    <map>
+      <key>Comment</key>
+      <string>Suppresses reporting "unset" or "duplicate" command restrictions when RestrainedLoveDebug is TRUE</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RLVaEnableCompositeFolders</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables composite folders for shared inventory</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RLVaEnableIMQuery</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables a limited number of configuration queries via IM (e.g. @version)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaEnableLegacyNaming</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables legacy naming convention for folders</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaEnableSharedWear</key>
+    <map>
+      <key>Comment</key>
+      <string>Attachments in the shared #RLV folder can be force-attached without needing to specify an attachment point</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaEnableTemporaryAttachments</key>
+    <map>
+      <key>Comment</key>
+      <string>Allows temporary attachments (regardless of origin) to issue RLV commands</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaExperimentalCommands</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables the experimental command set</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaHideLockedLayers</key>
+    <map>
+      <key>Comment</key>
+      <string>Hides "remove outfit" restricted worn clothing layers from @getoufit</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RLVaHideLockedAttachments</key>
+    <map>
+      <key>Comment</key>
+      <string>Hides non-detachable worn attachments from @getattach</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
+    <key>RLVaSharedInvAutoRename</key>
+    <map>
+      <key>Comment</key>
+      <string>Automatically renames shared inventory items when worn</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaShowAssertionFailures</key>
+    <map>
+      <key>Comment</key>
+      <string>Notify the user when an assertion fails</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaTopLevelMenu</key>
+    <map>
+      <key>Comment</key>
+      <string>Show the RLVa specific menu as a top level menu</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
+    <key>RLVaWearReplaceUnlocked</key>
+    <map>
+      <key>Comment</key>
+      <string>Don't block wear replace when at least one attachment on the target attachment point is non-detachable</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>1</boolean>
+    </map>
   <key>ImporterDebug</key>
   <map>
     <key>Comment</key>
@@ -4339,6 +4592,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>ForceMissingType</key>
+    <map>
+      <key>Comment</key>
+      <string>Force this wearable type to be missing from COF</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>255</integer>
+    </map>
     <key>FreezeTime</key>
     <map>
       <key>Comment</key>
@@ -6816,6 +7080,17 @@
       <key>Value</key>
       <integer>305</integer>
     </map>
+    <key>NotificationCanEmbedInIM</key>
+    <map>
+      <key>Comment</key>
+      <string>Controls notification panel embedding in IMs (0 = default, 1 = focused, 2 = never)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>NotificationConferenceIMOptions</key>
     <map>
       <key>Comment</key>
@@ -11129,7 +11404,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <boolean>1</boolean>
     </map>
     <key>NearbyListShowIcons</key>
     <map>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index fd6b1b5b3f032bfad6fd1d9819f355db2e40ac62..05ec070b12b6c7dab7c385e1b9703da9d3bb910e 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -1,5 +1,16 @@
 <llsd>
     <map>
+    <key>RLVaLoginLastLocation</key>
+        <map>
+        <key>Comment</key>
+            <string>Determines whether the next login will be forced to the last logoff location (set by the viewer)</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <boolean>1</boolean>
+        </map>
     <key>AvatarHoverOffsetZ</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index d933537d2e63d5dd57c4c7bf35168bfb292bbb8b..6c31e3304917a969d05f48f77aad71e0d934d647 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -93,6 +93,12 @@
 #include "stringize.h"
 #include "boost/foreach.hpp"
 #include "llcorehttputil.h"
+// [RLVa:KB] - Checked: 2011-11-04 (RLVa-1.4.4a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 using namespace LLAvatarAppearanceDefines;
 
@@ -202,7 +208,10 @@ class LLTeleportRequestViaLocation : public LLTeleportRequest
 class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation
 {
 public:
-	LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal);
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal, const LLVector3& look_at);
+// [/RLVa:KB]
+//	LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal);
 	virtual ~LLTeleportRequestViaLocationLookAt();
 
 	virtual bool canRestartTeleport();
@@ -211,8 +220,14 @@ class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation
 	virtual void restartTeleport();
 
 protected:
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	const LLVector3& getLookAt() const { return mLookAt; }
+// [/RLVa:KB]
 
 private:
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	LLVector3 mLookAt;
+// [/RLVa:KB]
 
 };
 
@@ -356,7 +371,10 @@ LLAgent::LLAgent() :
 	mDoubleTapRunMode(DOUBLETAP_NONE),
 
 	mbAlwaysRun(false),
-	mbRunning(false),
+//	mbRunning(false),
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+	mbTempRun(false),
+// [/RLVa:KB]
 	mbTeleportKeepsLookAt(false),
 
 	mAgentAccess(new LLAgentAccess(gSavedSettings)),
@@ -525,11 +543,11 @@ LLAgent::~LLAgent()
 //-----------------------------------------------------------------------------
 void LLAgent::onAppFocusGained()
 {
-	if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode())
-	{
-		gAgentCamera.changeCameraToDefault();
-		LLToolMgr::getInstance()->clearSavedTool();
-	}
+//	if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode())
+//	{
+//		gAgentCamera.changeCameraToDefault();
+//		LLToolMgr::getInstance()->clearSavedTool();
+//	}
 }
 
 
@@ -715,6 +733,9 @@ void LLAgent::movePitch(F32 mag)
 // Does this parcel allow you to fly?
 BOOL LLAgent::canFly()
 {
+// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) return FALSE;
+// [/RLVa:KB]
 	if (isGodlike()) return TRUE;
 
 	LLViewerRegion* regionp = getRegion();
@@ -763,6 +784,13 @@ void LLAgent::setFlying(BOOL fly)
 
 	if (fly)
 	{
+// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY))
+		{
+			return;
+		}
+// [/RLVa:KB]
+
 		BOOL was_flying = getFlying();
 		if (!canFly() && !was_flying)
 		{
@@ -825,7 +853,14 @@ bool LLAgent::enableFlying()
 
 void LLAgent::standUp()
 {
-	setControlFlags(AGENT_CONTROL_STAND_UP);
+//	setControlFlags(AGENT_CONTROL_STAND_UP);
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	// RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking
+	if ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) )
+	{
+		setControlFlags(AGENT_CONTROL_STAND_UP);
+	}
+// [/RLVa:KB]
 }
 
 void LLAgent::changeParcels()
@@ -921,7 +956,10 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 
 	LLSelectMgr::getInstance()->updateSelectionCenter();
 
-	LLFloaterMove::sUpdateFlyingStatus();
+//	LLFloaterMove::sUpdateFlyingStatus();
+// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+	LLFloaterMove::sUpdateMovementStatus();
+// [/RLVa:KB]
 
 	LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL;
 	mRegionChangedSignal();
@@ -1149,7 +1187,14 @@ LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const
 
 void LLAgent::sitDown()
 {
-	setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+//	setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	// RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking
+	if ( (!rlv_handler_t::isEnabled()) || ((RlvActions::canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) )
+	{
+		setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+	}
+// [/RLVa:KB]
 }
 
 
@@ -1895,7 +1940,10 @@ std::ostream& operator<<(std::ostream &s, const LLAgent &agent)
 //-----------------------------------------------------------------------------
 BOOL LLAgent::needsRenderAvatar()
 {
-	if (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson)
+//	if (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson)
+// [RLVa:KB] - Checked: RLVa-2.0.2
+	if ( (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) || (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELF)) )
+// [/RLVa:KB]
 	{
 		return FALSE;
 	}
@@ -1906,7 +1954,10 @@ BOOL LLAgent::needsRenderAvatar()
 // TRUE if we need to render your own avatar's head.
 BOOL LLAgent::needsRenderHead()
 {
-	return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook());
+// [RLVa:KB] - Checked: RLVa-2.0.2
+	return ((LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook())) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELFHEAD));
+// [/RLVa:KB]
+//	return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook());
 }
 
 //-----------------------------------------------------------------------------
@@ -2432,7 +2483,11 @@ void LLAgent::onAnimStop(const LLUUID& id)
 	}
 	else if (id == ANIM_AGENT_AWAY)
 	{
-		clearAFK();
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Added: RLVa-1.1.0g
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE))
+			clearAFK();
+// [/RLVa:KB]
+//		clearAFK();
 	}
 	else if (id == ANIM_AGENT_STANDUP)
 	{
@@ -3097,7 +3152,36 @@ void LLAgent::sendRevokePermissions(const LLUUID & target, U32 permissions)
 	}
 }
 
-void LLAgent::sendWalkRun(bool running)
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+void LLAgent::setAlwaysRun()
+{
+	mbAlwaysRun = (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_ALWAYSRUN));
+	sendWalkRun();
+}
+
+void LLAgent::setTempRun()
+{
+	mbTempRun = (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_TEMPRUN));
+	sendWalkRun();
+}
+
+void LLAgent::clearAlwaysRun()
+{
+	mbAlwaysRun = false;
+	sendWalkRun();
+}
+
+void LLAgent::clearTempRun()
+{
+	mbTempRun = false;
+	sendWalkRun();
+}
+// [/RLVa:KB]
+
+//void LLAgent::sendWalkRun(bool running)
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+void LLAgent::sendWalkRun()
+// [/RLVa:KB]
 {
 	LLMessageSystem* msgsys = gMessageSystem;
 	if (msgsys)
@@ -3106,7 +3190,10 @@ void LLAgent::sendWalkRun(bool running)
 		msgsys->nextBlockFast(_PREHASH_AgentData);
 		msgsys->addUUIDFast(_PREHASH_AgentID, getID());
 		msgsys->addUUIDFast(_PREHASH_SessionID, getSessionID());
-		msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) );
+//		msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) );
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+		msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(getRunning()) );
+// [/RLVa:KB]
 		sendReliableMessage();
 	}
 }
@@ -3931,10 +4018,13 @@ void LLAgent::handleTeleportFailed()
 	}
 }
 
-void LLAgent::teleportRequest(
-	const U64& region_handle,
-	const LLVector3& pos_local,
-	bool look_at_from_camera)
+//void LLAgent::teleportRequest(
+//	const U64& region_handle,
+//	const LLVector3& pos_local,
+//	bool look_at_from_camera)
+// [RLVa:KB] - Checked: RLVa-2.0.0
+void LLAgent::teleportRequest(const U64& region_handle, const LLVector3& pos_local, const LLVector3& look_at)
+// [/RLVa:KB]
 {
 	LLViewerRegion* regionp = getRegion();
 	bool is_local = (region_handle == regionp->getHandle());
@@ -3950,11 +4040,11 @@ void LLAgent::teleportRequest(
 		msg->nextBlockFast(_PREHASH_Info);
 		msg->addU64("RegionHandle", region_handle);
 		msg->addVector3("Position", pos_local);
-		LLVector3 look_at(0,1,0);
-		if (look_at_from_camera)
-		{
-			look_at = LLViewerCamera::getInstance()->getAtAxis();
-		}
+//		LLVector3 look_at(0,1,0);
+//		if (look_at_from_camera)
+//		{
+//			look_at = LLViewerCamera::getInstance()->getAtAxis();
+//		}
 		msg->addVector3("LookAt", look_at);
 		sendReliableMessage();
 	}
@@ -3963,6 +4053,18 @@ void LLAgent::teleportRequest(
 // Landmark ID = LLUUID::null means teleport home
 void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
 {
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+	// NOTE: we'll allow teleporting home unless both @tplm=n *and* @tploc=n restricted
+	if ( (rlv_handler_t::isEnabled()) &&
+		 ( ( (landmark_asset_id.notNull()) ? gRlvHandler.hasBehaviour(RLV_BHVR_TPLM)
+		                                   : gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC) ) ||
+		   ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->isSitting())) ))
+	{
+		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT);
+		return;
+	}
+// [/RLVa:KB]
+
 	mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id));
 	startTeleportRequest();
 }
@@ -4055,6 +4157,22 @@ void LLAgent::restoreCanceledTeleportRequest()
 
 void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
 {
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	if ( (RlvActions::isRlvEnabled()) && (!RlvUtil::isForceTp()) )
+	{
+		if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() )
+		{
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT);
+			return;
+		}
+
+		if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) )
+		{
+			gRlvHandler.setCanCancelTp(false);
+		}
+	}
+// [/RLVa:KB]
+
 	mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocation(pos_global));
 	startTeleportRequest();
 }
@@ -4107,15 +4225,37 @@ void LLAgent::doTeleportViaLocation(const LLVector3d& pos_global)
 }
 
 // Teleport to global position, but keep facing in the same direction 
-void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global)
+// [RLVa:KB] - Checked: RLVa-2.0.0
+void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at)
 {
-	mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global));
+	if ( (RlvActions::isRlvEnabled()) && (!RlvUtil::isForceTp()) )
+	{
+		if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() )
+		{
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT);
+			return;
+		}
+
+		if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) )
+		{
+			gRlvHandler.setCanCancelTp(false);
+		}
+	}
+
+	mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global, (look_at.isExactlyZero()) ? LLViewerCamera::getInstance()->getAtAxis() : look_at));
 	startTeleportRequest();
 }
+// [/RLVa:KB]
+//void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global)
+//{
+//	mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global));
+//	startTeleportRequest();
+//}
 
-void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global)
+// [RLVa:KB] - Checked: RLVa-2.0.0
+void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at)
 {
-	mbTeleportKeepsLookAt = true;
+	mbTeleportKeepsLookAt = look_at.isExactlyZero();
 
 	if(!gAgentCamera.isfollowCamLocked())
 	{
@@ -4124,8 +4264,23 @@ void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global)
 
 	U64 region_handle = to_region_handle(pos_global);
 	LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle));
-	teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt());
+	teleportRequest(region_handle, pos_local, look_at);
 }
+// [/RLVa:KB]
+//void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at)
+//{
+//	mbTeleportKeepsLookAt = true;
+//
+//	if(!gAgentCamera.isfollowCamLocked())
+//	{
+//		gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);	// detach camera form avatar, so it keeps direction
+//	}
+//
+//	U64 region_handle = to_region_handle(pos_global);
+//	LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle));
+//	teleportRequest(region_handle, pos_local, look_at);
+//	teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt());
+//}
 
 LLAgent::ETeleportState	LLAgent::getTeleportState() const
 {
@@ -4594,11 +4749,18 @@ void LLTeleportRequestViaLocation::restartTeleport()
 // LLTeleportRequestViaLocationLookAt
 //-----------------------------------------------------------------------------
 
-LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal)
-	: LLTeleportRequestViaLocation(pPosGlobal)
+// [RLVa:KB] - Checked: RLVa-2.0.0
+LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal, const LLVector3& look_at)
+	: LLTeleportRequestViaLocation(pPosGlobal), mLookAt(look_at)
 {
     LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt created" << LL_ENDL;
 }
+// [/RLVa:KB]
+
+//LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal)
+//	: LLTeleportRequestViaLocation(pPosGlobal)
+//{
+//}
 
 LLTeleportRequestViaLocationLookAt::~LLTeleportRequestViaLocationLookAt()
 {
@@ -4614,13 +4776,19 @@ bool LLTeleportRequestViaLocationLookAt::canRestartTeleport()
 void LLTeleportRequestViaLocationLookAt::startTeleport()
 {
     LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt::startTeleport" << LL_ENDL;
-    gAgent.doTeleportViaLocationLookAt(getPosGlobal());
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	gAgent.doTeleportViaLocationLookAt(getPosGlobal(), getLookAt());
+// [/RLVa:KB]
+//    gAgent.doTeleportViaLocationLookAt(getPosGlobal());
 }
 
 void LLTeleportRequestViaLocationLookAt::restartTeleport()
 {
     LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt::restartTeleport" << LL_ENDL;
-    gAgent.doTeleportViaLocationLookAt(getPosGlobal());
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	gAgent.doTeleportViaLocationLookAt(getPosGlobal(), getLookAt());
+// [/RLVa:KB]
+//    gAgent.doTeleportViaLocationLookAt(getPosGlobal());
 }
 
 // EOF
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 3a533c2cba7564b981020476845af74eaab26ebd..981dda6c7a967ff92158d65fec8e6426f8b0d080 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -408,19 +408,31 @@ class LLAgent : public LLOldEvents::LLObservable
 		DOUBLETAP_SLIDERIGHT
 	};
 
-	void			setAlwaysRun() 			{ mbAlwaysRun = true; }
-	void			clearAlwaysRun() 		{ mbAlwaysRun = false; }
-	void			setRunning() 			{ mbRunning = true; }
-	void			clearRunning() 			{ mbRunning = false; }
-	void 			sendWalkRun(bool running);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+	void			setAlwaysRun();
+	void			setTempRun();
+	void			clearAlwaysRun();
+	void			clearTempRun();
+	void 			sendWalkRun();
+	bool			getTempRun()			{ return mbTempRun; }
+	bool			getRunning() const 		{ return (mbAlwaysRun) || (mbTempRun); }
+// [/RLVa:KB]
+//	void			setAlwaysRun() 			{ mbAlwaysRun = true; }
+//	void			clearAlwaysRun() 		{ mbAlwaysRun = false; }
+//	void			setRunning() 			{ mbRunning = true; }
+//	void			clearRunning() 			{ mbRunning = false; }
+//	void 			sendWalkRun(bool running);
 	bool			getAlwaysRun() const 	{ return mbAlwaysRun; }
-	bool			getRunning() const 		{ return mbRunning; }
+//	bool			getRunning() const 		{ return mbRunning; }
 public:
 	LLFrameTimer 	mDoubleTapRunTimer;
 	EDoubleTapRunMode mDoubleTapRunMode;
 private:
 	bool 			mbAlwaysRun; 			// Should the avatar run by default rather than walk?
-	bool 			mbRunning;				// Is the avatar trying to run right now?
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+	bool 			mbTempRun;
+// [/RLVa:KB]
+//	bool 			mbRunning;				// Is the avatar trying to run right now?
 	bool			mbTeleportKeepsLookAt;	// Try to keep look-at after teleport is complete
 
 	//--------------------------------------------------------------------
@@ -628,7 +640,10 @@ class LLAgent : public LLOldEvents::LLObservable
 	void 			teleportHome()	{ teleportViaLandmark(LLUUID::null); }	// Go home
 	void 			teleportViaLure(const LLUUID& lure_id, BOOL godlike);	// To an invited location
 	void 			teleportViaLocation(const LLVector3d& pos_global);		// To a global location - this will probably need to be deprecated
-	void			teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	void			teleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at = LLVector3::zero);// To a global location, preserving camera rotation
+// [/RLVa:KB]
+//	void			teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation
 	void 			teleportCancel();										// May or may not be allowed by server
     void            restoreCanceledTeleportRequest();
 	bool			getTeleportKeepsLookAt() { return mbTeleportKeepsLookAt; } // Whether look-at reset after teleport
@@ -665,13 +680,19 @@ class LLAgent : public LLOldEvents::LLObservable
 	bool            hasPendingTeleportRequest();
 	void            startTeleportRequest();
 
-	void 			teleportRequest(const U64& region_handle,
-									const LLVector3& pos_local,				// Go to a named location home
-									bool look_at_from_camera = false);
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	void 			teleportRequest(const U64& region_handle, const LLVector3& pos_local, const LLVector3& look_at = LLVector3(0, 1, 0));
+// [/RLVa:KB]
+//	void 			teleportRequest(const U64& region_handle,
+//									const LLVector3& pos_local,				// Go to a named location home
+//									bool look_at_from_camera = false);
 	void 			doTeleportViaLandmark(const LLUUID& landmark_id);			// Teleport to a landmark
 	void 			doTeleportViaLure(const LLUUID& lure_id, BOOL godlike);	// To an invited location
 	void 			doTeleportViaLocation(const LLVector3d& pos_global);		// To a global location - this will probably need to be deprecated
-	void			doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	void			doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at);// To a global location, preserving camera rotation
+// [/RLVa:KB]
+//	void			doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation
 
 	void            handleTeleportFinished();
 	void            handleTeleportFailed();
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index fa16f02c16cc154e0c0214871b9b1bda4c204dad..0d6a6073163e37c8019cac585939d15847ac6836 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -50,6 +50,10 @@
 #include "llvoavatarself.h"
 #include "llwindow.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-05-10 (RLVa-1.2.0g)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 using namespace LLAvatarAppearanceDefines;
 
@@ -208,10 +212,18 @@ void LLAgentCamera::init()
 	mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView");
 	mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView");
 	mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView");
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW] = gSavedSettings.declareVec3("CameraOffsetRLVaView", LLVector3(mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW]->getDefault()), "Declared in code", LLControlVariable::PERSIST_NO);
+	mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->setHiddenFromSettingsEditor(true);
+// [/RLVa:KB]
 
 	mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView");
 	mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView");
 	mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView");
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW] = gSavedSettings.declareVec3("FocusOffsetRLVaView", LLVector3(mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW]->getDefault()), "Declared in code", LLControlVariable::PERSIST_NO);
+	mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->setHiddenFromSettingsEditor(true);
+// [/RLVa:KB]
 
 	mCameraCollidePlane.clearVec();
 	mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
@@ -809,7 +821,13 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction)
 
 		LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
 		camera_offset_dir.normalize();
-		mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
+// [RLVa:KB] - Checked: 2.0.0
+		const LLVector3d focus_offset_target = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
+		if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(focus_offset_target)) )
+			return;
+		mCameraFocusOffsetTarget = focus_offset_target;
+// [/RLVa:KB]
+//		mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
 	}
 	startCameraAnimation();
 }
@@ -934,6 +952,11 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction)
 		new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
 	}
 
+// [RLVa:KB] - Checked: 2.0.0
+	if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) )
+		return;
+// [/RLVa:KB]
+
 	mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
 }
 
@@ -997,6 +1020,11 @@ void LLAgentCamera::cameraOrbitIn(const F32 meters)
 			new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
 		}
 
+// [RLVa:KB] - Checked: 2.0.0
+		if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) )
+			return;
+// [/RLVa:KB]
+
 		// Compute new camera offset
 		mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
 		cameraZoomIn(1.f);
@@ -1141,6 +1169,14 @@ void LLAgentCamera::updateCamera()
 	mCameraUpVector = LLVector3::z_axis;
 	//LLVector3	camera_skyward(0.f, 0.f, 1.f);
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	// Set focus back on our avie if something changed it
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK)) && (cameraThirdPerson()) && (!getFocusOnAvatar()) )
+	{
+		setFocusOnAvatar(TRUE, FALSE);
+	}
+// [/RLVa:KB]
+
 	U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
 
 	validateFocusObject();
@@ -1911,6 +1947,44 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 //			}
 	}
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	if ( (CAMERA_MODE_THIRD_PERSON == mCameraMode) && (RlvActions::isRlvEnabled()) && (RlvActions::isCameraDistanceClamped()) )
+	{
+		m_fRlvMinDist = m_fRlvMaxDist = false;
+
+		// Av-locked | Focus-locked | Result
+		// ===================================================
+		//     T     |      T       | skip focus => slam av
+		//     T     |      F       | skip focus => slam av
+		//     F     |      T       | skip av    => slam focus
+		//     F     |      F       | clamp focus then av
+		bool fCamAvDistClamped, fCamAvDistLocked = false; float nCamAvDistLimitMin, nCamAvDistLimitMax;
+		if (fCamAvDistClamped = RlvActions::getCameraAvatarDistanceLimits(nCamAvDistLimitMin, nCamAvDistLimitMax))
+			fCamAvDistLocked = nCamAvDistLimitMin == nCamAvDistLimitMax;
+		bool fCamOriginDistClamped, fCamOriginDistLocked = false; float nCamOriginDistLimitMin, nCamOriginDistLimitMax;
+		if (fCamOriginDistClamped = RlvActions::getCameraOriginDistanceLimits(nCamOriginDistLimitMin, nCamOriginDistLimitMax))
+			fCamOriginDistLocked = nCamOriginDistLimitMin == nCamOriginDistLimitMax;
+
+		// Check focus distance limits
+		if ( (fCamOriginDistClamped) && (!fCamAvDistLocked) )
+		{
+			const LLVector3 offsetCameraLocal = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale");
+			const LLVector3d offsetCamera(gAgent.getFrameAgent().rotateToAbsolute(offsetCameraLocal));
+			const LLVector3d posFocusCam = frame_center_global + head_offset + offsetCamera;
+			if (clampCameraPosition(camera_position_global, posFocusCam, nCamOriginDistLimitMin, nCamOriginDistLimitMax))
+				isConstrained = TRUE;
+		}
+
+		// Check avatar distance limits
+		if ( (fCamAvDistClamped) && (fCamAvDistLocked || !fCamOriginDistClamped) )
+		{
+			const LLVector3d posAvatarCam = gAgent.getPosGlobalFromAgent( (isAgentAvatarValid()) ? gAgentAvatarp->mHeadp->getWorldPosition() : gAgent.getPositionAgent() );
+			if (clampCameraPosition(camera_position_global, posAvatarCam, nCamAvDistLimitMin, nCamAvDistLimitMax))
+				isConstrained = TRUE;
+		}
+	}
+// [/RLVa:KB]
+
 	// Don't let camera go underground
 	F32 camera_min_off_ground = getCameraMinOffGround();
 
@@ -1931,6 +2005,49 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 	return camera_position_global;
 }
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+bool LLAgentCamera::allowFocusOffsetChange(const LLVector3d& offsetFocus)
+{
+	if (RlvActions::isCameraDistanceClamped())
+	{
+		if ( (CAMERA_MODE_THIRD_PERSON == getCameraMode()) && ((m_fRlvMinDist) || (m_fRlvMaxDist)) )
+		{
+			const LLVector3d posFocusGlobal = calcFocusPositionTargetGlobal();
+			// Don't allow moving the focus offset if at minimum and moving closer (or if at maximum and moving further) to prevent camera warping
+			F32 nCurDist = llabs((posFocusGlobal + mCameraFocusOffsetTarget - m_posRlvRefGlobal).magVec());
+			F32 nNewDist = llabs((posFocusGlobal + offsetFocus - m_posRlvRefGlobal).magVec());
+			if ( ((m_fRlvMaxDist) && (nNewDist > nCurDist)) || ((m_fRlvMinDist) && (nNewDist < nCurDist)) )
+				return false;
+		}
+	}
+	return true;
+}
+
+bool LLAgentCamera::clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax)
+{
+	const LLVector3d offsetCamera = posCamGlobal - posCamRefGlobal;
+
+	F32 nCamAvDist = llabs(offsetCamera.magVec()), nDistMult = NAN;
+	if (nCamAvDist > nDistMax)
+	{
+		nDistMult = nDistMax / nCamAvDist;
+		m_fRlvMaxDist = true;
+	}
+	else if (nCamAvDist < nDistMin)
+	{
+		nDistMult = nDistMin / nCamAvDist;
+		m_fRlvMinDist = true;
+	}
+
+	if (!isnan(nDistMult))
+	{
+		posCamGlobal = posCamRefGlobal + nDistMult * offsetCamera;
+		m_posRlvRefGlobal = posCamRefGlobal;
+		return true;
+	}
+	return false;
+}
+// [/RLVa:KB]
 
 LLVector3 LLAgentCamera::getCameraOffsetInitial()
 {
@@ -2033,6 +2150,10 @@ void LLAgentCamera::resetCamera()
 void LLAgentCamera::changeCameraToMouselook(BOOL animate)
 {
 	if (!gSavedSettings.getBOOL("EnableMouselook") 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		|| ( (RlvActions::isRlvEnabled()) && (!RlvActions::canChangeToMouselook()) )
+// [/RLVa:KB]
+
 		|| LLViewerJoystick::getInstance()->getOverrideCamera())
 	{
 		return;
@@ -2058,8 +2179,8 @@ void LLAgentCamera::changeCameraToMouselook(BOOL animate)
 
 	//gViewerWindow->stopGrab();
 	LLSelectMgr::getInstance()->deselectAll();
-	gViewerWindow->hideCursor();
-	gViewerWindow->moveCursorToCenter();
+//	gViewerWindow->hideCursor();
+//	gViewerWindow->moveCursorToCenter();
 
 	if (mCameraMode != CAMERA_MODE_MOUSELOOK)
 	{
@@ -2253,6 +2374,13 @@ void LLAgentCamera::changeCameraToCustomizeAvatar()
 		return;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+	if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	gAgent.standUp(); // force stand up
 	gViewerWindow->getWindow()->resetBusyCount();
 
@@ -2314,6 +2442,26 @@ void LLAgentCamera::changeCameraToCustomizeAvatar()
 
 void LLAgentCamera::switchCameraPreset(ECameraPreset preset)
 {
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	if (RlvActions::isRlvEnabled())
+	{
+		// Don't allow changing away from the our view if an object is restricting it
+		if (RlvActions::isCameraPresetLocked())
+			preset = CAMERA_RLV_SETCAM_VIEW;
+
+		// Don't reset anything if our view is already current
+		if ( (CAMERA_RLV_SETCAM_VIEW == preset) && (CAMERA_RLV_SETCAM_VIEW == mCameraPreset) )
+			return;
+
+		// Reset our view when switching away
+		if (CAMERA_RLV_SETCAM_VIEW != preset)
+		{
+			mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->resetToDefault();
+			mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->resetToDefault();
+		}
+	}
+// [/RLVa:KB]
+
 	//zoom is supposed to be reset for the front and group views
 	mCameraZoomFraction = 1.f;
 
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index ab793ff316b2ea54eef884323d6b81506b66a07b..969a86ab558ae3c0e01cabf47d176ba65e90145b 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -56,7 +56,12 @@ enum ECameraPreset
 	CAMERA_PRESET_FRONT_VIEW, 
 
 	/** "Above and to the left, over the shoulder, pulled back a little on the zoom" */
-	CAMERA_PRESET_GROUP_VIEW
+	CAMERA_PRESET_GROUP_VIEW,
+
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	/* Used by RLVa */
+	CAMERA_RLV_SETCAM_VIEW
+// [/RLVa:KB]
 };
 
 //------------------------------------------------------------------------
@@ -300,6 +305,18 @@ class LLAgentCamera
 	F32				mHUDTargetZoom;	// Target zoom level for HUD objects (used when editing)
 	F32				mHUDCurZoom; 	// Current animated zoom level for HUD objects
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	//--------------------------------------------------------------------
+	// RLVa
+	//--------------------------------------------------------------------
+protected:
+	bool allowFocusOffsetChange(const LLVector3d& offsetFocus);
+	bool clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax);
+
+	bool m_fRlvMaxDist;				// True if the camera is at max distance
+	bool m_fRlvMinDist;				// True if the camera is at min distance
+	LLVector3d m_posRlvRefGlobal;		// Current reference point for distance calculations
+// [/RLVa:KB]
 
 /********************************************************************************
  **                                                                            **
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index 7887184a11b01ed3968a6c4f5298c1e7d0caf0bf..85bae5cd7592f6ecf22b81b039f588250fb28687 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -43,6 +43,11 @@
 #include "lltoolgrab.h"
 #include "llhudeffectlookat.h"
 #include "llagentcamera.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "llvoavatarself.h"
+// [/RLVa:KB]
 
 LLAgentListener::LLAgentListener(LLAgent &agent)
   : LLEventAPI("LLAgent",
@@ -179,8 +184,28 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
 		object = findObjectClosestTo(target_position);
 	}
 
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.1.0j
+	// TODO-RLVa: [RLVa-1.2.1] Figure out how to call this?
+	if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canSit(object)) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
     if (object && object->getPCode() == LL_PCODE_VOLUME)
     {
+// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) )
+		{
+			if (gAgentAvatarp->isSitting())
+			{
+				gAgent.standUp();
+				return;
+			}
+			gRlvHandler.setSitSource(gAgent.getPositionGlobal());
+		}
+// [/RLVa:KB]
+
         gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
         gMessageSystem->nextBlockFast(_PREHASH_AgentData);
         gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID());
@@ -200,6 +225,14 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
 
 void LLAgentListener::requestStand(LLSD const & event_data) const
 {
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	// TODO-RLVa: [RLVa-1.2.1] Figure out how to call this?
+	if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
     mAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
 }
 
diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp
index 3410a37890505052f86db52601015e878f6f469c..8258e77caa2387699a1eb8d16ec3f72fa5830a19 100644
--- a/indra/newview/llagentui.cpp
+++ b/indra/newview/llagentui.cpp
@@ -38,6 +38,9 @@
 #include "llviewerparcelmgr.h"
 #include "llvoavatarself.h"
 #include "llslurl.h"
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //static
 void LLAgentUI::buildFullname(std::string& name)
@@ -99,6 +102,18 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const
 	// create a default name and description for the landmark
 	std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName();
 	std::string region_name = region->getName();
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+	// RELEASE-RLVa: [SL-2.0.0] Check ELocationFormat to make sure our switch still makes sense
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		parcel_name = RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL);
+		region_name = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+		if (LOCATION_FORMAT_NO_MATURITY == fmt)
+			fmt = LOCATION_FORMAT_LANDMARK;
+		else if (LOCATION_FORMAT_FULL == fmt)
+			fmt = LOCATION_FORMAT_NO_COORDS;
+	}
+// [/RLVa:KB]
 	std::string sim_access_string = region->getSimAccessString();
 	std::string buffer;
 	if( parcel_name.empty() )
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 1c327b479e90a4b03562b9fb73dae62dccdfb1c0..7be674789dbddcfb2d49ff2fc106b46ef5d15eb8 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -51,6 +51,10 @@
 #include "llviewerwearable.h"
 #include "llwearablelist.h"
 #include "llfloaterperms.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 #include <boost/scoped_ptr.hpp>
 
@@ -60,6 +64,9 @@ BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
 // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1)
 bool LLAgentWearables::mInitialWearablesLoaded = false;
 // [/SL:KB]
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+bool LLAgentWearables::mInitialAttachmentsRequested = false;
+// [/RLVa:KB]
 
 using namespace LLAvatarAppearanceDefines;
 
@@ -659,6 +666,34 @@ const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32
 		return LLUUID();
 }
 
+// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0)
+void LLAgentWearables::getWearableItemIDs(uuid_vec_t& idItems) const
+{
+	for (wearableentry_map_t::const_iterator itWearableType = mWearableDatas.begin(); 
+			itWearableType != mWearableDatas.end(); ++itWearableType)
+	{
+		getWearableItemIDs(itWearableType->first, idItems);
+	}
+}
+
+void LLAgentWearables::getWearableItemIDs(LLWearableType::EType eType, uuid_vec_t& idItems) const
+{
+	wearableentry_map_t::const_iterator itWearableType = mWearableDatas.find(eType);
+	if (mWearableDatas.end() != itWearableType)
+	{
+		for (wearableentry_vec_t::const_iterator itWearable = itWearableType->second.begin();
+				itWearable != itWearableType->second.end(); ++itWearable)
+		{
+			const LLViewerWearable* pWearable = dynamic_cast<LLViewerWearable*>(*itWearable);
+			if (pWearable)
+			{
+				idItems.push_back(pWearable->getItemID());
+			}
+		}
+	}
+}
+// [/RLVa:KB]
+
 const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const
 {
 	const LLViewerWearable *wearable = getViewerWearable(type,index);
@@ -960,7 +995,11 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
 				old_wearable->removeFromAvatar();
 			}
 		}
-		clearWearableType(type);
+//		clearWearableType(type);
+// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0)
+		// The line above shouldn't be needed
+		RLV_VERIFY(0 == getWearableCount(type));
+// [/RLVa:KB]
 	}
 	else
 	{
@@ -1149,146 +1188,140 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
 
 
 // User has picked "wear on avatar" from a menu.
-void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
-{
-	//LLAgentDumper dumper("setWearableItem");
-	if (isWearingItem(new_item->getUUID()))
-	{
-		LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL;
-		return;
-	}
-	
-	const LLWearableType::EType type = new_wearable->getType();
-
-	if (!do_append)
-	{
-		// Remove old wearable, if any
-		// MULTI_WEARABLE: hardwired to 0
-		LLViewerWearable* old_wearable = getViewerWearable(type,0);
-		if (old_wearable)
-		{
-			const LLUUID& old_item_id = old_wearable->getItemID();
-			if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
-				(old_item_id == new_item->getUUID()))
-			{
-				LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL;
-				return;
-			}
-			
-			if (old_wearable->isDirty())
-			{
-				// Bring up modal dialog: Save changes? Yes, No, Cancel
-				LLSD payload;
-				payload["item_id"] = new_item->getUUID();
-				LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable));
-				return;
-			}
-		}
-	}
-
-	setWearableFinal(new_item, new_wearable, do_append);
-}
+//void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
+//{
+//	//LLAgentDumper dumper("setWearableItem");
+//	if (isWearingItem(new_item->getUUID()))
+//	{
+//		LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL;
+//		return;
+//	}
+//	
+//	const LLWearableType::EType type = new_wearable->getType();
+//
+//	if (!do_append)
+//	{
+//		// Remove old wearable, if any
+//		// MULTI_WEARABLE: hardwired to 0
+//		LLViewerWearable* old_wearable = getViewerWearable(type,0);
+//		if (old_wearable)
+//		{
+//			const LLUUID& old_item_id = old_wearable->getItemID();
+//			if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
+//				(old_item_id == new_item->getUUID()))
+//			{
+//				LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL;
+//				return;
+//			}
+//			
+//			if (old_wearable->isDirty())
+//			{
+//				// Bring up modal dialog: Save changes? Yes, No, Cancel
+//				LLSD payload;
+//				payload["item_id"] = new_item->getUUID();
+//				LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable));
+//				return;
+//			}
+//		}
+//	}
+//
+//	setWearableFinal(new_item, new_wearable, do_append);
+//}
 
 // static 
-bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable)
-{
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-	LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
-	U32 index;
-	if (!gAgentWearables.getWearableIndex(wearable,index))
-	{
-		LL_WARNS() << "Wearable not found" << LL_ENDL;
-		delete wearable;
-		return false;
-	}
-	if (!new_item)
-	{
-		delete wearable;
-		return false;
-	}
-
-	switch(option)
-	{
-		case 0:  // "Save"
-			gAgentWearables.saveWearable(wearable->getType(),index);
-			gAgentWearables.setWearableFinal(new_item, wearable);
-			break;
-
-		case 1:  // "Don't Save"
-			gAgentWearables.setWearableFinal(new_item, wearable);
-			break;
-
-		case 2: // "Cancel"
-			break;
-
-		default:
-			llassert(0);
-			break;
-	}
-
-	delete wearable;
-	return false;
-}
+//bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable)
+//{
+//	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+//	LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
+//	U32 index;
+//	if (!gAgentWearables.getWearableIndex(wearable,index))
+//	{
+//		LL_WARNS() << "Wearable not found" << LL_ENDL;
+//		delete wearable;
+//		return false;
+//	}
+//	switch(option)
+//	{
+//		case 0:  // "Save"
+//			gAgentWearables.saveWearable(wearable->getType(),index);
+//			gAgentWearables.setWearableFinal(new_item, wearable);
+//			break;
+//
+//		case 1:  // "Don't Save"
+//			gAgentWearables.setWearableFinal(new_item, wearable);
+//			break;
+//
+//		case 2: // "Cancel"
+//			break;
+//
+//		default:
+//			llassert(0);
+//			break;
+//	}
+//
+//	delete wearable;
+//	return false;
+//}
 
 // Called from setWearableItem() and onSetWearableDialog() to actually set the wearable.
 // MULTI_WEARABLE: unify code after null objects are gone.
-void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
-{
-	const LLWearableType::EType type = new_wearable->getType();
-
-	if (do_append && getWearableItemID(type,0).notNull())
-	{
-		new_wearable->setItemID(new_item->getUUID());
-		const bool trigger_updated = false;
-		pushWearable(type, new_wearable, trigger_updated);
-		LL_INFOS() << "Added additional wearable for type " << type
-				<< " size is now " << getWearableCount(type) << LL_ENDL;
-		checkWearableAgainstInventory(new_wearable);
-	}
-	else
-	{
-		// Replace the old wearable with a new one.
-		llassert(new_item->getAssetUUID() == new_wearable->getAssetID());
-
-		LLViewerWearable *old_wearable = getViewerWearable(type,0);
-		LLUUID old_item_id;
-		if (old_wearable)
-		{
-			old_item_id = old_wearable->getItemID();
-		}
-		new_wearable->setItemID(new_item->getUUID());
-		setWearable(type,0,new_wearable);
-
-		if (old_item_id.notNull())
-		{
-			gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
-			gInventory.notifyObservers();
-		}
-		LL_INFOS() << "Replaced current element 0 for type " << type
-				<< " size is now " << getWearableCount(type) << LL_ENDL;
-	}
-}
+//void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
+//{
+//	const LLWearableType::EType type = new_wearable->getType();
+//
+//	if (do_append && getWearableItemID(type,0).notNull())
+//	{
+//		new_wearable->setItemID(new_item->getUUID());
+//		const bool trigger_updated = false;
+//		pushWearable(type, new_wearable, trigger_updated);
+//		LL_INFOS() << "Added additional wearable for type " << type
+//				<< " size is now " << getWearableCount(type) << LL_ENDL;
+//		checkWearableAgainstInventory(new_wearable);
+//	}
+//	else
+//	{
+//		// Replace the old wearable with a new one.
+//		llassert(new_item->getAssetUUID() == new_wearable->getAssetID());
+//
+//		LLViewerWearable *old_wearable = getViewerWearable(type,0);
+//		LLUUID old_item_id;
+//		if (old_wearable)
+//		{
+//			old_item_id = old_wearable->getItemID();
+//		}
+//		new_wearable->setItemID(new_item->getUUID());
+//		setWearable(type,0,new_wearable);
+//
+//		if (old_item_id.notNull())
+//		{
+//			gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
+//			gInventory.notifyObservers();
+//		}
+//		LL_INFOS() << "Replaced current element 0 for type " << type
+//				<< " size is now " << getWearableCount(type) << LL_ENDL;
+//	}
+//}
 
 // User has picked "remove from avatar" from a menu.
 // static
-void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index)
-{
-	if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
-		//!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
-	{
-		gAgentWearables.removeWearable(type,false,index);
-	}
-}
+//void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index)
+//{
+//	if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
+//		//!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
+//	{
+//		gAgentWearables.removeWearable(type,false,index);
+//	}
+//}
 
 //static 
-void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type)
-{
-	if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
-		//!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
-	{
-		gAgentWearables.removeWearable(type,true,0);
-	}
-}
+//void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type)
+//{
+//	if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
+//		//!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
+//	{
+//		gAgentWearables.removeWearable(type,true,0);
+//	}
+//}
 
 // Given a desired set of attachments, find what objects need to be
 // removed, and what additional inventory items need to be added.
@@ -1378,6 +1411,34 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo
 {
 	if (!isAgentAvatarValid()) return;
 
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0)
+	// RELEASE-RLVa: [SL-3.4] Check our callers and verify that erasing elements from the passed vector won't break random things
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+	{
+		llvo_vec_t::iterator itObj = objects_to_remove.begin();
+		while (objects_to_remove.end() != itObj)
+		{
+			const LLViewerObject* pAttachObj = *itObj;
+			if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj))
+			{
+				itObj = objects_to_remove.erase(itObj);
+
+				// Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere)
+				bool fInCOF = LLAppearanceMgr::instance().isLinkedInCOF(pAttachObj->getAttachmentItemID());
+				RLV_ASSERT(fInCOF);
+				if (!fInCOF)
+				{
+					LLAppearanceMgr::instance().registerAttachment(pAttachObj->getAttachmentItemID());
+				}
+			}
+			else
+			{
+				++itObj;
+			}
+		}
+	}
+// [/RLVa:KB]
+
 	if (objects_to_remove.empty())
 		return;
 
@@ -1419,6 +1480,10 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
 		const LLInventoryItem* item = *it;
         LLAttachmentsMgr::instance().addAttachmentRequest(item->getLinkedUUID(), 0, TRUE);
     }
+
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+	mInitialAttachmentsRequested = true;
+// [/RLVa:KB]
 }
 
 // Returns false if the given wearable is already topmost/bottommost
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index d3bf760ba0eadfe7ce4ce8a061f854b302ae5a53..938208cef5e39edc1345054c448ac6080f390bec 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -74,6 +74,9 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1)
 	bool			areInitalWearablesLoaded() const { return mInitialWearablesLoaded; }
 // [/SL:KB]
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+	bool			areInitialAttachmentsRequested() const { return mInitialAttachmentsRequested;  }
+// [/RLVa:KB]
 	bool			isCOFChangeInProgress() const { return mCOFChangeInProgress; }
 	F32				getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); }
 	void			updateWearablesLoaded();
@@ -89,6 +92,10 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 	// Accessors
 	//--------------------------------------------------------------------
 public:
+// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0)
+	void				getWearableItemIDs(uuid_vec_t& idItems) const;
+	void				getWearableItemIDs(LLWearableType::EType eType, uuid_vec_t& idItems) const;
+// [/RLVa:KB]
 	const LLUUID		getWearableItemID(LLWearableType::EType type, U32 index /*= 0*/) const;
 	const LLUUID		getWearableAssetID(LLWearableType::EType type, U32 index /*= 0*/) const;
 	const LLViewerWearable*	getWearableFromItemID(const LLUUID& item_id) const;
@@ -105,15 +112,15 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 private:
 	/*virtual*/void	wearableUpdated(LLWearable *wearable, BOOL removed);
 public:
-	void			setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false);
+//	void			setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false);
 	void			setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables);
 	void			setWearableName(const LLUUID& item_id, const std::string& new_name);
 	// *TODO: Move this into llappearance/LLWearableData ?
 	void			addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index);
 
 protected:
-	void			setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false);
-	static bool		onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable);
+//	void			setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false);
+//	static bool		onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable);
 
 	void			addWearableToAgentInventory(LLPointer<LLInventoryCallback> cb,
 												LLViewerWearable* wearable, 
@@ -145,8 +152,11 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 	// Removing wearables
 	//--------------------------------------------------------------------
 public:
-	void			removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
+//	void			removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
 private:
+// [RLVa:KB] - Checked: 2010-05-11 (RLVa-1.2.0)
+	void			removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
+// [/RLVa:KB]
 	void			removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
 protected:
 	static bool		onRemoveWearableDialog(const LLSD& notification, const LLSD& response);
@@ -176,8 +186,8 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 	// Static UI hooks
 	//--------------------------------------------------------------------
 public:
-	static void		userRemoveWearable(const LLWearableType::EType &type, const U32 &index);
-	static void		userRemoveWearablesOfType(const LLWearableType::EType &type);
+//	static void		userRemoveWearable(const LLWearableType::EType &type, const U32 &index);
+//	static void		userRemoveWearablesOfType(const LLWearableType::EType &type);
 	
 	typedef std::vector<LLViewerObject*> llvo_vec_t;
 
@@ -222,6 +232,9 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.2)
 	static bool		mInitialWearablesLoaded;
 // [/SL:KB]
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+	static bool		mInitialAttachmentsRequested;
+// [/RLVa:KB]
 	BOOL			mWearablesLoaded;
 
 	/**
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index de8844f6d9b6281830846f9161c33ddd2d84212b..3db61d4ae073a7976ed93d2fadd8e1c1a73630c9 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -60,6 +60,12 @@
 #include "llappviewer.h"
 #include "llcoros.h"
 #include "lleventcoro.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 #include "llavatarpropertiesprocessor.h"
 
@@ -1316,6 +1322,25 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
 
 //=========================================================================
 
+// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2015-06-30 (Catznip-3.7)
+static void removeDuplicateWearableItemsByAssetID(LLInventoryModel::item_array_t& items)
+{
+	std::set<LLUUID> idsAsset;
+	items.erase(std::remove_if(items.begin(), items.end(), 
+		[&idsAsset](const LLViewerInventoryItem* pItem)
+		{
+			if (pItem->isWearableType())
+			{
+				const LLUUID& idAsset = pItem->getAssetUUID();
+				if ( (idAsset.notNull()) &&  (idsAsset.end() != idsAsset.find(idAsset)) )
+					return true;
+				idsAsset.insert(idAsset);
+			}
+			return false;
+		}), items.end());
+}
+// [/SL:KB]
+
 const LLUUID LLAppearanceMgr::getCOF() const
 {
 	return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
@@ -1473,6 +1498,13 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
             continue;
         }
 
+// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
+		if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item_to_wear, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) )
+		{
+			continue;
+		}
+// [/RLVa:KB]
+
         switch (item_to_wear->getType())
         {
             case LLAssetType::AT_CLOTHING:
@@ -1490,9 +1522,9 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
                         LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
                                                                            wearable_count-1);
 // [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7)
-			removeCOFItemLinks(item_id, NULL, true);
+						removeCOFItemLinks(item_id, NULL, true);
 // [/SL:KB]
-//			removeCOFItemLinks(item_id, cb);
+//						removeCOFItemLinks(item_id, cb);
                     }
                     
                     items_to_link.push_back(item_to_wear);
@@ -1868,6 +1900,13 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)
 	{
 		return false;
 	}
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_REMOVE)) )
+	{
+		return false;
+	}
+// [/RLVa:KB]
+
 	LLInventoryModel::cat_array_t cats;
 	LLInventoryModel::item_array_t items;
 	LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false);
@@ -1887,6 +1926,13 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)
 		return false;
 	}
 
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_ADD)) )
+	{
+		return false;
+	}
+// [/RLVa:KB]
+
 	LLInventoryModel::cat_array_t cats;
 	LLInventoryModel::item_array_t items;
 	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
@@ -1907,6 +1953,14 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
 		return false;
 	}
 
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	// Block "Replace Current Outfit" if the user can't wear the new folder
+	if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_ADD)) )
+	{
+		return false;
+	}
+// [/RLVa:KB]
+
 	// Check whether it's the base outfit.
 //	if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID())
 // [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-21 (Catznip-2.1)
@@ -2036,6 +2090,8 @@ void LLAppearanceMgr::filterWearableItems(
     }
 }
 
+//void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0)
 void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 {
 	LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
@@ -2046,6 +2102,32 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	}
 	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;
 
+	LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new;
+	getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART);
+	getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING);
+	getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT);
+	getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE);
+	updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category);
+}
+
+void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, 
+								LLInventoryModel::item_array_t& wear_items_new, 
+								LLInventoryModel::item_array_t& obj_items_new,
+								LLInventoryModel::item_array_t& gest_items_new,
+								bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/, LLPointer<LLInventoryCallback> link_waiter /*= NULL*/)
+// [/RLVa:KB]
+{
+//	LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
+//	if (!pcat)
+//	{
+//		LL_WARNS() << "no category found for id " << category << LL_ENDL;
+//		return;
+//	}
+//	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;
+// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0)
+	LL_INFOS("Avatar") << "starting" << LL_ENDL;
+// [/RLVa:KB]
+
 	const LLUUID cof = getCOF();
 
 	// Deactivate currently active gestures in the COF, if replacing outfit
@@ -2065,39 +2147,87 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	
 	// Collect and filter descendents to determine new COF contents.
 
-	// - Body parts: always include COF contents as a fallback in case any
-	// required parts are missing.
+	//
+	// - Body parts: always include COF contents as a fallback in case any required parts are missing.
+	//
 	// Preserve body parts from COF if appending.
 	LLInventoryModel::item_array_t body_items;
 	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART);
-	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART);
-	if (append)
-		reverse(body_items.begin(), body_items.end());
+//	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART);
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	// Filter out any new body parts that can't be worn before adding them
+	if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) )
+		body_items_new.erase(std::remove_if(body_items_new.begin(), body_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR_REPLACE)), body_items_new.end());
+	body_items.insert(body_items.end(), body_items_new.begin(), body_items_new.end());
+// [/RLVa:KB]
+	// NOTE-RLVa: we don't actually want to favour COF body parts over the folder's body parts (if only because it breaks force wear)
+//	if (append)
+//		reverse(body_items.begin(), body_items.end());
 	// Reduce body items to max of one per type.
 	removeDuplicateItems(body_items);
 	filterWearableItems(body_items, 1, 0);
 
+	//
 	// - Wearables: include COF contents only if appending.
+	//
 	LLInventoryModel::item_array_t wear_items;
 	if (append)
 		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING);
-	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING);
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	else if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_REMOVE))) )
+	{
+		// Make sure that all currently locked clothing layers remain in COF when replacing
+		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING);
+		wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), RlvPredCanRemoveItem()), wear_items.end());
+	}
+// [/RLVa:KB]
+//	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING);
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	// Filter out any new wearables that can't be worn before adding them
+	if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) )
+		wear_items_new.erase(std::remove_if(wear_items_new.begin(), wear_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), wear_items_new.end());
+	wear_items.insert(wear_items.end(), wear_items_new.begin(), wear_items_new.end());
+// [/RLVa:KB]
 	// Reduce wearables to max of one per type.
 	removeDuplicateItems(wear_items);
+// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e
+	removeDuplicateWearableItemsByAssetID(wear_items);
+// [/SL:KB]
 	filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS);
 
+	//
 	// - Attachments: include COF contents only if appending.
+	//
 	LLInventoryModel::item_array_t obj_items;
 	if (append)
 		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
-	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT);
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	else if ( (RlvActions::isRlvEnabled()) && ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_REMOVE))) )
+	{
+		// Make sure that all currently locked attachments remain in COF when replacing
+		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
+		obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), RlvPredCanRemoveItem()), obj_items.end());
+	}
+// [/RLVa:KB]
+//	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT);
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	// Filter out any new attachments that can't be worn before adding them
+	if ( (RlvActions::isRlvEnabled()) && ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) )
+		obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), obj_items_new.end());
+	obj_items.insert(obj_items.end(), obj_items_new.begin(), obj_items_new.end());
+// [/RLVa:KB]
 	removeDuplicateItems(obj_items);
 
+	//
 	// - Gestures: include COF contents only if appending.
+	//
 	LLInventoryModel::item_array_t gest_items;
 	if (append)
 		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE);
-	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE);
+//	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE);
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0)
+	gest_items.insert(gest_items.end(), gest_items_new.begin(), gest_items_new.end());
+// [/RLVa:KB]
 	removeDuplicateItems(gest_items);
 	
 	// Create links to new COF contents.
@@ -2113,7 +2243,11 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 
 	// Will link all the above items.
 	// link_waiter enforce flags are false because we've already fixed everything up in updateCOF().
-	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false);
+//	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false);
+// [RLVa:KB] Checked: 2015-05-05 (RLVa-1.4.12)
+	if (!link_waiter)
+		link_waiter = new LLUpdateAppearanceOnDestroy(false, false);
+// [/RLVa:KB]
 	LLSD contents = LLSD::emptyArray();
 
 	for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin();
@@ -2141,8 +2275,12 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 		item_contents["type"] = LLAssetType::AT_LINK; 
 		contents.append(item_contents);
 	}
-	const LLUUID& base_id = append ? getBaseOutfitUUID() : category;
-	LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id);
+//	const LLUUID& base_id = append ? getBaseOutfitUUID() : category;
+//	LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id);
+// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11)
+	const LLUUID& base_id = (append) ? getBaseOutfitUUID() : idOutfit;
+	LLViewerInventoryCategory* base_cat = (base_id.notNull()) ? gInventory.getCategory(base_id) : NULL;
+// [/RLVa:KB]
 	if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT))
 	{
 		LLSD base_contents;
@@ -2194,6 +2332,14 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder)
 	LLInventoryItem::item_array_t items;
 	std::vector< LLViewerWearable* > wearables;
 	wearables.reserve(32);
+// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0)
+	uuid_vec_t idsCurrent; LLInventoryModel::item_array_t itemsNew;
+	if (rlv_handler_t::isEnabled())
+	{
+		// Collect the item UUIDs of all currently worn wearables
+		gAgentWearables.getWearableItemIDs(idsCurrent);
+	}
+// [/RLVa:KB]
 
 	// For each wearable type, find the wearables of that type.
 	for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ )
@@ -2208,13 +2354,60 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder)
 				LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
 				if( item && (item->getAssetUUID() == wearable->getAssetID()) )
 				{
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0)
+					// TODO-RLVa: [RLVa-1.2.1] This is fall-back code so if we don't ever trigger this code it can just be removed
+					//   -> one way to trigger the assertion:
+					//			1) "Replace Outfit" on a folder with clothing and an attachment that goes @addoutfit=n
+					//			2) updateCOF will add/link the items into COF => no @addoutfit=n present yet => allowed
+					//			3) llOwnerSay("@addoutfit=n") executes
+					//			4) code below runs => @addoutfit=n conflicts with adding new wearables
+					//     => if it's left as-is then the wearables won't get worn (but remain in COF which causes issues of its own)
+					//     => if it's changed to debug-only then we make tge assumption that anything that makes it into COF is always OK
+#ifdef RLV_DEBUG
+					// NOTE: make sure we don't accidentally block setting the initial wearables
+					if ( (rlv_handler_t::isEnabled()) && (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType())) &&
+						 (!gAgentWearables.getWearableFromItemID(item->getUUID())) && (gAgentWearables.areWearablesLoaded()) )
+					{
+						RLV_VERIFY(RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType()));
+						continue;
+					}
+#endif // RLV_DEBUG
+// [/RLVa:KB]
 					items.push_back(item);
 					wearables.push_back(wearable);
+// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0)
+					if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) )
+					{
+						// Remove the wearable from current item UUIDs if currently worn and requested, otherwise mark it as a new item
+						uuid_vec_t::iterator itItemID = std::find(idsCurrent.begin(), idsCurrent.end(), item->getUUID());
+						if (idsCurrent.end() != itItemID)
+							idsCurrent.erase(itItemID);
+						else
+							itemsNew.push_back(item);
+					}
+// [/RLVa:KB]
 				}
 			}
 		}
 	}
 
+// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0)
+	if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) )
+	{
+		// We need to report removals before additions or scripts will get confused
+		for (uuid_vec_t::const_iterator itItemID = idsCurrent.begin(); itItemID != idsCurrent.end(); ++itItemID)
+		{
+			const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(*itItemID);
+			if (pWearable)
+				RlvBehaviourNotifyHandler::onTakeOff(pWearable->getType(), true);
+		}
+		for (S32 idxItem = 0, cntItem = itemsNew.size(); idxItem < cntItem; idxItem++)
+		{
+			RlvBehaviourNotifyHandler::onWear(itemsNew.at(idxItem)->getWearableType(), true);
+		}
+	}
+// [/RLVa:KB]
+
 	if(wearables.size() > 0)
 	{
 		gAgentWearables.setWearableOutfit(items, wearables);
@@ -2403,6 +2596,10 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
 	removeDuplicateItems(gest_items);
 	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_LAYERS, LLAgentWearables::MAX_CLOTHING_LAYERS);
 // [/SL:KB]
+// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e
+	// Wearing two wearables that share the same asset causes some issues
+	removeDuplicateWearableItemsByAssetID(wear_items);
+// [/SL:KB]
 
 	dumpItemArray(wear_items,"asset_dump: wear_item");
 	dumpItemArray(obj_items,"asset_dump: obj_item");
@@ -2504,6 +2701,9 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
 		// fetch failures (should be replaced by new defaults in
 		// lost&found).
 		U32 skip_type = gSavedSettings.getU32("ForceAssetFail");
+// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2)
+		U32 missing_type = gSavedSettings.getU32("ForceMissingType");
+// [/RLVa:KB]
 
 		if (item && item->getIsLinkType() && linked_item)
 		{
@@ -2514,10 +2714,25 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
 							  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID
 				);
 
-			if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType)
+// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2)
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+			// Don't allow forcing an invalid wearable if the initial wearables aren't set yet, or if any wearable type is currently locked
+			if ( (!rlv_handler_t::isEnabled()) || 
+				 ((gAgentWearables.areInitalWearablesLoaded()) && (!gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_REMOVE))) )
+#endif // LL_RELEASE_FOR_DOWNLOAD
 			{
-				found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB
+				if (missing_type != LLWearableType::WT_INVALID && missing_type == found.mWearableType)
+				{
+					continue;
+				}
+// [/RLVa:KB]
+				if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType)
+				{
+					found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB
+				}
+// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2)
 			}
+// [/RLVa:KB]
 			//pushing back, not front, to preserve order of wearables for LLAgentWearables
 			holder->getFoundList().push_back(found);
 		}
@@ -2897,6 +3112,13 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
 				// MULTI-WEARABLES: make sure we don't go over clothing limits
 				remove_inventory_item(inv_item->getUUID(), cb);
 			}
+// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e
+			else if ( (vitem->getWearableType() == wearable_type) && (vitem->getAssetUUID() == inv_item->getAssetUUID()) )
+			{
+				// Only allow one wearable per unique asset
+				linked_already = true;
+			}
+// [/SL:KB]
 		}
 	}
 
@@ -3006,9 +3228,15 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInve
 								  LLInventoryModel::EXCLUDE_TRASH);
 	for (S32 i=0; i<item_array.size(); i++)
 	{
-		const LLInventoryItem* item = item_array.at(i).get();
+		const LLViewerInventoryItem* item = item_array.at(i).get();
 		if (item->getIsLinkType() && item->getLinkedUUID() == item_id)
 		{
+// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
+			if (rlv_handler_t::isEnabled())
+			{
+				RLV_ASSERT(rlvPredCanRemoveItem(item));
+			}
+// [/RLVa:KB]
 //			bool immediate_delete = false;
 //			if (item->getType() == LLAssetType::AT_OBJECT)
 //			{
@@ -3032,6 +3260,12 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer
 		const LLViewerInventoryItem* item = *it;
 		if (item->getIsLinkType()) // we must operate on links only
 		{
+// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
+			if (rlv_handler_t::isEnabled())
+			{
+				RLV_ASSERT(rlvPredCanRemoveItem(item));
+			}
+// [/RLVa:KB]
 			remove_inventory_item(item->getUUID(), cb);
 		}
 	}
@@ -3896,17 +4130,18 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLP
 		LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL;
 		return;
 	}
-//	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
-// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7)
-	if (!cb)
-	{
-		cb = new LLUpdateAppearanceOnDestroy;
-	}
-// [/SL:KB]
+// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
+//	LLPointer<LLInventoryCallback> cb = NULL;
 	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
 	{
 		const LLUUID& id_to_remove = *it;
 		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
+
+		if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(linked_item_id)) )
+		{
+			continue;
+		}
+
 		LLViewerInventoryItem *item = gInventory.getItem(linked_item_id);
 		if (item && item->getType() == LLAssetType::AT_OBJECT)
 		{
@@ -3916,15 +4151,33 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLP
 		{
 		    continue;
 		}
-// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7)
+
+		if (!cb)
+			cb = new LLUpdateAppearanceOnDestroy();
 		removeCOFItemLinks(linked_item_id, cb, immediate_delete);
-// [/SL:KB]
-//		removeCOFItemLinks(linked_item_id, cb);
 // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-03-01 (Catznip-3.7)
 		LLAttachmentsMgr::instance().clearPendingAttachmentLink(linked_item_id);
 // [/SL:KB]
 		addDoomedTempAttachment(linked_item_id);
 	}
+// [/RLVa:KB]
+////	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
+//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7)
+//	if (!cb)
+//	{
+//		cb = new LLUpdateAppearanceOnDestroy;
+//	}
+//// [/SL:KB]
+//	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
+//	{
+//		const LLUUID& id_to_remove = *it;
+//		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
+//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7)
+//		removeCOFItemLinks(linked_item_id, cb, immediate_delete);
+//// [/SL:KB]
+////		removeCOFItemLinks(linked_item_id, cb);
+//		addDoomedTempAttachment(linked_item_id);
+//	}
 }
 
 //void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index e864b953b66d49e01c8d5e7b5fd7e6ed79ee596a..8abfcf97e0754498f9f3b00437ccc1b16ceefe13 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -54,6 +54,11 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 								 bool enforce_ordering = true,
 								 nullary_func_t post_update_func = no_op);
 	void updateCOF(const LLUUID& category, bool append = false);
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	void updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new,
+				   LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new,
+				   bool append = false, const LLUUID& idOutfit = LLUUID::null, LLPointer<LLInventoryCallback> link_waiter = NULL);
+// [/RLVa:KB]
 	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
 	void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
 	void wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append);
@@ -273,6 +278,7 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 
 	static void onOutfitRename(const LLSD& notification, const LLSD& response);
 
+
 	bool mAttachmentInvLinkEnabled;
 	bool mOutfitIsDirty;
 	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls.
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 35734384eb2d1e5cc7ea7ea161cca30f349cc1ae..490c56d983b97b34e56ddefa4d1dbb7c1046c30e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -95,6 +95,11 @@
 // [SL:KB] - Patch: Appearance-Misc | Checked: 2013-02-12 (Catznip-3.4)
 #include "llappearancemgr.h"
 // [/SL:KB]
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 #include "llweb.h"
 #include "llupdaterservice.h"
 #include "llfloatertexturefetchdebugger.h"
@@ -485,7 +490,11 @@ void idle_afk_check()
 {
 	// check idle timers
 	F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32();
-	F32 afk_timeout  = gSavedSettings.getS32("AFKTimeout");
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+	// Enforce an idle time of 30 minutes if @allowidle=n restricted
+	F32 afk_timeout = (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) ? gSavedSettings.getS32("AFKTimeout") : 60 * 30;
+// [/RLVa:KB]
+//	F32 afk_timeout  = gSavedSettings.getS32("AFKTimeout");
 	if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK())
 	{
 		LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
@@ -3305,16 +3314,28 @@ LLSD LLAppViewer::getViewerInfo() const
 	LLViewerRegion* region = gAgent.getRegion();
 	if (region)
 	{
-		LLVector3d pos = gAgent.getPositionGlobal();
-		info["POSITION"] = ll_sd_from_vector3d(pos);
-		info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos));
-		info["REGION"] = gAgent.getRegion()->getName();
-		info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName();
-		info["HOSTIP"] = gAgent.getRegion()->getHost().getString();
+// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10)
+		if (RlvActions::canShowLocation())
+		{
+// [/RLVa:KB]
+			LLVector3d pos = gAgent.getPositionGlobal();
+			info["POSITION"] = ll_sd_from_vector3d(pos);
+			info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos));
+			info["REGION"] = gAgent.getRegion()->getName();
+			info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName();
+			info["HOSTIP"] = gAgent.getRegion()->getHost().getString();
+//			info["SERVER_VERSION"] = gLastVersionChannel;
+			LLSLURL slurl;
+			LLAgentUI::buildSLURL(slurl);
+			info["SLURL"] = slurl.getSLURLString();
+// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10)
+		}
+		else
+		{
+			info["REGION"] = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+		}
 		info["SERVER_VERSION"] = gLastVersionChannel;
-		LLSLURL slurl;
-		LLAgentUI::buildSLURL(slurl);
-		info["SLURL"] = slurl.getSLURLString();
+// [/RLVa:KB]
 	}
 
 	// CPU
@@ -3333,6 +3354,9 @@ LLSD LLAppViewer::getViewerInfo() const
 	}
 #endif
 
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0)
+	info["RLV_VERSION"] = (rlv_handler_t::isEnabled()) ? RlvStrings::getVersionAbout() : "(disabled)";
+// [/RLVa:KB]
 	info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
 
 	info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
@@ -3433,7 +3457,10 @@ std::string LLAppViewer::getViewerInfoString() const
 	}
 	if (info.has("REGION"))
 	{
-		support << "\n\n" << LLTrans::getString("AboutPosition", args);
+// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10)
+		support << "\n\n" << LLTrans::getString( (RlvActions::canShowLocation()) ? "AboutPosition" : "AboutPositionRLVShowLoc", args);
+// [/RLVa:KB]
+//		support << "\n\n" << LLTrans::getString("AboutPosition", args);
 	}
 	support << "\n\n" << LLTrans::getString("AboutSystem", args);
 	support << "\n";
diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp
index 7ed04b7f170abbb2c6962d6cbbe3ad38d84b66f7..3f16b1501531bd5cb5528d9bee41d2f341983a0d 100644
--- a/indra/newview/llattachmentsmgr.cpp
+++ b/indra/newview/llattachmentsmgr.cpp
@@ -35,6 +35,10 @@
 #include "llviewerinventory.h"
 #include "llviewerregion.h"
 #include "message.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 const F32 COF_LINK_BATCH_TIME = 5.0F;
 const F32 MAX_ATTACHMENT_REQUEST_LIFETIME = 30.0F;
@@ -72,9 +76,14 @@ LLAttachmentsMgr::~LLAttachmentsMgr()
 {
 }
 
+//void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id,
+//                                            const U8 attachment_pt,
+//                                            const BOOL add)
+// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1)
 void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id,
                                             const U8 attachment_pt,
-                                            const BOOL add)
+                                            const BOOL add, const BOOL fRlvForce /*=FALSE*/)
+// [/RLVa:KB]
 {
 	LLViewerInventoryItem *item = gInventory.getItem(item_id);
 
@@ -92,6 +101,26 @@ void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id,
 	attachment.mItemID = item_id;
 	attachment.mAttachmentPt = attachment_pt;
 	attachment.mAdd = add;
+
+// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1)
+	if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) && (gAgentWearables.areInitialAttachmentsRequested()) )
+	{
+		const LLInventoryItem* pItem = gInventory.getItem(item_id); 
+		if (!pItem)
+			return;
+
+		LLViewerJointAttachment* pAttachPt = NULL;
+		ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(pItem, &pAttachPt);
+		if ( ((add) && ((RLV_WEAR_ADD & eWearMask) == 0)) || ((!add) && ((RLV_WEAR_REPLACE & eWearMask) == 0)) )
+			return;
+
+		if ( (0 == attachment_pt) && (NULL != pAttachPt) )
+			attachment.mAttachmentPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt);
+		RlvAttachmentLockWatchdog::instance().onWearAttachment(pItem, (add) ? RLV_WEAR_ADD : RLV_WEAR_REPLACE);
+		attachment.mAdd = true;
+	}
+// [/RLVa:KB]
+
 	mPendingAttachments.push_back(attachment);
 
     mAttachmentRequests.addTime(item_id);
diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h
index 3221ae25800546b616bf6cd28f024248826eca59..4aee6614755508c6e425fceef88d77931eab4b21 100644
--- a/indra/newview/llattachmentsmgr.h
+++ b/indra/newview/llattachmentsmgr.h
@@ -75,9 +75,14 @@ class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr>
 	LLAttachmentsMgr();
 	virtual ~LLAttachmentsMgr();
 
+// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1)
 	void addAttachmentRequest(const LLUUID& item_id,
                               const U8 attachment_pt,
-                              const BOOL add);
+                              const BOOL add, const BOOL fRlvForce = FALSE);
+// [/RLVa:KB]
+//	void addAttachmentRequest(const LLUUID& item_id,
+//                              const U8 attachment_pt,
+//                              const BOOL add);
     void onAttachmentRequested(const LLUUID& item_id);
 	void requestAttachments(attachments_vec_t& attachment_requests);
 	static void onIdle(void *);
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index a6e745448a98c921cd4a1aa46238d01b18251426..a86a61a69c89c236fd5fcd601821034f5aaf5bea 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -74,6 +74,10 @@
 #include "llsidepanelinventory.h"
 #include "llavatarname.h"
 #include "llagentui.h"
+// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0)
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 // Flags for kick message
 const U32 KICK_FLAGS_DEFAULT	= 0x0;
@@ -203,6 +207,15 @@ void LLAvatarActions::startIM(const LLUUID& id)
 	if (id.isNull() || gAgent.getID() == id)
 		return;
 
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+	if (!RlvActions::canStartIM(id))
+	{
+		make_ui_sound("UISndInvalidOp");
+		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
+		return;
+	}
+// [/RLVa:KB]
+
 	LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_im, _1, _2));
 }
 
@@ -238,6 +251,16 @@ void LLAvatarActions::startCall(const LLUUID& id)
 	{
 		return;
 	}
+
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+	if (!RlvActions::canStartIM(id))
+	{
+		make_ui_sound("UISndInvalidOp");
+		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
+		return;
+	}
+// [/RLVa:KB]
+
 	LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_call, _1, _2));
 }
 
@@ -254,7 +277,17 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floate
 	id_array.reserve(ids.size());
 	for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
 	{
-		id_array.push_back(*it);
+// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0)
+		const LLUUID& idAgent = *it;
+		if (!RlvActions::canStartIM(idAgent))
+		{
+			make_ui_sound("UISndInvalidOp");
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
+			return;
+		}
+		id_array.push_back(idAgent);
+// [/RLVa:KB]
+//		id_array.push_back(*it);
 	}
 
 	// create the new ad hoc voice session
@@ -301,7 +334,17 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float
 	id_array.reserve(ids.size());
 	for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
 	{
-		id_array.push_back(*it);
+// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0)
+		const LLUUID& idAgent = *it;
+		if (!RlvActions::canStartIM(idAgent))
+		{
+			make_ui_sound("UISndInvalidOp");
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
+			return;
+		}
+		id_array.push_back(idAgent);
+// [/RLVa:KB]
+//		id_array.push_back(*it);
 	}
 	const std::string title = LLTrans::getString("conference-title");
 	LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, ids[0], id_array, false, floater_id);
@@ -417,6 +460,17 @@ void LLAvatarActions::teleport_request_callback(const LLSD& notification, const
 	{
 		LLMessageSystem* msg = gMessageSystem;
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		const LLUUID idRecipient = notification["substitutions"]["uuid"];
+		std::string strMessage = response["message"];
+
+		// Filter the request message if the recipients is IM-blocked
+		if ( (RlvActions::isRlvEnabled()) && ((!RlvActions::canStartIM(idRecipient)) || (!RlvActions::canSendIM(idRecipient))) )
+		{
+			strMessage = RlvStrings::getString(RLV_STRING_HIDDEN);
+		}
+// [/RLVa:KB]
+
 		msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
 		msg->nextBlockFast(_PREHASH_AgentData);
 		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
@@ -434,7 +488,10 @@ void LLAvatarActions::teleport_request_callback(const LLSD& notification, const
 		LLAgentUI::buildFullname(name);
 
 		msg->addStringFast(_PREHASH_FromAgentName, name);
-		msg->addStringFast(_PREHASH_Message, response["message"]);
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		msg->addStringFast(_PREHASH_Message, strMessage);
+// [/RLVa:KB]
+//		msg->addStringFast(_PREHASH_Message, response["message"]);
 		msg->addU32Fast(_PREHASH_ParentEstateID, 0);
 		msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
 		msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
@@ -453,14 +510,17 @@ void LLAvatarActions::teleportRequest(const LLUUID& id)
 {
 	LLSD notification;
 	notification["uuid"] = id;
-	LLAvatarName av_name;
-	if (!LLAvatarNameCache::get(id, &av_name))
-	{
-		// unlikely ... they just picked this name from somewhere...
-		LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id));
-		return; // reinvoke this when the name resolves
-	}
-	notification["NAME"] = av_name.getCompleteName();
+// [RLVa:KB] - Checked: RLVa-1.5.0
+	notification["NAME"] = LLSLURL("agent", id, (RlvActions::canShowName(RlvActions::SNC_TELEPORTREQUEST, id)) ? "completename" : "rlvanonym").getSLURLString();
+// [/RLVa:KB]
+//	LLAvatarName av_name;
+//	if (!LLAvatarNameCache::get(id, &av_name))
+//	{
+//		// unlikely ... they just picked this name from somewhere...
+//		LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id));
+//		return; // reinvoke this when the name resolves
+//	}
+//	notification["NAME"] = av_name.getCompleteName();
 
 	LLSD payload;
 
diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp
index c131dc641b4e78b45fa71c87f2c9dcc8f85779e8..3bcc61302fbf5596985128ecd6fb577550958e76 100644
--- a/indra/newview/llavatariconctrl.cpp
+++ b/indra/newview/llavatariconctrl.cpp
@@ -330,3 +330,13 @@ void LLAvatarIconCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarN
 		}
 	}
 }
+
+// [SL:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+BOOL LLAvatarIconCtrl::handleToolTip(S32 x, S32 y, MASK mask)
+{
+	// Don't show our tooltip if we were asked not to
+	if (!mDrawTooltip)
+		return FALSE;
+	return LLIconCtrl::handleToolTip(x, y, mask);
+}
+// [/SL:KB]
diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h
index 5b5720f4ac8fd74887b723c5feefe9d36e940ae8..75d6175254ba877142cb82e6a1b18d137a7e01cf 100644
--- a/indra/newview/llavatariconctrl.h
+++ b/indra/newview/llavatariconctrl.h
@@ -109,6 +109,10 @@ class LLAvatarIconCtrl
 public:
 	virtual ~LLAvatarIconCtrl();
 
+// [SL:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
+// [/SL:KB]
+
 	virtual void setValue(const LLSD& value);
 
 	// LLAvatarPropertiesProcessor observer trigger
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index 513f25e3017cd2795ae16c1698fc7d63d325a7c3..ef46dd1ed965a0c06fa4240ce753f9b52ac822da 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -141,6 +141,9 @@ LLAvatarList::LLAvatarList(const Params& p)
 , mShowSpeakingIndicator(p.show_speaking_indicator)
 , mShowPermissions(p.show_permissions_granted)
 , mShowCompleteName(false)
+// [RLVa:KB] - Checked: RLVa-1.2.0
+, mRlvCheckShowNames(false)
+// [/RLVa:KB]
 {
 	setCommitOnSelectionChange(true);
 
@@ -207,6 +210,10 @@ void LLAvatarList::draw()
 void LLAvatarList::clear()
 {
 	getIDs().clear();
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	// We need to be able to call this *somehow* and it actually makes moderate sense to call this in here
+	updateNoItemsMessage(mNameFilter);
+// [/RLVa:KB]
 	setDirty(true);
 	LLFlatListViewEx::clear();
 }
@@ -442,6 +449,9 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is
 {
 	LLAvatarListItem* item = new LLAvatarListItem();
 	item->setShowCompleteName(mShowCompleteName);
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	item->setRlvCheckShowNames(mRlvCheckShowNames);
+// [/RLVa:KB]
 	// This sets the name as a side effect
 	item->setAvatarId(id, mSessionID, mIgnoreOnlineStatus);
 	item->setOnline(mIgnoreOnlineStatus ? true : is_online);
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index 1a672c279b1d94cec40d6f2fdc8a00dea0e5c372..0613434ebb4ae76db4509c4dc1a65bfca7d86088 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -92,6 +92,12 @@ class LLAvatarList : public LLFlatListViewEx
 	// Return true if filter has at least one match.
 	bool filterHasMatches();
 
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; }
+	// We need this to be public since we call it from RlvUIEnabler::onToggleShowNames()
+	void updateAvatarNames();
+// [/RLVa:KB]
+
 	boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb);
 
 	boost::signals2::connection setItemDoubleClickCallback(const mouse_signal_t::slot_type& cb);
@@ -114,7 +120,7 @@ class LLAvatarList : public LLFlatListViewEx
 	void updateLastInteractionTimes();	
 	void rebuildNames();
 	void onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask);
-	void updateAvatarNames();
+//	void updateAvatarNames();
 
 private:
 
@@ -130,6 +136,9 @@ class LLAvatarList : public LLFlatListViewEx
 	bool mShowSpeakingIndicator;
 	bool mShowPermissions;
 	bool mShowCompleteName;
+// [RLVa:KB] - RLVa-1.2.0
+	bool mRlvCheckShowNames;
+// [/RLVa:KB]
 
 	LLTimer*				mLITUpdateTimer; // last interaction time update timer
 	std::string				mIconParamName;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index af3fac91bc07d17da393ad3010a7c9431c37f3ca..f0613f50de928dec8687f560367875accb1ebcdd 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -41,6 +41,10 @@
 #include "llavatariconctrl.h"
 #include "lloutputmonitorctrl.h"
 #include "lltooldraganddrop.h"
+// [RLVa:KB] - Checked: RLVa-2.0.1
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 bool LLAvatarListItem::sStaticInitialized = false;
 S32 LLAvatarListItem::sLeftPadding = 0;
@@ -76,6 +80,9 @@ LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/)
 	mOnlineStatus(E_UNKNOWN),
 	mShowInfoBtn(true),
 	mShowProfileBtn(true),
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	mRlvCheckShowNames(false),
+// [/RLVa:KB]
 	mShowPermissions(false),
 	mShowCompleteName(false),
 	mHovered(false),
@@ -179,8 +186,13 @@ S32 LLAvatarListItem::notifyParent(const LLSD& info)
 void LLAvatarListItem::onMouseEnter(S32 x, S32 y, MASK mask)
 {
 	getChildView("hovered_icon")->setVisible( true);
-	mInfoBtn->setVisible(mShowInfoBtn);
-	mProfileBtn->setVisible(mShowProfileBtn);
+//	mInfoBtn->setVisible(mShowInfoBtn);
+//	mProfileBtn->setVisible(mShowProfileBtn);
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	bool fRlvCanShowName = (!mRlvCheckShowNames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mAvatarId));
+	mInfoBtn->setVisible( (mShowInfoBtn) && (fRlvCanShowName) );
+	mProfileBtn->setVisible( (mShowProfileBtn) && (fRlvCanShowName) );
+// [/RLVa:KB]
 
 	mHovered = true;
 	LLPanel::onMouseEnter(x, y, mask);
@@ -357,12 +369,18 @@ void LLAvatarListItem::onProfileBtnClick()
 
 BOOL LLAvatarListItem::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
-	if(mInfoBtn->getRect().pointInRect(x, y))
+//	if(mInfoBtn->getRect().pointInRect(x, y))
+// [RVLa:KB] - Checked: RLVa-1.2.2
+	if ( (mInfoBtn->getVisible()) && (mInfoBtn->getEnabled()) && (mInfoBtn->getRect().pointInRect(x, y)) )
+// [/SL:KB]
 	{
 		onInfoBtnClick();
 		return TRUE;
 	}
-	if(mProfileBtn->getRect().pointInRect(x, y))
+//	if(mProfileBtn->getRect().pointInRect(x, y))
+// [RLVa:KB] - Checked: RLVa-1.2.2
+	if ( (mProfileBtn->getVisible()) && (mProfileBtn->getEnabled()) && (mProfileBtn->getRect().pointInRect(x, y)) )
+// [/SL:KB]
 	{
 		onProfileBtnClick();
 		return TRUE;
@@ -422,8 +440,16 @@ void LLAvatarListItem::onAvatarNameCache(const LLAvatarName& av_name)
 	    mGreyOutUsername = "[ " + av_name.getUserName(true) + " ]";
 	    LLStringUtil::toLower(mGreyOutUsername);
 	}
-	setAvatarName(name_string);
-	setAvatarToolTip(av_name.getUserName());
+//	setAvatarName(name_string);
+//	setAvatarToolTip(av_name.getUserName());
+// [RLVa:KB] - Checked: RLVa-1.2.2
+	bool fRlvCanShowName = (!mRlvCheckShowNames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mAvatarId));
+
+	setAvatarName( (fRlvCanShowName) ?  name_string : RlvStrings::getAnonym(av_name) );
+	setAvatarToolTip( (fRlvCanShowName) ? av_name.getUserName() : RlvStrings::getAnonym(av_name) );
+	// TODO-RLVa: bit of a hack putting this here. Maybe find a better way?
+	mAvatarIcon->setDrawTooltip(fRlvCanShowName);
+// [/RLVa:KB]
 
 	//requesting the list to resort
 	notifyParent(LLSD().with("sort", LLSD()));
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index 36d18114aaec80f6d6a4484b9df94c5c8b41027e..96e4fc3cc7cc8f6b9e8e147160f73a858e02af0a 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -107,6 +107,9 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver
 	void showLastInteractionTime(bool show);
 	void setAvatarIconVisible(bool visible);
 	void setShowCompleteName(bool show) { mShowCompleteName = show;};
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; }
+// [/RLVa:KB]
 	
 	const LLUUID& getAvatarId() const;
 	std::string getAvatarName() const;
@@ -212,6 +215,9 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver
 	//Speaker indicator and avatar name coords are translated accordingly
 	bool mShowInfoBtn;
 	bool mShowProfileBtn;
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	bool mRlvCheckShowNames;
+// [/RLVa:KB]
 
 	/// indicates whether to show icons representing permissions granted
 	bool mShowPermissions;
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index 00fa6dd9798793d036595787ecfdfc65d3520fe0..90f5fee4d9c394e4637703a9f35d7bba9db2a407 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -59,6 +59,9 @@
 #include "llui.h"
 #include "llviewermenu.h"
 #include "lluictrlfactory.h"
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Globals
@@ -78,7 +81,10 @@ class LLChatBarGestureObserver : public LLGestureManagerObserver
 };
 
 
-extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+//extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-0.2.2)
+extern void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel);
+// [/RLVa:KB]
 
 //
 // Functions
@@ -471,7 +477,11 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata )
 
 	S32 length = raw_text.length();
 
-	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
+//	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
+// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
+	// RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional?
+	if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) )
+// [/RLVa:KB]
 	{
 		gAgent.startTyping();
 	}
@@ -583,6 +593,22 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL
 		utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1);
 	}
 
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+	// RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional?
+	if ( (0 == channel) && (rlv_handler_t::isEnabled()) )
+	{
+		// Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation)
+		if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
+			type = CHAT_TYPE_WHISPER;
+		else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
+			type = CHAT_TYPE_NORMAL;
+		else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
+			type = CHAT_TYPE_NORMAL;
+
+		animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE );
+	}
+// [/RLVa:KB]
+
 	// Don't animate for chats people can't hear (chat to scripts)
 	if (animate && (channel == 0))
 	{
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 5d2997688fc2a0f172a4ed43d78263c260f45e88..bff789d3744f11ffce7efd6c359fa91743963781 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -62,6 +62,9 @@
 #include "llviewercontrol.h"
 #include "llviewerobjectlist.h"
 #include "llmutelist.h"
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f)
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history");
 
@@ -93,6 +96,10 @@ class LLObjectIMHandler : public LLCommandHandler
 		LLSD payload;
 		payload["object_id"] = object_id;
 		payload["owner_id"] = query_map["owner"];
+// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+		if (query_map.has("rlv_shownames"))
+			payload["rlv_shownames"] = query_map["rlv_shownames"];
+// [/RLVa:KB]
 		payload["name"] = query_map["name"];
 		payload["slurl"] = LLWeb::escapeURL(query_map["slurl"]);
 		payload["group_owned"] = query_map["groupowned"];
@@ -108,6 +115,10 @@ class LLChatHistoryHeader: public LLPanel
 	LLChatHistoryHeader()
 	:	LLPanel(),
 		mInfoCtrl(NULL),
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f
+		mShowContextMenu(true), 
+		mShowInfoCtrl(true),
+// [/RLVa:KB]
 		mPopupMenuHandleAvatar(),
 		mPopupMenuHandleObject(),
 		mAvatarID(),
@@ -348,7 +359,11 @@ class LLChatHistoryHeader: public LLPanel
 
 	void showInspector()
 	{
-		if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return;
+//		if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f
+		// Don't double-click show the inspector if we're not showing the info control
+		if ( (!mShowInfoCtrl) || (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) ) return;
+// [/RLVa:KB]
 		
 		if (mSourceType == CHAT_SOURCE_OBJECT)
 		{
@@ -412,8 +427,24 @@ class LLChatHistoryHeader: public LLPanel
 
 			// Start with blank so sample data from XUI XML doesn't
 			// flash on the screen
-			user_name->setValue( LLSD() );
-			fetchAvatarName();
+//			user_name->setValue( LLSD() );
+//			fetchAvatarName();
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+			if (!chat.mRlvNamesFiltered)
+			{
+				user_name->setValue( LLSD() );
+				fetchAvatarName();
+			}
+			else
+			{
+				// If the agent's chat was subject to @shownames=n we should display their anonimized name
+				mFrom = chat.mFromName;
+				user_name->setValue(mFrom);
+				user_name->setToolTip(mFrom);
+				setToolTip(mFrom);
+				updateMinUserNameWidth();
+			}
+// [/RLVa:KB]
 		}
 		else if (chat.mChatStyle == CHAT_STYLE_HISTORY ||
 				 mSourceType == CHAT_SOURCE_AGENT)
@@ -465,6 +496,15 @@ class LLChatHistoryHeader: public LLPanel
 		if(mSourceType != CHAT_SOURCE_AGENT ||	mAvatarID.isNull())
 			icon->setDrawTooltip(false);
 
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f
+		// Don't show the context menu, info control or avatar icon tooltip if this chat was subject to @shownames=n
+		if ( (chat.mRlvNamesFiltered) && ((CHAT_SOURCE_AGENT == mSourceType) || (CHAT_SOURCE_OBJECT == mSourceType))  )
+		{
+			mShowInfoCtrl = mShowContextMenu = false;
+			icon->setDrawTooltip(false);
+		}
+// [/RLVa:KB]
+
 		switch (mSourceType)
 		{
 			case CHAT_SOURCE_AGENT:
@@ -541,6 +581,10 @@ class LLChatHistoryHeader: public LLPanel
 
 	void showContextMenu(S32 x,S32 y)
 	{
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f
+		if (!mShowContextMenu)
+			return;
+// [/RLVa:KB]
 		if(mSourceType == CHAT_SOURCE_SYSTEM)
 			showSystemContextMenu(x,y);
 		if(mAvatarID.notNull() && mSourceType == CHAT_SOURCE_AGENT)
@@ -615,7 +659,10 @@ class LLChatHistoryHeader: public LLPanel
 
 	void showInfoCtrl()
 	{
-		const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType;
+//		const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f
+		const bool isVisible = mShowInfoCtrl && !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType;
+// [/RLVa:KB]
 		if (isVisible)
 		{
 			const LLRect sticky_rect = mUserNameTextBox->getRect();
@@ -705,6 +752,10 @@ class LLChatHistoryHeader: public LLPanel
 	EChatSourceType		mSourceType;
 	std::string			mFrom;
 	LLUUID				mSessionID;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f
+	bool                mShowContextMenu;
+	bool                mShowInfoCtrl;
+// [/RLVa:KB]
 
 	S32					mMinUserNameWidth;
 	const LLFontGL*		mUserNameFont;
@@ -989,8 +1040,18 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 			// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
 			if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
 			{
-				// for object IMs, create a secondlife:///app/objectim SLapp
-				std::string url = LLViewerChat::getSenderSLURL(chat, args);
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+				// NOTE-RLVa: we don't need to do any @shownames or @showloc filtering here because we'll already have an existing URL
+				std::string url = chat.mURL;
+				RLV_ASSERT( (url.empty()) || (std::string::npos != url.find("objectim")) );
+				if ( (url.empty()) || (std::string::npos == url.find("objectim")) )
+				{
+// [/RLVa:KB]
+					// for object IMs, create a secondlife:///app/objectim SLapp
+					/*std::string*/ url = LLViewerChat::getSenderSLURL(chat, args);
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+				}
+// [/RLVa:KB]
 
 				// set the link for the object name to be the objectim SLapp
 				// (don't let object names with hyperlinks override our objectim Url)
@@ -1004,7 +1065,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 				mEditor->appendText(chat.mFromName + delimiter, prependNewLineState, link_params);
 				prependNewLineState = false;
 			}
-			else if ( chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log)
+//			else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log)
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log && !chat.mRlvNamesFiltered)
+// [/RLVa:KB]
 			{
 				LLStyle::Params link_params(body_message_params);
 				link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID));
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index cfc62c07b6e073a8ee36e930cb74ec6fcd465a1c..54593311df2cfc1d59f9b24eba1dd25675d0cfb7 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -41,6 +41,10 @@
 
 #include "llslurl.h"
 
+// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 static const S32 msg_left_offset = 10;
 static const S32 msg_right_offset = 10;
 static const S32 msg_height_pad = 5;
@@ -182,7 +186,11 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)
 	std::string		fromName = notification["from"].asString();	// agent or object name
 	mFromID = notification["from_id"].asUUID();		// agent id or object id
 	mFromName = fromName;
-	
+
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	mShowIconTooltip = notification.has("show_icon_tooltip") ? notification["show_icon_tooltip"].asBoolean() : true;
+// [/RLVa:KB]
+
 	int sType = notification["source"].asInteger();
     mSourceType = (EChatSourceType)sType;
 	
@@ -228,8 +236,15 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)
 			style_params_name.font.name(font_name);
 			style_params_name.font.size(font_style_size);
 
-			style_params_name.link_href = notification["sender_slurl"].asString();
-			style_params_name.is_link = true;
+//			style_params_name.link_href = notification["sender_slurl"].asString();
+//			style_params_name.is_link = true;
+// [RLVa:KB] - Checked: 2011-12-13 (RLVa-1.4.6) | Added: RLVa-1.4.6
+			if (notification.has("sender_slurl"))
+			{
+				style_params_name.link_href = notification["sender_slurl"].asString();
+				style_params_name.is_link = true;
+			}
+// [/RLVa:KB]
 
 			mMsgText->appendText(str_sender, FALSE, style_params_name);
 
@@ -365,7 +380,10 @@ void LLFloaterIMNearbyChatToastPanel::draw()
 		LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false);
 		if(icon)
 		{
-			icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT);
+//			icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT);
+// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			icon->setDrawTooltip( (mShowIconTooltip) && (mSourceType == CHAT_SOURCE_AGENT) );
+// [/RLVa:KB]
 			if(mSourceType == CHAT_SOURCE_OBJECT)
 				icon->setValue(LLSD("OBJECT_Icon"));
 			else if(mSourceType == CHAT_SOURCE_SYSTEM)
diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h
index f66670ec8c83a91c3ac61fce643b925261906abb..bf977002f335c25d26b3c4e423074aec996c2f09 100644
--- a/indra/newview/llchatitemscontainerctrl.h
+++ b/indra/newview/llchatitemscontainerctrl.h
@@ -47,6 +47,9 @@ class LLFloaterIMNearbyChatToastPanel : public LLPanel
         LLFloaterIMNearbyChatToastPanel()
 		: 
 	mIsDirty(false),
+// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	mShowIconTooltip(true),
+// [/RLVa:KB]
 	mSourceType(CHAT_SOURCE_OBJECT)
 	{};
 public:
@@ -91,6 +94,9 @@ class LLFloaterIMNearbyChatToastPanel : public LLPanel
 
 
 	bool mIsDirty;
+// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	bool mShowIconTooltip;
+// [/RLVa:KB]
 };
 
 
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index dedb06c9459404a0b73fdfc3684949b86f62ff06..98e616f8f9b2c6ada01eb21d5e86209c773bfca5 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -36,6 +36,9 @@
 #include "llsingleton.h"
 #include "llsyswellwindow.h"
 #include "llfloaternotificationstabbed.h"
+// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5)
+#include "llchannelmanager.h"
+// [/SL:KB]
 
 static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
 static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
@@ -237,6 +240,15 @@ bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNo
 	{
 		displayNotification = true;
 	}
+// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5)
+	else if ("offer" == notification->getType())
+	{
+		// Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell
+		/*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel();
+		/*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL;
+		displayNotification = (pToast) && (pToast->getCanBeStored());
+	}
+// [/SL:KB]
 	else
 	{
 		displayNotification = false;
diff --git a/indra/newview/lldaycyclemanager.cpp b/indra/newview/lldaycyclemanager.cpp
index 803e2b2fb22e9544df263b883be8b6c326b1d5b3..b8d7b8ec3c1f4c5ea686332cd3d1c17bf3336676 100644
--- a/indra/newview/lldaycyclemanager.cpp
+++ b/indra/newview/lldaycyclemanager.cpp
@@ -30,6 +30,10 @@
 
 #include "lldiriterator.h"
 
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+#include <boost/algorithm/string.hpp>
+// [/RLVa:KB]
+
 void LLDayCycleManager::getPresetNames(preset_name_list_t& names) const
 {
 	names.clear();
@@ -60,6 +64,18 @@ void LLDayCycleManager::getPresetNames(preset_name_list_t& user, preset_name_lis
 	}
 }
 
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+const std::string& LLDayCycleManager::findPreset(const std::string& strPresetName)
+{
+	for (dc_map_t::const_iterator itCycle = mDayCycleMap.begin(); itCycle != mDayCycleMap.end(); ++itCycle)
+	{
+		if (boost::iequals(itCycle->first, strPresetName))
+			return itCycle->first;
+	}
+	return LLStringUtil::null;
+}
+// [/RLVa:KB]
+
 void LLDayCycleManager::getUserPresetNames(preset_name_list_t& user) const
 {
 	preset_name_list_t sys; // unused
diff --git a/indra/newview/lldaycyclemanager.h b/indra/newview/lldaycyclemanager.h
index 3d2144960da160d3429ec6b039f7db70f554911a..81b31dc71c536c2644752286e8b5ff16bf816f08 100644
--- a/indra/newview/lldaycyclemanager.h
+++ b/indra/newview/lldaycyclemanager.h
@@ -51,6 +51,9 @@ class LLDayCycleManager : public LLSingleton<LLDayCycleManager>
 	void getPresetNames(preset_name_list_t& names) const;
 	void getPresetNames(preset_name_list_t& user, preset_name_list_t& sys) const;
 	void getUserPresetNames(preset_name_list_t& user) const;
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+	const std::string& findPreset(const std::string& strPresetName);
+// [/RLVa:KB]
 
 	bool getPreset(const std::string name, LLWLDayCycle& day_cycle) const;
 	bool getPreset(const std::string name, LLSD& day_cycle) const;
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index b716a7654369f39b00f7465d5fd995e333c88a8a..fd3401243de2ac4bb2181dfd23e767a15aa219f7 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -308,10 +308,16 @@ void LLDrawPoolTerrain::renderFullShader()
 	// Hack! Get the region that this draw pool is rendering from!
 	LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
 	LLVLComposition *compp = regionp->getComposition();
-	LLViewerTexture *detail_texture0p = compp->mDetailTextures[0];
-	LLViewerTexture *detail_texture1p = compp->mDetailTextures[1];
-	LLViewerTexture *detail_texture2p = compp->mDetailTextures[2];
-	LLViewerTexture *detail_texture3p = compp->mDetailTextures[3];
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+// [/SL:KB]
+//	LLViewerTexture *detail_texture0p = compp->mDetailTextures[0];
+//	LLViewerTexture *detail_texture1p = compp->mDetailTextures[1];
+//	LLViewerTexture *detail_texture2p = compp->mDetailTextures[2];
+//	LLViewerTexture *detail_texture3p = compp->mDetailTextures[3];
 
 	LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal();
 	F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale;
@@ -459,10 +465,16 @@ void LLDrawPoolTerrain::renderFull4TU()
 	// Hack! Get the region that this draw pool is rendering from!
 	LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
 	LLVLComposition *compp = regionp->getComposition();
-	LLViewerTexture *detail_texture0p = compp->mDetailTextures[0];
-	LLViewerTexture *detail_texture1p = compp->mDetailTextures[1];
-	LLViewerTexture *detail_texture2p = compp->mDetailTextures[2];
-	LLViewerTexture *detail_texture3p = compp->mDetailTextures[3];
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+// [/SL:KB]
+//	LLViewerTexture *detail_texture0p = compp->mDetailTextures[0];
+//	LLViewerTexture *detail_texture1p = compp->mDetailTextures[1];
+//	LLViewerTexture *detail_texture2p = compp->mDetailTextures[2];
+//	LLViewerTexture *detail_texture3p = compp->mDetailTextures[3];
 
 	LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal();
 	F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale;
@@ -661,10 +673,16 @@ void LLDrawPoolTerrain::renderFull2TU()
 	// Hack! Get the region that this draw pool is rendering from!
 	LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
 	LLVLComposition *compp = regionp->getComposition();
-	LLViewerTexture *detail_texture0p = compp->mDetailTextures[0];
-	LLViewerTexture *detail_texture1p = compp->mDetailTextures[1];
-	LLViewerTexture *detail_texture2p = compp->mDetailTextures[2];
-	LLViewerTexture *detail_texture3p = compp->mDetailTextures[3];
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+	LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep;
+// [/SL:KB]
+//	LLViewerTexture *detail_texture0p = compp->mDetailTextures[0];
+//	LLViewerTexture *detail_texture1p = compp->mDetailTextures[1];
+//	LLViewerTexture *detail_texture2p = compp->mDetailTextures[2];
+//	LLViewerTexture *detail_texture3p = compp->mDetailTextures[3];
 
 	LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal();
 	F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale;
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index b1f40781f73e5bcdccd50ac111e41d928b8492cc..ecba1dc75db63f0df70b8933f7345010058aa050 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -98,7 +98,10 @@ void LLDrawPoolTree::render(S32 pass)
 	LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1);
 	LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f);
 
-	gGL.getTexUnit(sDiffTex)->bind(mTexturep);
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	gGL.getTexUnit(sDiffTex)->bind( (LLPipeline::sRenderTextures) ? mTexturep : LLViewerFetchedTexture::sDefaultDiffuseImagep );
+// [/SL:KB]
+//	gGL.getTexUnit(sDiffTex)->bind(mTexturep);
 				
 	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 		 iter != mDrawFace.end(); iter++)
diff --git a/indra/newview/llenvmanager.cpp b/indra/newview/llenvmanager.cpp
index a626ad1bffa7b9220cb290ce369c7d806a86d8bb..73b376a55e0c68649746004ac9a035f9caf8fc04 100644
--- a/indra/newview/llenvmanager.cpp
+++ b/indra/newview/llenvmanager.cpp
@@ -35,6 +35,10 @@
 #include "llwaterparammanager.h"
 #include "llwlhandlers.h"
 #include "llwlparammanager.h"
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+#include <boost/algorithm/string.hpp>
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 std::string LLEnvPrefs::getWaterPresetName() const
 {
@@ -479,7 +483,10 @@ void LLEnvManagerNew::onRegionSettingsResponse(const LLSD& content)
 	LLWLParamManager::instance().refreshRegionPresets();
 
 	// If using server settings, update managers.
-	if (getUseRegionSettings())
+//	if (getUseRegionSettings())
+// [RLVa:KB] - Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+	if ( (getUseRegionSettings()) && (LLWLParamManager::getInstance()->mAnimator.getIsRunning()) )
+// [/RLVa:KB]
 	{
 		updateManagersFromPrefs(mInterpNextChangeMessage);
 	}
@@ -590,6 +597,14 @@ void LLEnvManagerNew::updateWaterFromPrefs(bool interpolate)
 void LLEnvManagerNew::updateManagersFromPrefs(bool interpolate)
 {
 	LL_DEBUGS("Windlight")<<LL_ENDL;
+
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV))
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	// Apply water settings.
 	updateWaterFromPrefs(interpolate);
 
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index de349a03d4cafe9878c5e53bbae42b2335995c00..b4c1fc96c514ac33c7fe2836f7b84bc07037e4f0 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -53,6 +53,9 @@
 #include "llviewershadermgr.h"
 #include "llviewertexture.h"
 #include "llvoavatar.h"
+// [RLVa:KB] - Checked: RLVa-2.0.0
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #if LL_LINUX
 // Work-around spurious used before init warning on Vector4a
@@ -166,6 +169,10 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mBoundingSphereRadius = 0.0f ;
 
 	mHasMedia = FALSE ;
+
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	mShowDiffTexture = true;
+// [/SL:KB]
 }
 
 void LLFace::destroy()
@@ -282,6 +289,15 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex)
 		return ;
 	}
 
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	if ( (LLRender::DIFFUSE_MAP == ch) && (!mShowDiffTexture) )
+	{
+		mOrigDiffTexture = tex;
+		if (LLViewerFetchedTexture::sDefaultDiffuseImagep.get() == mTexture[ch].get())
+			return;
+	}
+// [/SL:KB]
+
 	if(mTexture[ch].notNull())
 	{
 		mTexture[ch]->removeFace(ch, this) ;
@@ -2644,9 +2660,60 @@ LLViewerTexture* LLFace::getTexture(U32 ch) const
 {
 	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	// Check whether the diffuse texture needs to be obscured or restored
+	if (mShowDiffTexture != LLPipeline::sRenderTextures)
+		setDefaultTexture(LLRender::DIFFUSE_MAP, !LLPipeline::sRenderTextures);
+// [/SL:KB]
+
 	return mTexture[ch] ;
 }
 
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+void LLFace::setDefaultTexture(U32 nChannel, bool fShowDefault) const
+{
+	bool fUpdated = false;
+	if ( (LLRender::DIFFUSE_MAP == nChannel) && (mVObjp) && (!mVObjp->isDead()) && ((LL_PCODE_VOLUME == mVObjp->getPCode()) || (LLViewerObject::LL_VO_PART_GROUP == mVObjp->getPCode())) )
+	{
+		if ( ((mShowDiffTexture) && (fShowDefault)) ||
+		     ((!mShowDiffTexture) && (fShowDefault) && (mOrigDiffTexture.notNull()) && (mTexture[nChannel]) && (mTexture[nChannel]->getID() != LLViewerFetchedTexture::sDefaultDiffuseImagep->getID())) )
+		{
+			if (mOrigDiffTexture.notNull())
+				mShowDiffTexture = true;				// Swap out the default texture
+			else
+				mOrigDiffTexture = mTexture[nChannel];	// Cache the original texture
+
+			if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_TEXTURES)) || (!mVObjp->isAttachment()) )
+			{
+				if (LL_PCODE_VOLUME == mVObjp->getPCode())
+					const_cast<LLFace*>(this)->switchTexture(nChannel, LLViewerFetchedTexture::sDefaultDiffuseImagep);
+				else
+					const_cast<LLFace*>(this)->setTexture(nChannel, LLViewerFetchedTexture::sDefaultDiffuseImagep);
+			}
+			mShowDiffTexture = false; fUpdated = true;
+		}
+		else if ( (!mShowDiffTexture) && (!fShowDefault) && (mOrigDiffTexture.notNull()) )
+		{
+			mShowDiffTexture = true;
+			if (LL_PCODE_VOLUME == mVObjp->getPCode())
+				const_cast<LLFace*>(this)->switchTexture(nChannel, mOrigDiffTexture);
+			else
+				const_cast<LLFace*>(this)->setTexture(nChannel, mOrigDiffTexture);
+			mOrigDiffTexture = nullptr; fUpdated = true;
+		}
+
+		if ((fUpdated) && (mDrawablep))
+		{
+			gPipeline.markTextured(mDrawablep);
+			const_cast<LLDrawable*>(mDrawablep.get())->updateTexture();
+		}
+	}
+
+	// Always flip the flag even if we didn't obscure so we don't keep wasting cycles with negative checks
+	mShowDiffTexture = !fShowDefault;
+}
+// [/SL:KB]
+
 void LLFace::setVertexBuffer(LLVertexBuffer* buffer)
 {
 	mVertexBuffer = buffer;
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index ee545acb94104c53bde604d81844acab02e1000f..35cfdc1f8b66f8301f97eecbf965c60acadb1362 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -220,6 +220,10 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 
 	BOOL		switchTexture() ;
 
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	void		setDefaultTexture(U32 nChannel, bool fShowDefault) const;
+// [/SL:KB]
+
 	//vertex buffer tracking
 	void setVertexBuffer(LLVertexBuffer* buffer);
 	void clearVertexBuffer(); //sets mVertexBuffer to NULL
@@ -294,7 +298,11 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 	F32         mBoundingSphereRadius ;
 	bool        mHasMedia ;
 
-	
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	mutable bool                       mShowDiffTexture;
+	mutable LLPointer<LLViewerTexture> mOrigDiffTexture;
+// [/SL:KB]
+
 protected:
 	static BOOL	sSafeRenderSelect;
 	
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 72892b47a492dd38623550c86fa88acfb6200598..71e5de3d97ab588a8b28acc6f04c5ba6cfe772c1 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -37,6 +37,10 @@
 #include "llviewercontrol.h"
 #include "llviewerregion.h"		// getCapability()
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.2a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Linden libraries
 #include "llavatarnamecache.h"	// IDEVO
@@ -279,6 +283,23 @@ void LLFloaterAvatarPicker::onRangeAdjust()
 void LLFloaterAvatarPicker::onList()
 {
 	getChildView("ok_btn")->setEnabled(isSelectBtnEnabled());
+
+// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.2a) | Modified: RLVa-1.2.0d
+	if (rlv_handler_t::isEnabled())
+	{
+		LLTabContainer* pTabs = getChild<LLTabContainer>("ResidentChooserTabs");
+		LLPanel* pNearMePanel = getChild<LLPanel>("NearMePanel");
+		RLV_ASSERT( (pTabs) && (pNearMePanel) );
+		if ( (pTabs) && (pNearMePanel) )
+		{
+			// TODO-RLVa: check this for RlvActions::canShowName()
+			bool fRlvEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES);
+			pTabs->enableTabButton(pTabs->getIndexForPanel(pNearMePanel), fRlvEnable);
+			if ( (!fRlvEnable) && (pTabs->getCurrentPanel() == pNearMePanel) )
+				pTabs->selectTabByName("SearchPanel");
+		}
+	}
+// [/RLVa:KB]
 }
 
 void LLFloaterAvatarPicker::populateNearMe()
@@ -589,7 +610,10 @@ BOOL LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask,
 				std::string avatar_name = selection->getColumn(0)->getValue().asString();
 				if (dest_agent_id.notNull() && dest_agent_id != gAgentID)
 				{
-					if (drop)
+//					if (drop)
+// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0)
+					if ( (drop) && (RlvActions::canStartIM(dest_agent_id)) )
+// [/RLVa:KB]
 					{
 						// Start up IM before give the item
 						session_id = gIMMgr->addSession(avatar_name, IM_NOTHING_SPECIAL, dest_agent_id);
diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp
index 5a9cdbba44d6bfe3aee80e43f079528bf4e32147..fa1667de73d376c28ab9f968f674f232718f6660 100644
--- a/indra/newview/llfloaterbuy.cpp
+++ b/indra/newview/llfloaterbuy.cpp
@@ -104,7 +104,10 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info)
 	// Clean up the lists...
 	floater->reset();
 	floater->mSaleInfo = sale_info;
-	floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	floater->mObjectSelection = LLSelectMgr::getInstance()->getSelection();
+// [/RLVa:KB]
+//	floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
 	
 	LLSelectNode* node = selection->getFirstRootNode();
 	if (!node)
diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp
index b32ac860aaa57299fec019a6e4fde0061e77026c..9d0682d251f6db2f443de00c2cd00bd78f7bb375 100644
--- a/indra/newview/llfloaterbuycontents.cpp
+++ b/indra/newview/llfloaterbuycontents.cpp
@@ -104,7 +104,10 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info)
 	if (list)
 		list->deleteAllItems();
 
-	floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	floater->mObjectSelection = LLSelectMgr::getInstance()->getSelection();
+// [/RLVa:KB]
+//	floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
 
 	LLUUID owner_id;
 	std::string owner_name;
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 7a989806a1ff2ff1ead578d21ddd1b3e6e55afc3..5f9ecbd30c156927d6b43fa0e5101b71b42698bf 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -67,6 +67,10 @@
 #include "llviewerchat.h"
 #include "lltranslate.h"
 #include "llautoreplace.h"
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+#include "rlvactions.h"
+// [/RLVa:KB]
 
 S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0;
 
@@ -75,7 +79,10 @@ const S32 COLLAPSED_HEIGHT = 60;
 const S32 EXPANDED_MIN_HEIGHT = 150;
 
 // legacy callback glue
-void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-0.2.2)
+void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel);
+// [/RLVa:KB]
 
 struct LLChatTypeTrigger {
 	std::string name;
@@ -835,8 +842,57 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32*
 	}
 }
 
-void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel)
+//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel)
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a
+void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel)
+// [/RLVa:KB]
 {
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a
+	// Only process chat messages (ie not CHAT_TYPE_START, CHAT_TYPE_STOP, etc)
+	if ( (rlv_handler_t::isEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) )
+	{
+		if (0 == channel)
+		{
+			// (We already did this before, but LLChatHandler::handle() calls this directly)
+			if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
+				type = CHAT_TYPE_WHISPER;
+			else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
+				type = CHAT_TYPE_NORMAL;
+			else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
+				type = CHAT_TYPE_NORMAL;
+
+			// Redirect chat if needed
+			if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT) || (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE)) ) && 
+				 (gRlvHandler.redirectChatOrEmote(utf8_out_text)) ) )
+			{
+				return;
+			}
+
+			// Filter public chat if sendchat restricted
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT))
+				gRlvHandler.filterChat(utf8_out_text, true);
+		}
+		else
+		{
+			// Don't allow chat on a non-public channel if sendchannel restricted (unless the channel is an exception)
+			if (!RlvActions::canSendChannel(channel))
+				return;
+
+			// Don't allow chat on debug channel if @sendchat, @redirchat or @rediremote restricted (shows as public chat on viewers)
+			if (CHAT_CHANNEL_DEBUG == channel)
+			{
+				bool fIsEmote = RlvUtil::isEmote(utf8_out_text);
+				if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) || 
+					 ((!fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT))) || 
+					 ((fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE))) )
+				{
+					return;
+				}
+			}
+		}
+	}
+// [/RLVa:KB]
+
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_ChatFromViewer);
 	msg->nextBlockFast(_PREHASH_AgentData);
diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp
index 9fd731ed5630e823b5df16b85086e93f09ce8670..750f410bcabac607e09bc61929889ddba9847b57 100644
--- a/indra/newview/llfloaterimnearbychathandler.cpp
+++ b/indra/newview/llfloaterimnearbychathandler.cpp
@@ -45,7 +45,13 @@
 #include "llrootview.h"
 #include "lllayoutstack.h"
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
+
 //add LLFloaterIMNearbyChatHandler to LLNotificationsUI namespace
+
 using namespace LLNotificationsUI;
 
 static LLFloaterIMNearbyChatToastPanel* createToastPanel()
@@ -485,6 +491,24 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
 	if(chat_msg.mText.empty())
 		return;//don't process empty messages
 
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+	if (RlvActions::isRlvEnabled())
+	{
+		// NOTE-RLVa: we can only filter the *message* here since most everything else will already be part of "args" as well
+		LLChat& tmp_chat = const_cast<LLChat&>(chat_msg);
+		if ( (!RlvActions::canShowLocation()) && (!tmp_chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) )
+		{
+			RlvUtil::filterLocation(tmp_chat.mText);
+			tmp_chat.mRlvLocFiltered = TRUE;
+		}
+		if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) && (!tmp_chat.mRlvNamesFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) )
+		{
+			RlvUtil::filterNames(tmp_chat.mText);
+			tmp_chat.mRlvNamesFiltered = TRUE;
+		}
+	}
+// [/RLVa:KB]
+
     LLFloaterReg::getInstance("im_container");
 	LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
 
@@ -498,7 +522,11 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
 	chat["chat_type"] = (S32)chat_msg.mChatType;
 	chat["chat_style"] = (S32)chat_msg.mChatStyle;
 	// Pass sender info so that it can be rendered properly (STORM-1021).
-	chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args);
+//	chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args);
+// [RLVa:KB] - Checked: 2011-12-13 (RLVa-1.4.6) | Added: RLVa-1.4.6
+	if ((CHAT_SOURCE_AGENT != chat_msg.mSourceType) || (!chat_msg.mRlvNamesFiltered))
+		chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args);
+// [/RLVa:KB]
 
 	if (chat_msg.mChatType == CHAT_TYPE_DIRECT &&
 		chat_msg.mText.length() > 0 &&
@@ -547,8 +575,11 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
  		LLFirstUse::otherAvatarChatFirst();
 
  		// Add sender to the recent people list.
- 		LLRecentPeople::instance().add(chat_msg.mFromID);
-
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		if ( (!RlvActions::isRlvEnabled()) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, chat_msg.mFromID)) )
+	 		LLRecentPeople::instance().add(chat_msg.mFromID);
+// [/RLVa:KB]
+// 		LLRecentPeople::instance().add(chat_msg.mFromID);
 	}
 
 	// Send event on to LLEventStream
@@ -640,6 +671,10 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
             LLUUID id;
             id.generate();
             chat["id"] = id;
+// [RLVa:KB] - Checked: RLVa-1.2.0
+			if (RlvActions::isRlvEnabled())
+				chat["show_icon_tooltip"] = !chat_msg.mRlvNamesFiltered;
+// [/RLVa:KB]
             std::string r_color_name = "White";
             F32 r_color_alpha = 1.0f; 
             LLViewerChat::getChatColor( chat_msg, r_color_name, r_color_alpha);
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 6623ce0f807ee910d2a150f0c8e4f31565d00d12..bbcde5cc756566491b57c8f22a025105087060e0 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -62,6 +62,10 @@
 #include "llnotificationmanager.h"
 #include "llautoreplace.h"
 #include "llcorehttputil.h"
+// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9)
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 const F32 ME_TYPING_TIMEOUT = 4.0f;
 const F32 OTHER_TYPING_TIMEOUT = 9.0f;
@@ -268,7 +272,60 @@ void LLFloaterIMSession::sendMsgFromInputEditor()
 
 void LLFloaterIMSession::sendMsg(const std::string& msg)
 {
-	const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1);
+//	const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1);
+// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0)
+	std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1);
+
+	if ( (RlvActions::hasBehaviour(RLV_BHVR_SENDIM)) || (RlvActions::hasBehaviour(RLV_BHVR_SENDIMTO)) )
+	{
+		const LLIMModel::LLIMSession* pIMSession = LLIMModel::instance().findIMSession(mSessionID);
+		RLV_ASSERT(pIMSession);
+
+		bool fRlvFilter = !pIMSession;
+		if (pIMSession)
+		{
+			switch (pIMSession->mSessionType)
+			{
+				case LLIMModel::LLIMSession::P2P_SESSION:	// One-on-one IM
+					fRlvFilter = !RlvActions::canSendIM(mOtherParticipantUUID);
+					break;
+				case LLIMModel::LLIMSession::GROUP_SESSION:	// Group chat
+					fRlvFilter = !RlvActions::canSendIM(mSessionID);
+					break;
+				case LLIMModel::LLIMSession::ADHOC_SESSION:	// Conference chat: allow if all participants can be sent an IM
+					{
+						if (!pIMSession->mSpeakers)
+						{
+							fRlvFilter = true;
+							break;
+						}
+
+						LLSpeakerMgr::speaker_list_t speakers;
+						pIMSession->mSpeakers->getSpeakerList(&speakers, TRUE);
+						for (LLSpeakerMgr::speaker_list_t::const_iterator itSpeaker = speakers.begin(); 
+								itSpeaker != speakers.end(); ++itSpeaker)
+						{
+							const LLSpeaker* pSpeaker = *itSpeaker;
+							if ( (gAgent.getID() != pSpeaker->mID) && (!RlvActions::canSendIM(pSpeaker->mID)) )
+							{
+								fRlvFilter = true;
+								break;
+							}
+						}
+					}
+					break;
+				default:
+					fRlvFilter = true;
+					break;
+			}
+		}
+
+		if (fRlvFilter)
+		{
+			utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM);
+		}
+	}
+// [/RLVa:KB]
 
 	if (mSessionInitialized)
 	{
diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp
index 10088d20c2353e12f5c97361fac7f4cab68b032f..57a05b42fcfaada163a224376627b2c7d65393d2 100644
--- a/indra/newview/llfloaterinspect.cpp
+++ b/indra/newview/llfloaterinspect.cpp
@@ -42,6 +42,11 @@
 #include "llviewercontrol.h"
 #include "llviewerobject.h"
 #include "lluictrlfactory.h"
+// [RLVa:KB] - Checked: RLVa-2.0.1
+#include "rlvactions.h"
+#include "rlvcommon.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 //LLFloaterInspect* LLFloaterInspect::sInstance = NULL;
 
@@ -101,11 +106,13 @@ void LLFloaterInspect::onOpen(const LLSD& key)
 	mObjectSelection = LLSelectMgr::getInstance()->getSelection();
 	refresh();
 }
-void LLFloaterInspect::onClickCreatorProfile()
+
+// [RLVa:KB] - Checked: RLVa-2.0.1
+const LLSelectNode* LLFloaterInspect::getSelectedNode() /*const*/
 {
 	if(mObjectList->getAllSelected().size() == 0)
 	{
-		return;
+		return NULL;
 	}
 	LLScrollListItem* first_selected =mObjectList->getFirstSelected();
 
@@ -120,32 +127,29 @@ void LLFloaterInspect::onClickCreatorProfile()
 				return (obj_id == node->getObject()->getID());
 			}
 		} func(first_selected->getUUID());
-		LLSelectNode* node = mObjectSelection->getFirstNode(&func);
-		if(node)
-		{
-			LLAvatarActions::showProfile(node->mPermissions->getCreator());
-		}
+		return mObjectSelection->getFirstNode(&func);
 	}
+	return NULL;
 }
 
-void LLFloaterInspect::onClickOwnerProfile()
+void LLFloaterInspect::onClickCreatorProfile()
 {
-	if(mObjectList->getAllSelected().size() == 0) return;
-	LLScrollListItem* first_selected =mObjectList->getFirstSelected();
-
-	if (first_selected)
-	{
-		LLUUID selected_id = first_selected->getUUID();
-		struct f : public LLSelectedNodeFunctor
+		const LLSelectNode* node = getSelectedNode();
+		if(node)
 		{
-			LLUUID obj_id;
-			f(const LLUUID& id) : obj_id(id) {}
-			virtual bool apply(LLSelectNode* node)
+			// Only anonymize the creator if they're also the owner or if they're a nearby avie
+			const LLUUID& idCreator = node->mPermissions->getCreator();
+			if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) && ((node->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator))) )
 			{
-				return (obj_id == node->getObject()->getID());
+				return;
 			}
-		} func(selected_id);
-		LLSelectNode* node = mObjectSelection->getFirstNode(&func);
+			LLAvatarActions::showProfile(idCreator);
+		}
+}
+
+void LLFloaterInspect::onClickOwnerProfile()
+{
+		const LLSelectNode* node = getSelectedNode();
 		if(node)
 		{
 			if(node->mPermissions->isGroupOwned())
@@ -156,21 +160,108 @@ void LLFloaterInspect::onClickOwnerProfile()
 			else
 			{
 				const LLUUID& owner_id = node->mPermissions->getOwner();
+				if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id))
+					return;
 				LLAvatarActions::showProfile(owner_id);
 			}
 
 		}
-	}
 }
 
 void LLFloaterInspect::onSelectObject()
 {
 	if(LLFloaterInspect::getSelectedUUID() != LLUUID::null)
 	{
-		getChildView("button owner")->setEnabled(true);
-		getChildView("button creator")->setEnabled(true);
+		if (!RlvActions::isRlvEnabled())
+		{
+			getChildView("button owner")->setEnabled(true);
+			getChildView("button creator")->setEnabled(true);
+		}
+		else
+		{
+			const LLSelectNode* node = getSelectedNode();
+			const LLUUID& idOwner = (node) ? node->mPermissions->getOwner() : LLUUID::null;
+			const LLUUID& idCreator = (node) ? node->mPermissions->getCreator() : LLUUID::null;
+
+			// See LLFloaterInspect::onClickCreatorProfile()
+			getChildView("button owner")->setEnabled( (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idOwner)) || ((node) && (node->mPermissions->isGroupOwned())) );
+			// See LLFloaterInspect::onClickOwnerProfile()
+			getChildView("button creator")->setEnabled( ((idOwner != idCreator) && (!RlvUtil::isNearbyAgent(idCreator))) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) );
+		}
 	}
 }
+// [/RLVa:KB]
+
+//void LLFloaterInspect::onClickCreatorProfile()
+//{
+//	if(mObjectList->getAllSelected().size() == 0)
+//	{
+//		return;
+//	}
+//	LLScrollListItem* first_selected =mObjectList->getFirstSelected();
+//
+//	if (first_selected)
+//	{
+//		struct f : public LLSelectedNodeFunctor
+//		{
+//			LLUUID obj_id;
+//			f(const LLUUID& id) : obj_id(id) {}
+//			virtual bool apply(LLSelectNode* node)
+//			{
+//				return (obj_id == node->getObject()->getID());
+//			}
+//		} func(first_selected->getUUID());
+//		LLSelectNode* node = mObjectSelection->getFirstNode(&func);
+//		if(node)
+//		{
+//			LLAvatarActions::showProfile(node->mPermissions->getCreator());
+//		}
+//	}
+//}
+
+//void LLFloaterInspect::onClickOwnerProfile()
+//{
+//	if(mObjectList->getAllSelected().size() == 0) return;
+//	LLScrollListItem* first_selected =mObjectList->getFirstSelected();
+//
+//	if (first_selected)
+//	{
+//		LLUUID selected_id = first_selected->getUUID();
+//		struct f : public LLSelectedNodeFunctor
+//		{
+//			LLUUID obj_id;
+//			f(const LLUUID& id) : obj_id(id) {}
+//			virtual bool apply(LLSelectNode* node)
+//			{
+//				return (obj_id == node->getObject()->getID());
+//			}
+//		} func(selected_id);
+//		LLSelectNode* node = mObjectSelection->getFirstNode(&func);
+//		if(node)
+//		{
+//			if(node->mPermissions->isGroupOwned())
+//			{
+//				const LLUUID& idGroup = node->mPermissions->getGroup();
+//				LLGroupActions::show(idGroup);
+//			}
+//			else
+//			{
+//				const LLUUID& owner_id = node->mPermissions->getOwner();
+//				LLAvatarActions::showProfile(owner_id);
+//			}
+//
+//		}
+//	}
+//}
+
+//void LLFloaterInspect::onSelectObject()
+//{
+//	if(LLFloaterInspect::getSelectedUUID() != LLUUID::null)
+//	{
+//		getChildView("button owner")->setEnabled(true);
+//		getChildView("button creator")->setEnabled(true);
+//	}
+//}
 
 LLUUID LLFloaterInspect::getSelectedUUID()
 {
@@ -254,7 +345,11 @@ void LLFloaterInspect::refresh()
 			// actual name and set a placeholder.
 			if (LLAvatarNameCache::get(idOwner, &av_name))
 			{
-				owner_name = av_name.getCompleteName();
+// [RLVa:KB] - Checked: RLVa-2.0.1
+				bool fRlvCanShowName = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idOwner)) || (obj->mPermissions->isGroupOwned());
+				owner_name = (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name);
+// [/RLVa:KB]
+//				owner_name = av_name.getCompleteName();
 			}
 			else
 			{
@@ -269,7 +364,12 @@ void LLFloaterInspect::refresh()
 
 		if (LLAvatarNameCache::get(idCreator, &av_name))
 		{
-			creator_name = av_name.getCompleteName();
+// [RLVa:KB] - Checked: RLVa-2.0.1
+			const LLUUID& idCreator = obj->mPermissions->getCreator();
+			bool fRlvCanShowName = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) || ( (obj->mPermissions->getOwner() != idCreator) && (!RlvUtil::isNearbyAgent(idCreator)) );
+			creator_name = (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name);
+// [/RLVa:KB]
+//			creator_name = av_name.getCompleteName();
 		}
 		else
 		{
diff --git a/indra/newview/llfloaterinspect.h b/indra/newview/llfloaterinspect.h
index 44381eac96f27cf64919fcae7469ba5e9ebb2dd8..7f7f7377f05d02aa8b33429fae4e0f24e7674df8 100644
--- a/indra/newview/llfloaterinspect.h
+++ b/indra/newview/llfloaterinspect.h
@@ -36,6 +36,9 @@
 class LLObjectSelection;
 class LLScrollListCtrl;
 class LLUICtrl;
+// [RLVa:KB] - Checked: RLVa-2.0.1
+class LLSelectNode;
+// [/RLVa:KB]
 
 class LLFloaterInspect : public LLFloater
 {
@@ -61,6 +64,10 @@ class LLFloaterInspect : public LLFloater
 	void setDirty() { mDirty = TRUE; }
 	bool mDirty;
 
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	const LLSelectNode* getSelectedNode() /*const*/;
+// [/RLVa:KB]
+
 private:
 	void onGetOwnerNameCallback();
 	void onGetCreatorNameCallback();
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 36bdcf4d897e89472aad099de8f94e58749df189..760bcefecd4550b7d3501513d8a5629831fdc5c9 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -108,6 +108,10 @@
 #include "llteleporthistorystorage.h"
 #include "llproxy.h"
 #include "llweb.h"
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "lllogininstance.h"        // to check if logged in yet
 #include "llsdserialize.h"
@@ -1239,6 +1243,13 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
 	LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections");
 	LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText");
 
+// [RLVa:KB] - Checked: 2013-05-11 (RLVa-1.4.9)
+	if (rlv_handler_t::isEnabled())
+	{
+		getChild<LLUICtrl>("do_not_disturb_response")->setEnabled(!RlvActions::hasBehaviour(RLV_BHVR_SENDIM));
+	}
+// [/RLVa:KB]
+
 	// Reflections
 	BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") 
 		&& gGLManager.mHasCubeMap
@@ -1282,8 +1293,14 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
 	LLSliderCtrl* terrain_detail = getChild<LLSliderCtrl>("TerrainDetail");   // can be linked with control var
 	LLTextBox* terrain_text = getChild<LLTextBox>("TerrainDetailText");
 
-	ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"));
-	
+//	ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"));
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a
+	// "Basic Shaders" can't be disabled - but can be enabled - under @setenv=n
+	bool fCtrlShaderEnable = LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable");
+	ctrl_shader_enable->setEnabled(
+		fCtrlShaderEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("VertexShaderEnable"))) );
+// [/RLVa:KB]
+
 	BOOL shaders = ctrl_shader_enable->get();
 	if (shaders)
 	{
@@ -1304,7 +1321,13 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState()
 
 	// *HACK just checks to see if we can use shaders... 
 	// maybe some cards that use shaders, but don't support windlight
-	ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders);
+//	ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders);
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a
+	// "Atmospheric Shaders" can't be disabled - but can be enabled - under @setenv=n
+	bool fCtrlWindLightEnable = fCtrlShaderEnable && shaders;
+	ctrl_wind_light->setEnabled(
+		fCtrlWindLightEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))) );
+// [/RLVa:KB]
 
 	sky->setEnabled(ctrl_wind_light->get() && shaders);
 	sky_text->setEnabled(ctrl_wind_light->get() && shaders);
diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp
index 6bfc7807224dcda602d4b6ef060c24832964954f..6a6f14acde80cb60226dbe3f5eb402eb5892fd07 100644
--- a/indra/newview/llfloaterproperties.cpp
+++ b/indra/newview/llfloaterproperties.cpp
@@ -59,6 +59,10 @@
 
 #include "lluictrlfactory.h"
 
+// [RLVa:KB] - Checked: RLVa-2.0.1
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLPropertiesObserver
@@ -279,6 +283,15 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
 		getChildView("BtnCreator")->setEnabled(TRUE);
 		getChildView("LabelCreatorTitle")->setEnabled(TRUE);
 		getChildView("LabelCreatorName")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+		// If the object creator matches the object owner we need to anonymize the creator field as well
+		if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getCreatorUUID())) &&
+		     ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) )
+		{
+			childSetEnabled("BtnCreator", FALSE);
+			name = RlvStrings::getAnonym(name);
+		}
+// [/RLVa:KB]
 		getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
 	}
 	else
@@ -294,6 +307,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
 	////////////////
 	if(perm.isOwned())
 	{
+// [RLVa:KB] - Checked: RVLa-2.0.1
+		bool fRlvCanShowOwner = true;
+// [/RLVa:KB]
 		std::string name;
 		if (perm.isGroupOwned())
 		{
@@ -302,8 +318,19 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
 		else
 		{
 			gCacheName->getFullName(perm.getOwner(), name);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+			if (RlvActions::isRlvEnabled())
+			{
+				fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, perm.getOwner());
+				if (!fRlvCanShowOwner)
+					name = RlvStrings::getAnonym(name);
+			}
+// [/RLVa:KB]
 		}
-		getChildView("BtnOwner")->setEnabled(TRUE);
+//		getChildView("BtnOwner")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+		getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner);
+// [/RLVa:KB]
 		getChildView("LabelOwnerTitle")->setEnabled(TRUE);
 		getChildView("LabelOwnerName")->setEnabled(TRUE);
 		getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
@@ -540,6 +567,17 @@ void LLFloaterProperties::onClickCreator()
 	if(!item) return;
 	if(!item->getCreatorUUID().isNull())
 	{
+// [RLVa:KB] - Checked: RLVa-1.2.1
+		const LLUUID& idCreator = item->getCreatorUUID();
+		if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) )
+		{
+			const LLPermissions& perm = item->getPermissions();
+			if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == idCreator) ) || (RlvUtil::isNearbyAgent(idCreator)) )
+			{
+				return;
+			}
+		}
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getCreatorUUID());
 	}
 }
@@ -555,6 +593,10 @@ void LLFloaterProperties::onClickOwner()
 	}
 	else
 	{
+// [RLVa:KB] - Checked: RLVa-1.0.0
+		if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getPermissions().getOwner())) )
+			return;
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getPermissions().getOwner());
 	}
 }
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index ed6f4ede9f4a6e86ab9abd4090b056f0e36858ac..4c1d4ca98b5f6beedd501259bedbdc52a9b5639a 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -318,6 +318,14 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
 			if (regionp)
 			{
 				getChild<LLUICtrl>("sim_field")->setValue(regionp->getName());
+// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
+/*
+				if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) )
+				{
+					childSetText("sim_field", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+				}
+*/
+// [/RLVa:KB]
 				LLVector3d global_pos;
 				global_pos.setVec(objectp->getPositionRegion());
 				setPosBox(global_pos);
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index fb202b4c406189156a8a0a86de2316aec649156e..d26574b3cc6e5a64cf8828169660330c6dccdc27 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -209,6 +209,20 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
 
 	if (controlp)
 	{
+// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
+		// If "HideFromEditor" was toggled while the floater is open then we need to manually disable access to the control
+		// NOTE: this runs per-frame so there's no need to explictly handle onCommitSettings() or onClickDefault()
+		bool fEnable = !controlp->isHiddenFromSettingsEditor();
+		spinner1->setEnabled(fEnable);
+		spinner2->setEnabled(fEnable);
+		spinner3->setEnabled(fEnable);
+		spinner4->setEnabled(fEnable);
+		color_swatch->setEnabled(fEnable);
+		childSetEnabled("val_text", fEnable);
+		childSetEnabled("boolean_combo", fEnable);
+		childSetEnabled("default_btn", fEnable);
+// [/RLVa:KB]
+
 		eControlType type = controlp->type();
 
 		//hide combo box only for non booleans, otherwise this will result in the combo box closing every frame
diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp
index c7218ad9d59532a3440533b8440ec95b96dc03e5..43f8665eb5c512b94ae5c4ffede2ff83bcf7034b 100644
--- a/indra/newview/llfloatersidepanelcontainer.cpp
+++ b/indra/newview/llfloatersidepanelcontainer.cpp
@@ -39,6 +39,10 @@
 //static
 const std::string LLFloaterSidePanelContainer::sMainPanelName("main_panel");
 
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+LLFloaterSidePanelContainer::validate_signal_t LLFloaterSidePanelContainer::mValidateSignal;
+// [/RLVa:KB]
+
 LLFloaterSidePanelContainer::LLFloaterSidePanelContainer(const LLSD& key, const Params& params)
 :	LLFloater(key, params)
 {
@@ -108,10 +112,25 @@ LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_na
 	return panel;
 }
 
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+bool LLFloaterSidePanelContainer::canShowPanel(const std::string& floater_name, const LLSD& key)
+{
+	return mValidateSignal(floater_name, sMainPanelName, key);
+}
+
+bool LLFloaterSidePanelContainer::canShowPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key)
+{
+	return mValidateSignal(floater_name, panel_name, key);
+}
+// [/RLVa:KB]
+	
 void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, const LLSD& key)
 {
 	LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name);
-	if (floaterp)
+//	if (floaterp)
+// [RLVa:KB] - Checked: 2013-04-16 (RLVa-1.4.8)
+	if ( (floaterp) && ((floaterp->getVisible()) || (LLFloaterReg::canShowInstance(floater_name, key))) && (canShowPanel(floater_name, key)) )
+// [/RLVa:KB]
 	{
 		floaterp->openChildPanel(sMainPanelName, key);
 	}
@@ -120,7 +139,10 @@ void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, con
 void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key)
 {
 	LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name);
-	if (floaterp)
+//	if (floaterp)
+// [RLVa:KB] - Checked: 2013-04-16 (RLVa-1.4.8)
+	if ( (floaterp) && ((floaterp->getVisible()) || (LLFloaterReg::canShowInstance(floater_name, key))) && (canShowPanel(floater_name, panel_name, key)) )
+// [/RLVa:KB]
 	{
 		floaterp->openChildPanel(panel_name, key);
 	}
diff --git a/indra/newview/llfloatersidepanelcontainer.h b/indra/newview/llfloatersidepanelcontainer.h
index d7ecd52e5746d2f432f116002b5b274b9f7da02f..f125bb94611a3f3b8c52f4690991ef727ec666cd 100644
--- a/indra/newview/llfloatersidepanelcontainer.h
+++ b/indra/newview/llfloatersidepanelcontainer.h
@@ -55,6 +55,11 @@ class LLFloaterSidePanelContainer : public LLFloater
 
 	LLPanel* openChildPanel(const std::string& panel_name, const LLSD& params);
 
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	static bool canShowPanel(const std::string& floater_name, const LLSD& key);
+	static bool canShowPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key);
+// [/RLVa:KB]
+	
 	static void showPanel(const std::string& floater_name, const LLSD& key);
 
 	static void showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key);
@@ -78,6 +83,15 @@ class LLFloaterSidePanelContainer : public LLFloater
 		}
 		return panel;
 	}
+	
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	// Used to determine whether a sidepanel can be shown
+public:
+	typedef boost::signals2::signal<bool(const std::string&, const std::string&, const LLSD&), boost_boolean_combiner> validate_signal_t;
+	static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); }
+private:
+	static validate_signal_t mValidateSignal;
+// [/RLVa:KB]
 };
 
 #endif // LL_LLFLOATERSIDEPANELCONTAINER_H
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index c67feb8158ba72f95199cd4d157278911a6dd5fd..6144998ab3182b49b77052d7d6c225281065f8e8 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -76,6 +76,10 @@
 #include "llwindow.h"			// copyTextToClipboard()
 #include <algorithm>
 
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 //---------------------------------------------------------------------------
 // Constants
 //---------------------------------------------------------------------------
@@ -493,6 +497,10 @@ void LLFloaterWorldMap::draw()
 	//	getChildView("Clear")->setEnabled((BOOL)tracking_status);
 	getChildView("Show Destination")->setEnabled((BOOL)tracking_status || LLWorldMap::getInstance()->isTracking());
 	getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) );
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	childSetEnabled("Go Home", 
+		(!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
+// [/RLVa:KB]
 	
 	setMouseOpaque(TRUE);
 	getDragHandle()->setMouseOpaque(TRUE);
@@ -667,7 +675,10 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
 	std::string tooltip("");
 	mTrackedStatus = LLTracker::TRACKING_LOCATION;
 	LLWorldMap::getInstance()->cancelTracking();		// The floater is taking over the tracking
-	LLTracker::trackLocation(pos_global, full_name, tooltip);
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	LLTracker::trackLocation(pos_global, (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? full_name : RlvStrings::getString(RLV_STRING_HIDDEN).c_str(), tooltip);
+// [/RLVa:KB]
+//	LLTracker::trackLocation(pos_global, full_name, tooltip);
 	
 	LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal();
 	updateTeleportCoordsDisplay( coord_pos );
@@ -681,9 +692,25 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
 // enable/disable teleport destination coordinates 
 void LLFloaterWorldMap::enableTeleportCoordsDisplay( bool enabled )
 {
-	childSetEnabled("teleport_coordinate_x", enabled );
-	childSetEnabled("teleport_coordinate_y", enabled );
-	childSetEnabled("teleport_coordinate_z", enabled );
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	LLUICtrl* pCtrl = getChild<LLUICtrl>("events_label");
+	pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+
+	pCtrl = getChild<LLUICtrl>("teleport_coordinate_x");
+	pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+	pCtrl->setEnabled(enabled);
+
+	pCtrl = getChild<LLUICtrl>("teleport_coordinate_y");
+	pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+	pCtrl->setEnabled(enabled);
+
+	pCtrl = getChild<LLUICtrl>("teleport_coordinate_z");
+	pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+	pCtrl->setEnabled(enabled);
+// [/RLVa:KB]
+//	childSetEnabled("teleport_coordinate_x", enabled );
+//	childSetEnabled("teleport_coordinate_y", enabled );
+//	childSetEnabled("teleport_coordinate_z", enabled );
 }
 
 // update display of teleport destination coordinates - pos is in global coordinates
@@ -722,7 +749,22 @@ void LLFloaterWorldMap::updateLocation()
 			// Make sure we know where we are before setting the current user position
 			std::string agent_sim_name;
 			gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( agentPos, agent_sim_name );
-			if ( gotSimName )
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+			{
+				mSetToUserPosition = FALSE;
+
+				// Fill out the location field
+				getChild<LLUICtrl>("location")->setValue(RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+				
+				// update the coordinate display with location of avatar in region
+				updateTeleportCoordsDisplay( agentPos );
+				
+				mSLURL = LLSLURL();
+			}
+			else if (gotSimName)
+// [/RLVa:KB]
+//			if ( gotSimName )
 			{
 				mSetToUserPosition = FALSE;
 				
@@ -767,7 +809,16 @@ void LLFloaterWorldMap::updateLocation()
 		updateTeleportCoordsDisplay( coord_pos );
 		
 		// simNameFromPosGlobal can fail, so don't give the user an invalid SLURL
-		if ( gotSimName )
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+			mSLURL = LLSLURL();
+
+			childSetValue("location", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+		}
+		else if (gotSimName)
+// [/RLVa:KB]
+//		if ( gotSimName )
 		{
 			mSLURL = LLSLURL(sim_name, pos_global);
 		}
diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp
index 950a6cfaef5b053b630bd70f9126baf8cfdcde4f..d22c40922add3d0e3c8d3a46a1fe0868e29485c3 100644
--- a/indra/newview/llgesturemgr.cpp
+++ b/indra/newview/llgesturemgr.cpp
@@ -56,6 +56,10 @@
 #include "llappearancemgr.h"
 #include "llgesturelistener.h"
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+#include "rlvactions.h"
+// [/RLVa:KB]
+
 // Longest time, in seconds, to wait for all animations to stop playing
 const F32 MAX_WAIT_ANIM_SECS = 30.f;
 
@@ -527,6 +531,11 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture)
 {
 	if (!gesture) return;
 
+// [RLVa:KB] - Checked: RLVa-2.0.0 | Handles: @sendgesture
+	if (!RlvActions::canPlayGestures())
+		return;
+// [/RLVa:KB]
+
 	// Reset gesture to first step
 	gesture->mCurrentStep = 0;
 
diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp
index a9bf8a9a508e73ec6b431fdad3ec92089a26de85..eb6df9723d6b0765b513f4cb770ce0711e2669b8 100644
--- a/indra/newview/llgiveinventory.cpp
+++ b/indra/newview/llgiveinventory.cpp
@@ -46,6 +46,12 @@
 #include "llrecentpeople.h"
 #include "llviewerobjectlist.h"
 #include "llvoavatarself.h"
+// [RLVa:KB] - Checked: RLVa-1.2.2
+#include "llavatarnamecache.h"
+#include "rlvactions.h"
+#include "rlvcommon.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
 // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
@@ -317,6 +323,19 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im
 	{
 		gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args);
 	}
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	else if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) && (RlvUtil::isNearbyAgent(to_agent)) && (!RlvUIEnabler::hasOpenProfile(to_agent)) )
+	{
+		// Log to chat history if the user didn't drop on an IM session or a profile to avoid revealing the name of the recipient
+		std::string strMsgName = "inventory_item_offered-im"; LLSD args; LLAvatarName avName;
+		if (LLAvatarNameCache::get(to_agent, &avName))
+		{
+			args["NAME"] = RlvStrings::getAnonym(avName);
+			strMsgName = "inventory_item_offered_rlv";
+		}
+		gIMMgr->addSystemMessage(LLUUID::null, strMsgName, args);
+	}
+// [/RLVa:KB]
 	// If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat.
 	else if (LLIMModel::getInstance()->findIMSession(session_id))
 	{
@@ -424,7 +443,15 @@ void LLGiveInventory::commitGiveInventoryItem(const LLUUID& to_agent,
 	logInventoryOffer(to_agent, im_session_id);
 
 	// add buddy to recent people list
-	LLRecentPeople::instance().add(to_agent);
+//	LLRecentPeople::instance().add(to_agent);
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	// Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile)
+	if ( (!RlvActions::isRlvEnabled()) ||
+	     (RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) || (RlvUIEnabler::hasOpenProfile(to_agent)) )
+	{
+		LLRecentPeople::instance().add(to_agent);
+	}
+// [/RLVa:KB]
 }
 
 // static
@@ -490,7 +517,15 @@ bool LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent,
 		<< cat->getUUID() << LL_ENDL;
 
 	// add buddy to recent people list
-	LLRecentPeople::instance().add(to_agent);
+//	LLRecentPeople::instance().add(to_agent);
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	// Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile)
+	if ( (!RlvActions::isRlvEnabled()) ||
+	     (RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) || (RlvUIEnabler::hasOpenProfile(to_agent)) )
+	{
+		LLRecentPeople::instance().add(to_agent);
+	}
+// [/RLVa:KB]
 
 	// Test out how many items are being given.
 	LLViewerInventoryCategory::cat_array_t cats;
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index c80dec0e75daee1d465b996a18fe2cfd8385e297..841edc94488361808247c1904f72db8883cdf114 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -63,6 +63,11 @@
 #include "pipeline.h"
 #include "llspatialpartition.h"
 #include "llviewershadermgr.h"
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+// [/RLVa:KB]
 
 // Height of the yellow selection highlight posts for land
 const F32 PARCEL_POST_HEIGHT = 0.666f;
@@ -70,6 +75,18 @@ const F32 PARCEL_POST_HEIGHT = 0.666f;
 // Returns true if you got at least one object
 void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 {
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
+	// Block rectangle selection if:
+	//   - prevented from editing and no exceptions are set (see below for the case where exceptions are set)
+	//   - prevented from interacting at all
+	if ( (rlv_handler_t::isEnabled()) && 
+		 ( ((gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!gRlvHandler.hasException(RLV_BHVR_EDIT))) || 
+		   (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) ) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLVector3 av_pos = gAgent.getPositionAgent();
 	F32 select_dist_squared = gSavedSettings.getF32("MaxSelectDistance");
 	select_dist_squared = select_dist_squared * select_dist_squared;
@@ -134,6 +151,29 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 		LLViewerCamera::getInstance()->setFar(new_far);
 		LLViewerCamera::getInstance()->setNear(new_near);
 	}
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0g
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))
+	{
+		static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST);
+
+		// We'll allow drag selection under fartouch, but only within the fartouch range
+		// (just copy/paste the code above us to make that work, thank you Lindens!)
+		LLVector3 relative_av_pos = av_pos;
+		relative_av_pos -= LLViewerCamera::getInstance()->getOrigin();
+
+		F32 new_far = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() + s_nFartouchDist;
+		F32 new_near = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() - s_nFartouchDist;
+
+		new_near = llmax(new_near, 0.1f);
+
+		LLViewerCamera::getInstance()->setFar(new_far);
+		LLViewerCamera::getInstance()->setNear(new_near);
+
+		// Usurp these two
+		limit_select_distance = TRUE;
+		select_dist_squared = s_nFartouchDist * s_nFartouchDist;
+	}
+// [/RLVa:KB]
 	LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, 
 							center_x-width/2, center_y-height/2, width, height, 
 							limit_select_distance);
@@ -208,6 +248,13 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 				continue;
 			}
 
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c
+			if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canEdit(vobjp)) )
+			{
+				continue;
+			}
+// [/RLVa:KB]
+
 			S32 result = LLViewerCamera::getInstance()->sphereInFrustum(drawable->getPositionAgent(), drawable->getRadius());
 			if (result)
 			{
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index 913efd643426aa50e727377a6d9987095cd206ae..73bb8543ee5955467149ade6936574b1bdd4c746 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -41,6 +41,12 @@
 #include "llnotificationsutil.h"
 #include "llstatusbar.h"	// can_afford_transaction()
 #include "groupchatlistener.h"
+// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0)
+#include "llslurl.h"
+#include "rlvactions.h"
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Globals
@@ -205,6 +211,15 @@ void LLGroupActions::startCall(const LLUUID& group_id)
 		return;
 	}
 
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+	if (!RlvActions::canStartIM(group_id))
+	{
+		make_ui_sound("UISndInvalidOp");
+		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
+		return;
+	}
+// [/RLVa:KB]
+
 	LLUUID session_id = gIMMgr->addSession(gdata.mName, IM_SESSION_GROUP_START, group_id, true);
 	if (session_id == LLUUID::null)
 	{
@@ -278,7 +293,10 @@ bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response)
 // static
 void LLGroupActions::leave(const LLUUID& group_id)
 {
-	if (group_id.isNull())
+//	if (group_id.isNull())
+// [RLVa:KB] - Checked: RLVa-1.3.0
+	if ( (group_id.isNull()) || ((gAgent.getGroupID() == group_id) && (!RlvActions::canChangeActiveGroup())) )
+// [/RLVa:KB]
 	{
 		return;
 	}
@@ -330,6 +348,13 @@ void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id)
 // static
 void LLGroupActions::activate(const LLUUID& group_id)
 {
+// [RLVa:KB] - Checked: RLVa-1.3.0
+	if ( (!RlvActions::canChangeActiveGroup()) && (gRlvHandler.getAgentGroup() != group_id) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_ActivateGroup);
 	msg->nextBlockFast(_PREHASH_AgentData);
@@ -426,6 +451,15 @@ LLUUID LLGroupActions::startIM(const LLUUID& group_id)
 {
 	if (group_id.isNull()) return LLUUID::null;
 
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+	if (!RlvActions::canStartIM(group_id))
+	{
+		make_ui_sound("UISndInvalidOp");
+		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
+		return LLUUID::null;
+	}
+// [/RLVa:KB]
+
 	LLGroupData group_data;
 	if (gAgent.getGroupData(group_id, group_data))
 	{
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 6126db2988c98e9e3b7e47310d3e40ffbc7f925d..7343178c10bc34b5c2a66b96f926ae0eb6cd396f 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -43,6 +43,9 @@
 #include "llviewercontrol.h"	// for gSavedSettings
 #include "llviewermenu.h"		// for gMenuHolder
 #include "llvoiceclient.h"
+// [RLVa:KB] - Checked: RLVa-2.0.3
+#include "rlvactions.h"
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLGroupList> r("group_list");
 S32 LLGroupListItem::sIconWidth = 0;
@@ -281,8 +284,14 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata)
 	bool real_group_selected = selected_group_id.notNull(); // a "real" (not "none") group is selected
 
 	// each group including "none" can be activated
+// [RLVa:KB] - Checked: RLVa-1.3.0
 	if (userdata.asString() == "activate")
-		return gAgent.getGroupID() != selected_group_id;
+		return (gAgent.getGroupID() != selected_group_id) && (RlvActions::canChangeActiveGroup());
+	else if (userdata.asString() == "leave")
+		return (real_group_selected) && ((gAgent.getGroupID() != selected_group_id) || (RlvActions::canChangeActiveGroup()));
+// [/RLVa:KB]
+//	if (userdata.asString() == "activate")
+//		return gAgent.getGroupID() != selected_group_id;
 
 	if (userdata.asString() == "call")
 	  return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 52e83fe412c78971a2f729c7e3f200f353ad765b..c35a86fc86b64b540f5258f467b71f81466f75d1 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -46,6 +46,10 @@
 #include "llstatusbar.h"
 #include "llmenugl.h"
 #include "pipeline.h"
+// [RLVa:KB] - Checked: RLVa-1.4.0
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 #include <boost/tokenizer.hpp>
 
 const F32 HORIZONTAL_PADDING = 15.f;
@@ -241,7 +245,32 @@ void LLHUDText::renderText()
 void LLHUDText::setString(const std::string &text_utf8)
 {
 	mTextSegments.clear();
-	addLine(text_utf8, mColor);
+//	addLine(text_utf8, mColor);
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	// NOTE: setString() is called for debug and map beacons as well
+	if (RlvActions::isRlvEnabled())
+	{
+		std::string text(text_utf8);
+		if (gRlvHandler.canShowHoverText(mSourceObject))
+		{
+			if (!RlvActions::canShowLocation())
+				RlvUtil::filterLocation(text);
+
+			bool fCanShowNearby = RlvActions::canShowNearbyAgents();
+			if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) || (!fCanShowNearby) )
+				RlvUtil::filterNames(text, true, !fCanShowNearby);
+		}
+		else
+		{
+			text = "";
+		}
+		addLine(text, mColor);
+	}
+	else
+	{
+		addLine(text_utf8, mColor);
+	}
+// [/RLVa:KB]
 }
 
 void LLHUDText::clearString()
@@ -630,3 +659,17 @@ F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font)
 		return width;
 	}
 }
+
+// [RLVa:KB] - Checked: RLVa-2.0.3
+void LLHUDText::refreshAllObjectText(EObjectTextFilter eObjFilter)
+{
+	for (LLHUDText* pText : sTextObjects)
+	{
+		if ((pText) && (!pText->mObjText.empty()) && (pText->mSourceObject) && (LL_PCODE_VOLUME == pText->mSourceObject->getPCode()) &&
+			((OTF_NONE == eObjFilter) || ((OTF_HUD_ATTACHMENTS == eObjFilter) && (pText->mSourceObject->isHUDAttachment()))))
+		{
+			pText->setString(pText->mObjText);
+		}
+	}
+}
+// [/RLVa:KB]
diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h
index 36015d51f0452fd583757928c388991885403efc..0be9eb4f2e98e5df862285deac1e16b7a7de96af 100644
--- a/indra/newview/llhudtext.h
+++ b/indra/newview/llhudtext.h
@@ -124,6 +124,13 @@ class LLHUDText : public LLHUDObject
 	static void reshape();
 	static void setDisplayText(BOOL flag) { sDisplayText = flag ; }
 
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	const std::string& getObjectText() const						{ return mObjText; }
+	void               setObjectText(const std::string &utf8string)	{ mObjText = utf8string; }
+
+	enum EObjectTextFilter { OTF_NONE, OTF_HUD_ATTACHMENTS };
+	static void        refreshAllObjectText(EObjectTextFilter eObjFilter = OTF_NONE);
+// [/RLVa:KB]
 protected:
 	LLHUDText(const U8 type);
 
@@ -161,6 +168,9 @@ class LLHUDText : public LLHUDObject
 	ETextAlignment	mTextAlignment;
 	EVertAlignment	mVertAlignment;
 	BOOL			mHidden;
+// [RLVa:KB] - Checked: RLVa-1.0.0
+	std::string     mObjText;
+// [/RLVa:KB]
 
 	static BOOL    sDisplayText ;
 	static std::set<LLPointer<LLHUDText> > sTextObjects;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 951389b8568059c8e5473d3b9ba68561bbba059e..94f8d0e8a0ca13fd705ca641f9a3dfd0c21fe122 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -69,7 +69,10 @@
 #include "message.h"
 #include "llviewerregion.h"
 #include "llcorehttputil.h"
-
+// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9)
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 const static std::string ADHOC_NAME_SUFFIX(" Conference");
 
@@ -3612,6 +3615,20 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode
 			{
 				return;
 			}
+// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0)
+			if ( (RlvActions::hasBehaviour(RLV_BHVR_RECVIM)) || (RlvActions::hasBehaviour(RLV_BHVR_RECVIMFROM)) )
+			{
+				if (gAgent.isInGroup(session_id))						// Group chat: don't accept the invite if not an exception
+				{
+					if (!RlvActions::canReceiveIM(session_id))
+						return;
+				}
+				else if (!RlvActions::canReceiveIM(from_id))			// Conference chat: don't block; censor if not an exception
+				{
+					message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM);
+				}
+			}
+// [/RLVa:KB]
 
 			// standard message, not from system
 			std::string saved;
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index 46019557f85f91be6784dd5a4a169eaa15d3264f..30275d44a4f60f819665a2dce1a8db56a3dbacf4 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -38,6 +38,11 @@
 #include "llviewermedia.h"
 #include "llviewermediafocus.h"
 #include "llviewerobjectlist.h"	// to select the requested object
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0c)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "lltoolpie.h"
+// [/RLVa:KB]
 
 // Linden libraries
 #include "llbutton.h"			// setLabel(), not virtual!
@@ -358,6 +363,10 @@ void LLInspectObject::updateButtons(LLSelectNode* nodep)
 		|| (parent && parent->flagHandleTouch()))
 	{
 		getChild<LLUICtrl>("touch_btn")->setVisible(true);
+// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g
+		if (rlv_handler_t::isEnabled())
+			getChild<LLUICtrl>("touch_btn")->setEnabled(gRlvHandler.canTouch(object));
+// [/RLVa:KB]
 		updateTouchLabel(nodep);
 	}
 	else if ( enable_object_open() )
@@ -387,6 +396,15 @@ void LLInspectObject::updateSitLabel(LLSelectNode* nodep)
 	{
 		sit_btn->setLabel( getString("Sit") );
 	}
+
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	// RELEASE-RLVa: [SL-2.0.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLPickInfo& pick = LLToolPie::getInstance()->getPick();
+		sit_btn->setEnabled( (pick.mObjectID.notNull()) && (RlvActions::canSit(pick.getObject(), pick.mObjectOffset)) );
+	}
+// [/RLVa:KB]
 }
 
 void LLInspectObject::updateTouchLabel(LLSelectNode* nodep)
@@ -482,10 +500,15 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)
 		// a clickable link		
 		// Objects cannot be created by a group, so use agent URL format
 		LLUUID creator_id = nodep->mPermissions->getCreator();
-		std::string creator_url =
-			LLSLURL("agent", creator_id, "about").getSLURLString();
+//		std::string creator_url = 
+//			LLSLURL("agent", creator_id, "about").getSLURLString();
+// [RLVa:KB] - Checked: RLVa-1.2.2
+		// Only anonymize the creator if they're also the owner or if they're a nearby avie
+		bool fRlvHideCreator = (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, creator_id)) && ((nodep->mPermissions->getOwner() == creator_id) || (RlvUtil::isNearbyAgent(creator_id)));
+		const std::string creator_url = LLSLURL("agent", creator_id, (!fRlvHideCreator) ? "about" : "rlvanonym").getSLURLString();
+// [/RLVa:KB]
 		args["[CREATOR]"] = creator_url;
-				
+
 		// created by one user but owned by another
 		std::string owner_url;
 		LLUUID owner_id;
@@ -498,7 +521,11 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)
 		else
 		{
 			owner_id = nodep->mPermissions->getOwner();
-			owner_url =	LLSLURL("agent", owner_id, "about").getSLURLString();
+//			owner_url = LLSLURL("agent", owner_id, "about").getSLURLString();
+// [RLVa:KB] - Checked: RLVa-1.2.2
+			bool fRlvHideOwner = (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id));
+			owner_url = LLSLURL("agent", owner_id, (!fRlvHideOwner) ? "about" : "rlvanonym").getSLURLString();
+// [/RLVa:KB]
 		}
 		args["[OWNER]"] = owner_url;
 		
diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp
index b64df2bd47176affd6fcfc24bb7de8f2f3c24d1f..079975b8c7ecffccf27ca1890c0b189b4fa97310 100644
--- a/indra/newview/llinspectremoteobject.cpp
+++ b/indra/newview/llinspectremoteobject.cpp
@@ -35,6 +35,9 @@
 #include "llui.h"
 #include "lluictrl.h"
 #include "llurlaction.h"
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //////////////////////////////////////////////////////////////////////////////
 // LLInspectRemoteObject
@@ -66,6 +69,9 @@ class LLInspectRemoteObject : public LLInspect
 	LLUUID		 mOwnerID;
 	std::string  mSLurl;
 	std::string  mName;
+// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+	bool         mRlvHideNames;
+// [/RLVa:KB]
 	bool         mGroupOwned;
 };
 
@@ -75,6 +81,9 @@ LLInspectRemoteObject::LLInspectRemoteObject(const LLSD& sd) :
 	mOwnerID(NULL),
 	mSLurl(""),
 	mName(""),
+// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+	mRlvHideNames(false),
+// [/RLVa:KB]
 	mGroupOwned(false)
 {
 }
@@ -107,6 +116,10 @@ void LLInspectRemoteObject::onOpen(const LLSD& data)
 	mOwnerID    = data["owner_id"].asUUID();
 	mGroupOwned = data["group_owned"].asBoolean();
 	mSLurl      = data["slurl"].asString();
+// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+	if (data.has("rlv_shownames"))
+		mRlvHideNames = data["rlv_shownames"].asBoolean();
+// [/RLVa:KB]
 
 	// update the inspector with the current object state
 	update();
@@ -160,7 +173,10 @@ void LLInspectRemoteObject::update()
 		}
 		else
 		{
-			owner = LLSLURL("agent", mOwnerID, "about").getSLURLString();
+//			owner = LLSLURL("agent", mOwnerID, "about").getSLURLString();
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+			owner = LLSLURL("agent", mOwnerID, (!mRlvHideNames) ? "about" : "rlvanonym").getSLURLString();
+// [/RLVa:KB]
 		}
 	}
 	else
@@ -182,6 +198,14 @@ void LLInspectRemoteObject::update()
 
 	// disable the Block button if we don't have the object ID (will this ever happen?)
 	getChild<LLUICtrl>("block_btn")->setEnabled(!mObjectID.isNull() && !LLMuteList::getInstance()->isMuted(mObjectID));
+
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	if ( (rlv_handler_t::isEnabled()) && (RlvStrings::getString(RLV_STRING_HIDDEN_REGION) == mSLurl) )
+	{
+		getChild<LLUICtrl>("object_slurl")->setValue(mSLurl);
+		getChild<LLUICtrl>("map_btn")->setEnabled(false);
+	}
+// [/RLVa:KB]
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 0a5ff566055db47b5da75a06b759461df2c3133e..b08c6fd21a4046699641db7016240a7f79ef9a82 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -79,6 +79,11 @@
 #include "llwearableitemslist.h"
 #include "lllandmarkactions.h"
 #include "llpanellandmarks.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 #include <boost/shared_ptr.hpp>
 
@@ -842,6 +847,20 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 		addOpenRightClickMenuOption(items);
 		items.push_back(std::string("Properties"));
 
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a
+		if (rlv_handler_t::isEnabled())
+		{
+			const LLInventoryObject* pItem = getInventoryObject();
+			if ( (pItem) &&
+				 ( ((LLAssetType::AT_NOTECARD == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE))) ||
+				   ((LLAssetType::AT_LSL_TEXT == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT))) ||
+				   ((LLAssetType::AT_TEXTURE == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE))) ) )
+			{
+				disabled_items.push_back(std::string("Open"));
+			}
+		}
+// [/RLVa:KB]
+
 		getClipboardEntries(true, items, disabled_items, flags);
 	}
 	hide_context_entries(menu, items, disabled_items);
@@ -1892,6 +1911,13 @@ BOOL LLItemBridge::isItemRenameable() const
 			return FALSE;
 		}
 
+// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+		if ( (rlv_handler_t::isEnabled()) && (!RlvFolderLocks::instance().canRenameItem(mUUID)) )
+		{
+			return FALSE;
+		}
+// [/RLVa:KB]
+
 		return (item->getPermissions().allowModifyBy(gAgent.getID()));
 	}
 	return FALSE;
@@ -2528,6 +2554,14 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
 				}
 			}
 		}
+
+// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+		if ( (is_movable) && (rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) )
+		{
+			is_movable = RlvFolderLocks::instance().canMoveFolder(cat_id, mUUID);
+		}
+// [/RLVa:KB]
+
 		// 
 		//--------------------------------------------------------------------------------
 
@@ -3962,6 +3996,13 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
 		{
 			disabled_items.push_back(std::string("Replace Outfit"));
 		}
+// [RLVa:KB] - Checked: RLVa-2.0.3
+		// Block "Replace Current Outfit" if the user can't wear the new folder
+		if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(mUUID, RLV_LOCK_ADD)) )
+		{
+			disabled_items.push_back(std::string("Replace Outfit"));
+		}
+// [/RLVa:KB]
 		if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID))
 		{
 			disabled_items.push_back(std::string("Add To Outfit"));
@@ -4547,6 +4588,24 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 		{
 			is_movable = FALSE;
 		}
+		
+// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+		if ( (rlv_handler_t::isEnabled()) && (is_movable) )
+		{
+			if (move_is_into_current_outfit)
+			{
+				// RELEASE-RLVa: [RLVa-1.3.0] Keep sync'ed with code below => LLAppearanceMgr::wearItemOnAvatar() with "replace == true"
+				const LLViewerInventoryItem* pItem = dynamic_cast<const LLViewerInventoryItem*>(inv_item);
+				is_movable = rlvPredCanWearItem(pItem, RLV_WEAR_REPLACE);
+			}
+			if (is_movable)
+			{
+				is_movable = (!RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) || 
+					(RlvFolderLocks::instance().canMoveItem(inv_item->getUUID(), mUUID));
+			}
+		}
+// [/RLVa:KB]
+
 		if (move_is_into_trash)
 		{
 			is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID());
@@ -5360,6 +5419,16 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act
 			{
 				callingcard_name = av_name.getCompleteName();
 			}
+
+// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
+			if (!RlvActions::canStartIM(item->getCreatorUUID()))
+			{
+				make_ui_sound("UISndInvalidOp");
+				RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", item->getCreatorUUID(), "completename").getSLURLString()));
+				return;
+			}
+// [/RLVa:KB]
+
 			LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID());
 			if (session_id != LLUUID::null)
 			{
@@ -5969,6 +6038,21 @@ std::string LLObjectBridge::getLabelSuffix() const
 
 void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace)
 {
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1)
+	// If no attachment point was specified, try looking it up from the item name
+	static LLCachedControl<bool> fRlvDeprecateAttachPt(gSavedSettings, "RLVaDebugDeprecateExplicitPoint", false);
+	if ( (rlv_handler_t::isEnabled()) && (!fRlvDeprecateAttachPt) && 
+	     (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+	{
+		attachment = RlvAttachPtLookup::getAttachPoint(item);
+	}
+
+	if ( (RlvActions::isRlvEnabled()) && (!rlvPredCanWearItem(item, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	const LLUUID& item_id = item->getLinkedUUID();
 
 	// Check for duplicate request.
@@ -6001,10 +6085,24 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach
 	if (replace &&
 		(attachment && attachment->getNumObjects() > 0))
 	{
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1)
+		// Block if we can't "replace wear" what's currently there
+		if ( (rlv_handler_t::isEnabled()) && ((gRlvAttachmentLocks.canAttach(attachment) & RLV_WEAR_REPLACE) == 0) )
+		{
+			return;
+		}
+// [/RLVa:KB]
 		LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez);
 	}
 	else
 	{
+// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0)
+		// Block wearing anything on a non-attachable attachment point
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachmentPoint(attach_pt, RLV_LOCK_ADD)) )
+		{
+			return;
+		}
+// [/RLVa:KB]
 		LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);
 	}
 }
@@ -6078,6 +6176,10 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 			{
 				items.push_back(std::string("Wearable And Object Separator"));
 				items.push_back(std::string("Detach From Yourself"));
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+				if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canDetach(item)) )
+					disabled_items.push_back(std::string("Detach From Yourself"));
+// [/RLVa:KB]
 			}
 			else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder())
 			{
@@ -6096,6 +6198,17 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 					disabled_items.push_back(std::string("Attach To"));
 					disabled_items.push_back(std::string("Attach To HUD"));
 				}
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+				else if (rlv_handler_t::isEnabled())
+				{
+					ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(item);
+					if ((eWearMask & RLV_WEAR_REPLACE) == 0)
+						disabled_items.push_back(std::string("Wearable And Object Wear"));
+					if ((eWearMask & RLV_WEAR_ADD) == 0)
+						disabled_items.push_back(std::string("Wearable Add"));
+				}
+// [/RLVa:KB]
+
 				LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE);
 				LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE);
 				if (attach_menu
@@ -6340,18 +6453,36 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 					{
 						disabled_items.push_back(std::string("Wearable And Object Wear"));
 						disabled_items.push_back(std::string("Wearable Add"));
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Added: RLVa-1.2.0c
+						if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) )
+							disabled_items.push_back(std::string("Take Off"));
+// [/RLVa:KB]
 					}
 					else
 					{
 						items.push_back(std::string("Wearable And Object Wear"));
 						disabled_items.push_back(std::string("Take Off"));
 						disabled_items.push_back(std::string("Wearable Edit"));
+
+// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+						if (rlv_handler_t::isEnabled())
+						{
+							ERlvWearMask eWearMask = gRlvWearableLocks.canWear(item);
+							if ((eWearMask & RLV_WEAR_REPLACE) == 0)
+								disabled_items.push_back(std::string("Wearable And Object Wear"));
+							if ((eWearMask & RLV_WEAR_ADD) == 0)
+								disabled_items.push_back(std::string("Wearable Add"));
+						}
+// [/RLVa:KB]
 					}
 
 					if (LLWearableType::getAllowMultiwear(mWearableType))
 					{
 						items.push_back(std::string("Wearable Add"));
-						if (!gAgentWearables.canAddWearable(mWearableType))
+//						if (!gAgentWearables.canAddWearable(mWearableType))
+// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e
+						if ( (!gAgentWearables.canAddWearable(mWearableType)) || (gAgentWearables.getWearableFromAssetID(item->getAssetUUID())) )
+// [/SL:KB]
 						{
 							disabled_items.push_back(std::string("Wearable Add"));
 						}
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 851d92f23ec2acbfbe3c35975f079909023be770..d11a7ea98741e1b459a2b015bfa55edb5ffef8f5 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -86,6 +86,10 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llwearablelist.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 #include <boost/foreach.hpp>
 
@@ -628,6 +632,14 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id)
 		}
 	}
 
+// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+	if ( (rlv_handler_t::isEnabled()) && 
+		 (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveItem(id)) )
+	{
+		return FALSE;
+	}
+// [/RLVa:KB]
+
 	const LLInventoryObject *obj = model->getItem(id);
 	if (obj && obj->getIsLinkType())
 	{
@@ -656,6 +668,14 @@ BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id)
 		return FALSE;
 	}
 
+// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+	if ( ((rlv_handler_t::isEnabled()) && 
+		 (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveFolder(id))) )
+	{
+		return FALSE;
+	}
+// [/RLVa:KB]
+
 	if (!isAgentAvatarValid()) return FALSE;
 
 	const LLInventoryCategory* category = model->getCategory(id);
@@ -691,6 +711,13 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
 		return FALSE;
 	}
 
+// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+	if ( (rlv_handler_t::isEnabled()) && (model == &gInventory) && (!RlvFolderLocks::instance().canRenameFolder(id)) )
+	{
+		return FALSE;
+	}
+// [/RLVa:KB]
+
 	LLViewerInventoryCategory* cat = model->getCategory(id);
 
 	if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) &&
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 9a33e210ff3352128e92a2a7af79aee05f82244b..b7121caaadb14871d940d7d0ea0bedb4bda55ce1 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -58,6 +58,10 @@
 #include "bufferarray.h"
 #include "bufferstream.h"
 #include "llcorehttputil.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 //#define DIFF_INVENTORY_FILES
 #ifdef DIFF_INVENTORY_FILES
@@ -715,11 +719,19 @@ void LLInventoryModel::collectDescendents(const LLUUID& id,
 	collectDescendentsIf(id, cats, items, include_trash, always);
 }
 
+//void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
+//											cat_array_t& cats,
+//											item_array_t& items,
+//											BOOL include_trash,
+//											LLInventoryCollectFunctor& add)
+// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8)
 void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
 											cat_array_t& cats,
 											item_array_t& items,
 											BOOL include_trash,
-											LLInventoryCollectFunctor& add)
+											LLInventoryCollectFunctor& add,
+											bool follow_folder_links)
+// [/RLVa:KB]
 {
 	// Start with categories
 	if(!include_trash)
@@ -739,7 +751,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
 			{
 				cats.push_back(cat);
 			}
-			collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add);
+// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8)
+			collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add, follow_folder_links);
+// [/RLVa:KB]
+//			collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add);
 		}
 	}
 
@@ -759,6 +774,44 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
 			}
 		}
 	}
+
+// [RLVa:KB] - Checked: 2010-09-30 (RLVa-1.2.1d) | Added: RLVa-1.2.1d
+	// The problem is that we want some way for the functor to know that it's being asked to decide on a folder link
+	// but it won't know that until after it has encountered the folder link item (which doesn't happen until *after* 
+	// it has already collected all items from it the way the code was originally laid out)
+	// This breaks the "finish collecting all folders before collecting items (top to bottom and then bottom to top)" 
+	// assumption but no functor is (currently) relying on it (and likely never should since it's an implementation detail?)
+	// [Only LLAppearanceMgr actually ever passes in 'follow_folder_links == TRUE']
+	// Follow folder links recursively.  Currently never goes more
+	// than one level deep (for current outfit support)
+	// Note: if making it fully recursive, need more checking against infinite loops.
+	if (follow_folder_links && item_array)
+	{
+		S32 count = item_array->size();
+		for(S32 i = 0; i < count; ++i)
+		{
+			item = item_array->at(i);
+			if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER)
+			{
+				LLViewerInventoryCategory *linked_cat = item->getLinkedCategory();
+				if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT)
+					// BAP - was 
+					// LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType()))
+					// Change back once ensemble typing is in place.
+				{
+					if(add(linked_cat,NULL))
+					{
+						// BAP should this be added here?  May not
+						// matter if it's only being used in current
+						// outfit traversal.
+						cats.push_back(LLPointer<LLViewerInventoryCategory>(linked_cat));
+					}
+					collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, false);
+				}
+			}
+		}
+	}
+// [/RLVa:KB]
 }
 
 U32 LLInventoryModel::getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit)
@@ -3024,6 +3077,14 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg,
 		LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item"
 			" not found: " << item_id << LL_ENDL;
 	}
+
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-0.2.0e
+	if (rlv_handler_t::isEnabled())
+	{
+		RlvAttachmentLockWatchdog::instance().onSavedAssetIntoInventory(item_id);
+	}
+// [/RLVa:KB]
+
 	if(gViewerWindow)
 	{
 		gViewerWindow->getWindow()->decBusyCount();
@@ -3085,6 +3146,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 			{
 				if(tfolder->getParentUUID() == folderp->getParentUUID())
 				{
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+					// NOTE-RLVa: not sure if this is a hack or a bug-fix :o
+					//		-> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain
+					//         the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the
+					//         viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server
+					//      -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues
+					//		-> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem
+					//		   to be any way to accomplish that either *sighs*
+					if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) &&
+						 ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) )
+					{
+						tfolder->rename(folderp->getName());
+					}
+// [/RLVa:KB]
 					update[tfolder->getParentUUID()];
 				}
 				else
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 826d1f880d76db5c845450e46f3808d49637df6c..9c7a68ca4d9d7d6d2ff7a20e03ba5aed96db1227 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -249,11 +249,19 @@ class LLInventoryModel
 							cat_array_t& categories,
 							item_array_t& items,
 							BOOL include_trash);
+// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8)
 	void collectDescendentsIf(const LLUUID& id,
 							  cat_array_t& categories,
 							  item_array_t& items,
 							  BOOL include_trash,
-							  LLInventoryCollectFunctor& add);
+							  LLInventoryCollectFunctor& add,
+							  bool follow_folder_links = false);
+// [/RLVa:KB]
+//	void collectDescendentsIf(const LLUUID& id,
+//							  cat_array_t& categories,
+//							  item_array_t& items,
+//							  BOOL include_trash,
+//							  LLInventoryCollectFunctor& add);
 
 	// Collect all items in inventory that are linked to item_id.
 	// Assumes item_id is itself not a linked item.
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index f5dcbf838daf7dcbebecbe5b51e5f4b1460b31a7..100052d04bb2786121f56e421c602aecb4ffe9f7 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -50,6 +50,10 @@
 #include "llviewerattachmenu.h"
 #include "llviewerfoldertype.h"
 #include "llvoavatarself.h"
+// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel");
 
@@ -1105,7 +1109,11 @@ bool LLInventoryPanel::beginIMSession()
 	std::string name;
 
 	std::vector<LLUUID> members;
-	EInstantMessage type = IM_SESSION_CONFERENCE_START;
+//	EInstantMessage type = IM_SESSION_CONFERENCE_START;
+
+// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
+	bool fRlvCanStartIM = true;
+// [/RLVa:KB]
 
 	std::set<LLFolderViewItem*>::const_iterator iter;
 	for (iter = selected_items.begin(); iter != selected_items.end(); iter++)
@@ -1144,10 +1152,17 @@ bool LLInventoryPanel::beginIMSession()
 					for(S32 i = 0; i < count; ++i)
 					{
 						id = item_array.at(i)->getCreatorUUID();
-						if(at.isBuddyOnline(id))
+// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
+						if ( (at.isBuddyOnline(id)) && (members.end() == std::find(members.begin(), members.end(), id)) )
 						{
+							fRlvCanStartIM &= RlvActions::canStartIM(id);
 							members.push_back(id);
 						}
+// [/RLVa:KB]
+//						if(at.isBuddyOnline(id))
+//						{
+//							members.push_back(id);
+//						}
 					}
 				}
 			}
@@ -1164,10 +1179,17 @@ bool LLInventoryPanel::beginIMSession()
 						LLAvatarTracker& at = LLAvatarTracker::instance();
 						LLUUID id = inv_item->getCreatorUUID();
 
-						if(at.isBuddyOnline(id))
+// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
+						if ( (at.isBuddyOnline(id)) && (members.end() == std::find(members.begin(), members.end(), id)) )
 						{
+							fRlvCanStartIM &= RlvActions::canStartIM(id);
 							members.push_back(id);
 						}
+// [/RLVa:KB]
+//						if(at.isBuddyOnline(id))
+//						{
+//							members.push_back(id);
+//						}
 					}
 				} //if IT_CALLINGCARD
 			} //if !IT_CATEGORY
@@ -1177,16 +1199,34 @@ bool LLInventoryPanel::beginIMSession()
 	// the session_id is randomly generated UUID which will be replaced later
 	// with a server side generated number
 
+// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
+	if (!fRlvCanStartIM)
+	{
+		make_ui_sound("UISndInvalidOp");
+		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
+		return true;
+	}
+// [/RLVa:KB]
+
 	if (name.empty())
 	{
 		name = LLTrans::getString("conference-title");
 	}
 
-	LLUUID session_id = gIMMgr->addSession(name, type, members[0], members);
-	if (session_id != LLUUID::null)
+// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
+	if (!members.empty())
 	{
-		LLFloaterIMContainer::getInstance()->showConversation(session_id);
+		if (members.size() > 1)
+			LLAvatarActions::startConference(members);
+		else
+			LLAvatarActions::startIM(members[0]);
 	}
+// [/RLVa:KB]
+//	LLUUID session_id = gIMMgr->addSession(name, type, members[0], members);
+//	if (session_id != LLUUID::null)
+//	{
+//		LLFloaterIMContainer::getInstance()->showConversation(session_id);
+//	}
 		
 	return true;
 }
@@ -1274,8 +1314,11 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
 			active_inv_floaterp->setMinimized(FALSE);
 		}
 	}	
-	else if (auto_open)
+//	else if (auto_open)
+// [RLVa:KB] - Checked: 2012-05-15 (RLVa-1.4.6)
+	else if ( (auto_open) && (LLFloaterReg::canShowInstance(floater_inventory->getInstanceName())) )
 	{
+// [/RLVa:KB]
 		floater_inventory->openFloater();
 
 		res = inventory_panel->getActivePanel();
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 53b2ca2b74a12b4ea241778edb37897409b8d3a5..cdaa6c007dfce2aec20d8e74ea59f25a2c5a5b68 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -63,6 +63,9 @@
 #include "llviewermenu.h"
 #include "llurllineeditorctrl.h"
 #include "llagentui.h"
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "llmenuoptionpathfindingrebakenavmesh.h"
 #include "llpathfindingmanager.h"
@@ -633,16 +636,31 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent
 
 void LLLocationInputCtrl::onInfoButtonClicked()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		return;
+// [/RLVa:KB]
+
 	LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent"));
 }
 
 void LLLocationInputCtrl::onForSaleButtonClicked()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		return;
+// [/RLVa:KB]
+
 	handle_buy_land();
 }
 
 void LLLocationInputCtrl::onAddLandmarkButtonClicked()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		return;
+// [/RLVa:KB]
+
 	LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
 	// Landmark exists, open it for preview and edit
 	if(landmark && landmark->getUUID().notNull())
@@ -770,6 +788,10 @@ void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask)
 
 void LLLocationInputCtrl::refresh()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0
+	mInfoBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
+
 	refreshLocation();			// update location string
 	refreshParcelIcons();
 	updateAddLandmarkButton();	// indicate whether current parcel has been landmarked 
@@ -1047,6 +1069,9 @@ void LLLocationInputCtrl::enableAddLandmarkButton(bool val)
 // depending on whether current parcel has been landmarked.
 void LLLocationInputCtrl::updateAddLandmarkButton()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0
+	mAddLandmarkBtn->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
 	enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark());
 }
 void LLLocationInputCtrl::updateAddLandmarkTooltip()
@@ -1076,6 +1101,9 @@ void LLLocationInputCtrl::updateContextMenu(){
 		{
 			landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
 		}
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0
+		landmarkItem->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
 	}
 }
 void LLLocationInputCtrl::updateWidgetlayout()
@@ -1131,17 +1159,23 @@ void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata)
 	}
 	else if (item == "landmark")
 	{
-		LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
-		
-		if(!landmark)
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
 		{
-			LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
-		}
-		else
-		{
-			LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID()));
-
+// [/RLVa:KB]
+			LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
+			
+			if(!landmark)
+			{
+				LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
+			}
+			else
+			{
+				LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID()));
+			}
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
 		}
+// [/RLVa:KB]
 	}
 	else if (item == "cut")
 	{
diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h
index da71bab6c1bddc09030ae4f1588f97da072e98b7..1c4adb9e8fc5810facf74d1bead63311a9e1616c 100644
--- a/indra/newview/lllocationinputctrl.h
+++ b/indra/newview/lllocationinputctrl.h
@@ -109,6 +109,10 @@ class LLLocationInputCtrl
 	LLLineEditor*			getTextEntry() const { return mTextEntry; }
 	void					handleLoginComplete();
 
+// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10)
+	void					refresh();
+// [/RLVa:KB]
+
 private:
 
 	enum EParcelIcon
@@ -135,7 +139,7 @@ class LLLocationInputCtrl
 	 * depending on whether current parcel has been landmarked.
 	 */
 	void					enableAddLandmarkButton(bool val);
-	void					refresh();
+//	void					refresh();
 	void					refreshLocation();
 	void					refreshParcelIcons();
 	// Refresh the value in the health percentage text field
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index b4259a456cc1e773ee58c2a49b99d99510a64da3..8dfc42c819ac2081f093fb9cf2628a5abda36a73 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -62,6 +62,9 @@
 #include "pipeline.h"
 #include "llviewershadermgr.h"
 #include "lltrans.h"
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 const S32 NUM_AXES = 3;
 const S32 MOUSE_DRAG_SLOP = 2;       // pixels
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 70035bcc74eff63f30436bbd7473a1d4786142b4..ae7d0d4c0b6e2822616141a6b9313235e3579126 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -50,6 +50,9 @@
 #include "llviewerparcelmgr.h"
 #include "llviewerregion.h"
 #include "lltooltip.h"
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c)
+#include "rlvactions.h"
+// [/RLVa:KB]
 
 //
 // Constants
@@ -140,7 +143,10 @@ BOOL LLFloaterMove::postBuild()
 
 	initMovementMode();
 
-	gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateFlyingStatus);
+//	gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateFlyingStatus);
+// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+	gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateMovementStatus);
+// [/RLVa:KB]
 
 	return TRUE;
 }
@@ -325,23 +331,32 @@ void LLFloaterMove::setMovementMode(const EMovementMode mode)
 	{
 	case MM_RUN:
 		gAgent.setAlwaysRun();
-		gAgent.setRunning();
+//		gAgent.setRunning();
 		break;
 	case MM_WALK:
 		gAgent.clearAlwaysRun();
-		gAgent.clearRunning();
+//		gAgent.clearRunning();
 		break;
 	default:
 		//do nothing for other modes (MM_FLY)
 		break;
 	}
 	// tell the simulator.
-	gAgent.sendWalkRun(gAgent.getAlwaysRun());
-	
-	updateButtonsWithMovementMode(mode);
+//	gAgent.sendWalkRun(gAgent.getAlwaysRun());
+//	
+//	updateButtonsWithMovementMode(mode);
+//
+//	bool bHideModeButtons = MM_FLY == mode
+//		|| (isAgentAvatarValid() && gAgentAvatarp->isSitting());
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+	// Running may have been restricted so update walk-vs-run from the agent's actual running state
+	if ( (MM_WALK == mode) || (MM_RUN == mode) )
+		mCurrentMode = (gAgent.getRunning()) ? MM_RUN : MM_WALK;
 
-	bool bHideModeButtons = MM_FLY == mode
-		|| (isAgentAvatarValid() && gAgentAvatarp->isSitting());
+	updateButtonsWithMovementMode(mCurrentMode);
+
+	bool bHideModeButtons = (MM_FLY == mCurrentMode) || (isAgentAvatarValid() && gAgentAvatarp->isSitting());
+// [/RLVa:KB]
 
 	showModeButtons(!bHideModeButtons);
 
@@ -444,12 +459,23 @@ void LLFloaterMove::setModeTitle(const EMovementMode mode)
 }
 
 //static
-void LLFloaterMove::sUpdateFlyingStatus()
+//void LLFloaterMove::sUpdateFlyingStatus()
+//{
+//	LLFloaterMove *floater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview");
+//	if (floater) floater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly());
+//	
+//}
+// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+void LLFloaterMove::sUpdateMovementStatus()
 {
-	LLFloaterMove *floater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview");
-	if (floater) floater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly());
-	
+	LLFloaterMove* pFloater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview");
+	if (pFloater)
+	{
+		pFloater->mModeControlButtonMap[MM_RUN]->setEnabled(!RlvActions::hasBehaviour(RLV_BHVR_ALWAYSRUN));
+		pFloater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly());
+	}
 }
+// [/RLVa:KB]
 
 void LLFloaterMove::showModeButtons(BOOL bShow)
 {
@@ -489,7 +515,10 @@ void LLFloaterMove::onOpen(const LLSD& key)
 		showModeButtons(FALSE);
 	}
 
-	sUpdateFlyingStatus();
+//	sUpdateFlyingStatus();
+// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+	sUpdateMovementStatus();
+// [/RLVa:KB]
 }
 
 void LLFloaterMove::setModeButtonToggleState(const EMovementMode mode)
@@ -680,10 +709,17 @@ LLPanelStandStopFlying* LLPanelStandStopFlying::getStandStopFlyingPanel()
 
 void LLPanelStandStopFlying::onStandButtonClick()
 {
-	LLFirstUse::sit(false);
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	if ( (!RlvActions::isRlvEnabled()) || (RlvActions::canStand()) )
+	{
+		LLFirstUse::sit(false);
 
-	LLSelectMgr::getInstance()->deselectAllForStandingUp();
-	gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+		LLSelectMgr::getInstance()->deselectAllForStandingUp();
+		gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+	}
+// [/RLVa:KB]
+//	LLSelectMgr::getInstance()->deselectAllForStandingUp();
+//	gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
 
 	setFocus(FALSE); // EXT-482
 	mStandButton->setVisible(FALSE); // force visibility changing to avoid seeing Stand & Move buttons at once.
diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h
index c525d9dfdb6580d1c5bb1ea62c89fe01a3840cb1..6f42db76a9dbab95aa4a399ba5bba462c0817cc7 100644
--- a/indra/newview/llmoveview.h
+++ b/indra/newview/llmoveview.h
@@ -59,7 +59,10 @@ class LLFloaterMove
 	static void enableInstance(BOOL bEnable);
 	/*virtual*/ void onOpen(const LLSD& key);
 
-	static void sUpdateFlyingStatus();
+//	static void sUpdateFlyingStatus();
+// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+	static void sUpdateMovementStatus();
+// [/RLVa:KB]
 
 protected:
 	void turnLeft();
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index 84a2cd8be103559f488b4446a965209e51021764..06faa9a47403ad41e7c03042b38e5e77d31e86d6 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -699,6 +699,15 @@ void LLNavigationBar::resizeLayoutPanel()
 	nav_bar_rect.setLeftTopAndSize(nav_bar_rect.mLeft, nav_bar_rect.mTop, nav_panel_width, nav_bar_rect.getHeight());
 	mNavigationPanel->handleReshape(nav_bar_rect,true);
 }
+
+// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10)
+void LLNavigationBar::refreshLocationCtrl()
+{
+	if (mCmbLocation)
+		mCmbLocation->refresh();
+}
+// [/RLVa:KB]
+
 void LLNavigationBar::invokeSearch(std::string search_text)
 {
 	LLFloaterReg::showInstance("search", LLSD().with("category", "all").with("query", LLSD(search_text)));
diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h
index 29dbaedf7af9c2f63b0add0d058db42614a4a169..382fd0c38446f03a7499900d2caae4a562d2c7b4 100644
--- a/indra/newview/llnavigationbar.h
+++ b/indra/newview/llnavigationbar.h
@@ -102,6 +102,9 @@ class LLNavigationBar
 	int getDefNavBarHeight();
 	int getDefFavBarHeight();
 	
+// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10)
+	void refreshLocationCtrl();
+// [/RLVa:KB]
 private:
 	// the distance between navigation panel and favorites panel in pixels
 	const static S32 FAVBAR_TOP_PADDING = 10;
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 5fc73c67d1bfbbf4c17c1f0464bdfbe096274a51..05d5cb8ffe5cb051a5b5599ac2dc1c5edebcbe59 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -60,6 +60,10 @@
 #include "llviewerwindow.h"
 #include "llworld.h"
 #include "llworldmapview.h"		// shared draw code
+// [RLVa:KB] - Checked: RLVa-2.0.1
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map");
 
@@ -350,7 +354,10 @@ void LLNetMap::draw()
 
 			pos_map = globalPosToView(positions[i]);
 
-			bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
+// [RLVa:KB] - Checked: RLVa-1.2.0
+			bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, uuid));
+// [/RLVa:KB]
+//			bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
 
 			LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color;
 
@@ -602,11 +609,20 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
 
 	// If the cursor is near an avatar on the minimap, a mini-inspector will be
 	// shown for the avatar, instead of the normal map tooltip.
-	if (handleToolTipAgent(mClosestAgentToCursor))
+//	if (handleToolTipAgent(mClosestAgentToCursor))
+// [RLVa:KB] - Checked: RLVa-1.2.2
+	bool fRlvCanShowName = (mClosestAgentToCursor.notNull()) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mClosestAgentToCursor));
+	if ( (fRlvCanShowName) && (handleToolTipAgent(mClosestAgentToCursor)) )
+// [/RLVa:KB]
 	{
 		return TRUE;
 	}
 
+// [RLVa:KB] - Checked: RLVa-1.2.2
+	LLStringUtil::format_map_t args; LLAvatarName avName;
+	args["[AGENT]"] = ( (!fRlvCanShowName) && (mClosestAgentToCursor.notNull()) && (LLAvatarNameCache::get(mClosestAgentToCursor, &avName)) ) ? RlvStrings::getAnonym(avName) + "\n" : "";
+// [/RLVa:KB]
+
 	LLRect sticky_rect;
 	std::string region_name;
 	LLViewerRegion*	region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
@@ -618,14 +634,17 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
 		sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP;
 		sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP;
 
-		region_name = region->getName();
+//		region_name = region->getName();
+// [RLVa:KB] - Checked: RLVa-1.2.2
+		region_name = (RlvActions::canShowLocation()) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+// [/RLVa:KB]
 		if (!region_name.empty())
 		{
 			region_name += "\n";
 		}
 	}
 
-	LLStringUtil::format_map_t args;
+//	LLStringUtil::format_map_t args;
 	args["[REGION]"] = region_name;
 	std::string msg = mToolTipMsg;
 	LLStringUtil::format(msg, args);
diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp
index 58a9b01a45944df8e232110ac02650f7eee0a33d..1058c3836cbf1fa5b589dc550c3ae877fadb65e9 100644
--- a/indra/newview/llnotificationalerthandler.cpp
+++ b/indra/newview/llnotificationalerthandler.cpp
@@ -38,6 +38,10 @@
 
 #include "lltoastalertpanel.h"
 
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+#include "rlvactions.h"
+// [/RLVa:KB]
+
 using namespace LLNotificationsUI;
 
 //--------------------------------------------------------------------------
@@ -88,8 +92,19 @@ bool LLAlertHandler::processNotification(const LLNotificationPtr& notification)
 
 		LLUUID from_id = notification->getPayload()["from_id"];
 
-		// firstly create session...
-		LLHandlerUtil::spawnIMSession(name, from_id);
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+		// Don't spawn an IM session for non-chat related events:
+		//   - LLHandlerUtil::logToIMP2P() below will still be called with to_file_only == false
+		//   - LLHandlerUtil::logToIM() will eventually be called as a result and without an open IM session it will log the
+		//     same message as it would for an open session whereas to_file_only == true would take a different code path
+		if (RlvActions::canStartIM(from_id))
+		{
+// [/RLVa:KB]
+			// firstly create session...
+			LLHandlerUtil::spawnIMSession(name, from_id);
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+		}
+// [/RLVa:KB]
 
 		// ...then log message to have IM Well notified about new message
 		LLHandlerUtil::logToIMP2P(notification);
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index 7a183cb298e9449ba39e0014fafcbe1cb3ecb2b0..2c5c610dbb14309f9782b2b517fb5e813f031a20 100644
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -332,16 +332,23 @@ class LLHandlerUtil
 	 */
 	static void updateIMFLoaterMesages(const LLUUID& session_id);
 
-	/**
-	 * Updates messages of visible IM floater.
-	 */
-	static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification);
+//	/**
+//	 * Updates messages of visible IM floater.
+//	 */
+//	static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification);
 
 	/**
 	 * Decrements counter of IM messages.
 	 */
 	static void decIMMesageCounter(const LLNotificationPtr& notification);
 
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
+	/**
+	 * Checks whether the user has opted to embed (certain) notifications in IM sessions
+	 */
+	static bool canEmbedNotificationInIM(const LLNotificationPtr& notification);
+// [/SL:KB]
+
 };
 
 }
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index a078889d46569a576ecec0e343585c229cc20d52..63d62ecb4cb7162928261746fc7652eac27aeb2a 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -265,15 +265,15 @@ void LLHandlerUtil::updateIMFLoaterMesages(const LLUUID& session_id)
 	}
 }
 
-// static
-void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification)
-{
-	const std::string name = LLHandlerUtil::getSubstitutionName(notification);
-	LLUUID from_id = notification->getPayload()["from_id"];
-	LLUUID session_id = spawnIMSession(name, from_id);
-
-	updateIMFLoaterMesages(session_id);
-}
+//// static
+//void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification)
+//{
+//	const std::string name = LLHandlerUtil::getSubstitutionName(notification);
+//	LLUUID from_id = notification->getPayload()["from_id"];
+//	LLUUID session_id = spawnIMSession(name, from_id);
+//
+//	updateIMFLoaterMesages(session_id);
+//}
 
 // static
 void LLHandlerUtil::decIMMesageCounter(const LLNotificationPtr& notification)
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index 2657b84ef30379962260d45674ee1bd7d33604d2..379edb19e5e2c070bdd65037a430986612dd4191 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -36,6 +36,9 @@
 #include "llscriptfloater.h"
 #include "llimview.h"
 #include "llnotificationsutil.h"
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+#include "rlvactions.h"
+// [/RLVa:KB]
 
 using namespace LLNotificationsUI;
 
@@ -108,9 +111,21 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification)
 			                notification->playSound();
 			            }
 
-			LLHandlerUtil::spawnIMSession(name, from_id);
-			LLHandlerUtil::addNotifPanelToIM(notification);
-
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+			// Don't spawn an IM session for non-chat related events
+			if (RlvActions::canStartIM(from_id))
+			{
+// [/RLVa:KB]
+				LLHandlerUtil::spawnIMSession(name, from_id);
+				LLHandlerUtil::addNotifPanelToIM(notification);
+// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
+			}
+			else
+			{
+				// Since we didn't add this notification to an IM session we want it to get routed to the notification syswell
+				add_notif_to_im = false;
+			}
+// [/RLVa:KB]
 		}
 
 		if (!notification->canShowToast())
@@ -177,9 +192,18 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification)
 	}
 	else
 	{
-		if (notification->canLogToIM() 
-			&& notification->hasFormElements()
-			&& !LLHandlerUtil::isIMFloaterOpened(notification))
+//		if (notification->canLogToIM() 
+//			&& notification->hasFormElements()
+//			&& !LLHandlerUtil::isIMFloaterOpened(notification))
+// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5)
+		// The above test won't necessarily tell us whether the notification went into an IM or to the notification syswell
+		//   -> the one and only time we need to decrease the unread IM count is when we've clicked any of the buttons on the *toast*
+		//   -> since LLIMFloater::updateMessages() hides the toast when we open the IM (which resets the unread count to 0) we should 
+		//      *only* decrease the unread IM count if there's a visible toast since the unread count will be at 0 otherwise anyway
+		LLScreenChannel* pChannel = dynamic_cast<LLScreenChannel*>(mChannel.get());
+		LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL;
+		if ( (pToast) && (!pToast->getCanBeStored()) )
+// [/SL:KB]
 		{
 			LLHandlerUtil::decIMMesageCounter(notification);
 		}
diff --git a/indra/newview/llpanelappearancetab.cpp b/indra/newview/llpanelappearancetab.cpp
index 8fa8867c696fca1358eda2c37a006b8899bac65c..fdb331163b2c8e1487c143a4ec8657485cace9ce 100644
--- a/indra/newview/llpanelappearancetab.cpp
+++ b/indra/newview/llpanelappearancetab.cpp
@@ -32,6 +32,10 @@
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
 #include "llviewerinventory.h"
+// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7)
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //virtual
 bool LLPanelAppearanceTab::canTakeOffSelected()
@@ -46,6 +50,11 @@ bool LLPanelAppearanceTab::canTakeOffSelected()
 		LLViewerInventoryItem* item = gInventory.getItem(*it);
 		if (!item) continue;
 
+// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7)
+		if ( (rlv_handler_t::isEnabled()) && (rlvPredCanNotRemoveItem(item)) )
+			return false;
+// [/RLVa:KB]
+
 		if (is_worn(NULL, item)) return true;
 	}
 	return false;
diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp
index 451f41cd3bfe6dfa756ac9ea2f95ad97ffacacf9..07693bda99331b755bded0756e33e7dc256f6696 100644
--- a/indra/newview/llpanelcontents.cpp
+++ b/indra/newview/llpanelcontents.cpp
@@ -60,6 +60,10 @@
 #include "llviewerwindow.h"
 #include "llworld.h"
 #include "llfloaterperms.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 //
 // Imported globals
@@ -119,6 +123,25 @@ void LLPanelContents::getState(LLViewerObject *objectp )
 					       && ( objectp->permYouOwner() || ( !group_id.isNull() && gAgent.isInGroup(group_id) )));  // solves SL-23488
 	BOOL all_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME );
 
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+	if ( (rlv_handler_t::isEnabled()) && (editable) )
+	{
+		// Don't allow creation of new scripts if it's non-detachable
+		if (objectp->isAttachment())
+			editable = !gRlvAttachmentLocks.isLockedAttachment(objectp->getRootEdit());
+
+		// Don't allow creation of new scripts if we're @unsit=n or @sittp=n restricted and we're sitting on the selection
+		if ( (editable) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) )
+		{
+			// Only check the first (non-)root object because nothing else would result in enabling the button (see below)
+			LLViewerObject* pObj = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(TRUE);
+
+			editable = 
+				(pObj) && (isAgentAvatarValid()) && ((!gAgentAvatarp->isSitting()) || (gAgentAvatarp->getRoot() != pObj->getRootEdit()));
+		}
+	}
+// [/RLVa:KB]
+
 	// Edit script button - ok if object is editable and there's an unambiguous destination for the object.
 	getChildView("button new script")->setEnabled(
 		editable &&
@@ -162,6 +185,21 @@ void LLPanelContents::onClickNewScript(void *userdata)
 	LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok);
 	if(object)
 	{
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+		if (rlv_handler_t::isEnabled())	// Fallback code [see LLPanelContents::getState()]
+		{
+			if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit()))
+			{
+				return;					// Disallow creating new scripts in a locked attachment
+			}
+			else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+			{
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()) )
+					return;				// .. or in a linkset the avie is sitting on under @unsit=n/@sittp=n
+			}
+		}
+// [/RLVa:KB]
+
 		LLPermissions perm;
 		perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
 
diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp
index acdb16f43291807995eaeb9dfb2f99a6082c14f0..49b96fb10da4df5f70801cb9239ddc48af153a84 100644
--- a/indra/newview/llpanelland.cpp
+++ b/indra/newview/llpanelland.cpp
@@ -44,6 +44,10 @@
 
 #include "lluictrlfactory.h"
 
+// [RLVa:KB]
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 LLPanelLandSelectObserver* LLPanelLandInfo::sObserver = NULL;
 LLPanelLandInfo* LLPanelLandInfo::sInstance = NULL;
 
@@ -224,6 +228,14 @@ void LLPanelLandInfo::refresh()
 //static
 void LLPanelLandInfo::onClickClaim()
 {
+// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
+/*
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		return;
+	}
+*/
+// [/RLVa:KB]
 	LLViewerParcelMgr::getInstance()->startBuyLand();
 }
 
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index cd1dc0f0701de1e5173fe84d353a9449060df4c8..d0b21a6ac33d668dfe46512d19bf54140ee24a6b 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -56,6 +56,9 @@
 #include "lltoggleablemenu.h"
 #include "llviewermenu.h"
 #include "llviewerregion.h"
+// [RLVa:KB]
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Not yet implemented; need to remove buildPanel() from constructor when we switch
 //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks");
@@ -771,15 +774,22 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const
 	std::string command_name = userdata.asString();
 	if("add_landmark" == command_name)
 	{
-		LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
-		if(landmark)
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
 		{
-			LLNotificationsUtil::add("LandmarkAlreadyExists");
-		}
-		else
-		{
-			LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
+// [/RLVa:KB]
+			LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
+			if(landmark)
+			{
+				LLNotificationsUtil::add("LandmarkAlreadyExists");
+			}
+			else
+			{
+				LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
+			}
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
 		}
+// [/RLVa:KB]
 	} 
 	else if ("category" == command_name)
 	{
@@ -1045,6 +1055,12 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const
 		}
 		return false;
 	}
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	else if("add_landmark" == command_name)
+	{
+		return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+	}
+// [/RLVa:KB]
 	else
 	{
 		LL_WARNS() << "Unprocessed command has come: " << command_name << LL_ENDL;
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 5dd44b4444f5cda6a84b02b83b93cb53ed76b044..248cddac422eb4c334f26423224b6615a98674fb 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -66,6 +66,10 @@
 #include "llviewercontrol.h"
 #include "lluictrlfactory.h"
 //#include "llfirstuse.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "llvoavatarself.h"
+// [/RLVa:KB]
 
 #include "lldrawpool.h"
 
@@ -357,6 +361,14 @@ void LLPanelObject::getState( )
 		enable_rotate = FALSE;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) )
+	{
+		if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == objectp->getRootEdit()) )
+			enable_move = enable_scale = enable_rotate = FALSE;
+	}
+// [/RLVa:KB]
+
 	LLVector3 vec;
 	if (enable_move)
 	{
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index c4211d550806ab77b16d9729cb991061e2423e73..0ea7093128bf466b70e84d05614ea1f18683fb9d 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -66,6 +66,10 @@
 #include "llviewerregion.h"
 #include "llviewerobjectlist.h"
 #include "llviewermessage.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 const LLColor4U DEFAULT_WHITE(255, 255, 255);
 
@@ -377,8 +381,16 @@ void LLTaskInvFVBridge::openItem()
 
 BOOL LLTaskInvFVBridge::isItemRenameable() const
 {
-	if(gAgent.isGodlike()) return TRUE;
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a
 	LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
+	if ( (rlv_handler_t::isEnabled()) && (object) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+	{
+		return FALSE;
+	}
+// [/RLVa:KB]
+
+	if(gAgent.isGodlike()) return TRUE;
+//	LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
 	if(object)
 	{
 		LLInventoryItem* item = (LLInventoryItem*)(object->getInventoryObject(mUUID));
@@ -393,7 +405,15 @@ BOOL LLTaskInvFVBridge::isItemRenameable() const
 
 BOOL LLTaskInvFVBridge::renameItem(const std::string& new_name)
 {
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a
 	LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
+	if ( (rlv_handler_t::isEnabled()) && (object) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+	{
+		return FALSE;
+	}
+// [/RLVa:KB]
+
+//	LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
 	if(object)
 	{
 		LLViewerInventoryItem* item = NULL;
@@ -420,12 +440,45 @@ BOOL LLTaskInvFVBridge::isItemMovable() const
 	//	return TRUE;
 	//}
 	//return FALSE;
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLViewerObject* pObj = gObjectList.findObject(mPanel->getTaskUUID());
+		if (pObj)
+		{
+			if (gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))
+			{
+				return FALSE;
+			}
+			else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+			{
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObj->getRootEdit()) )
+					return FALSE;
+			}
+		}
+	}
+// [/RLVa:KB]
 	return TRUE;
 }
 
 BOOL LLTaskInvFVBridge::isItemRemovable() const
 {
 	const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+	if ( (object) && (rlv_handler_t::isEnabled()) )
+	{
+		if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit()))
+		{
+			return FALSE;
+		}
+		else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+		{
+			if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()) )
+				return FALSE;
+		}
+	}
+// [/RLVa:KB]
+
 	if(object
 	   && (object->permModify() || object->permYouOwner()))
 	{
@@ -574,6 +627,13 @@ BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
 				const LLPermissions& perm = inv->getPermissions();
 				bool can_copy = gAgent.allowOperation(PERM_COPY, perm,
 														GP_OBJECT_MANIPULATE);
+// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a
+				// Kind of redundant due to the note below, but in case that ever gets fixed
+				if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+				{
+					return FALSE;
+				}
+// [/RLVa:KB]
 				if (object->isAttachment() && !can_copy)
 				{
                     //RN: no copy contents of attachments cannot be dragged out
@@ -689,20 +749,45 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 	else if (canOpenItem())
 	{
 		items.push_back(std::string("Task Open"));
-	}
-	items.push_back(std::string("Task Properties"));
-	if(isItemRenameable())
-	{
-		items.push_back(std::string("Task Rename"));
-		if ((flags & FIRST_SELECTED_ITEM) == 0)
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a
+		if (rlv_handler_t::isEnabled())
 		{
-			disabled_items.push_back(std::string("Task Rename"));
+			LLViewerObject* pAttachObj = gObjectList.findObject(mPanel->getTaskUUID());
+			bool fLocked = (pAttachObj) ? gRlvAttachmentLocks.isLockedAttachment(pAttachObj->getRootEdit()) : false;
+			if ( ((LLAssetType::AT_NOTECARD == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || (fLocked))) || 
+				 ((LLAssetType::AT_LSL_TEXT == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (fLocked))) ||
+				 ((LLAssetType::AT_TEXTURE == item->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE))) )
+			{
+				disabled_items.push_back(std::string("Task Open"));
+			}
 		}
+// [/RLVa:KB]
 	}
-	if(isItemRemovable())
-	{
-		items.push_back(std::string("Task Remove"));
-	}
+	items.push_back(std::string("Task Properties"));
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Added: RLVa-1.2.1f
+	items.push_back(std::string("Task Rename"));
+	if ( (!isItemRenameable()) || ((flags & FIRST_SELECTED_ITEM) == 0) )
+	{
+		disabled_items.push_back(std::string("Task Rename"));
+	}
+	items.push_back(std::string("Task Remove"));
+	if (!isItemRemovable())
+	{
+		disabled_items.push_back(std::string("Task Remove"));
+	}
+// [/RLVa:KB]
+//	if(isItemRenameable())
+//	{
+//		items.push_back(std::string("Task Rename"));
+//		if ((flags & FIRST_SELECTED_ITEM) == 0)
+//		{
+//			disabled_items.push_back(std::string("Task Rename"));
+//		}
+//	}
+//	if(isItemRemovable())
+//	{
+//		items.push_back(std::string("Task Remove"));
+//	}
 
 	hide_context_entries(menu, items, disabled_items);
 }
@@ -1106,6 +1191,13 @@ void LLTaskLSLBridge::openItem()
 	{
 		return;
 	}
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+	{
+		RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT);
+		return;
+	}
+// [/RLVa:KB]
 	if (object->permModify() || gAgent.isGodlike())
 	{
 		LLSD floater_key;
@@ -1168,6 +1260,14 @@ void LLTaskNotecardBridge::openItem()
 		return;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+	{
+		RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD);
+		return;
+	}
+// [/RLVa:KB]
+
 	// Note: even if we are not allowed to modify copyable notecard, we should be able to view it
 	LLInventoryItem *item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mUUID));
 	BOOL item_copy = item && gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE);
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 8331c152e206a34fc2f3f3c9b006e1e53963f91b..d2db4b718da97743ede76f6b470c852c6e61b7d4 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -73,6 +73,9 @@
 #include "llwearableitemslist.h"
 #include "llwearabletype.h"
 #include "llweb.h"
+// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 static LLPanelInjector<LLPanelOutfitEdit> t_outfit_edit("panel_outfit_edit");
 
@@ -602,6 +605,10 @@ void LLPanelOutfitEdit::toggleAddWearablesPanel()
 
 void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables)
 {
+// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	show_add_wearables = (show_add_wearables) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV));
+// [/RLVa:KB]
+
 	mAddWearablesPanel->setVisible(show_add_wearables);
 	
 	getChild<LLUICtrl>("show_add_wearables_btn")->setValue(show_add_wearables);
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index 6a0ea04fa6a050d14e95bb9a573c1f674eb5c2d7..827c7c1c227f17f1325cf5eac4a566202cadbb19 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -57,6 +57,12 @@ class LLPanelOutfitsInventory : public LLPanel
 
 	static LLSidepanelAppearance* getAppearanceSP();
 
+// [RLVa:KB] - Checked: 2010-08-24 (RLVa-1.4.0a) | Added: RLVa-1.2.1a
+	LLTabContainer* getAppearanceTabs()		{ return mAppearanceTabs; }
+	LLOutfitsList*  getMyOutfitsPanel()		{ return mMyOutfitsPanel; }
+	LLPanelWearing* getCurrentOutfitPanel()	{ return mCurrentOutfitPanel; }
+// [/RLVa:KB]
+
 	static LLPanelOutfitsInventory* findInstance();
 
 protected:
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index bc177abc57f2f377dfcab06a4195cc56fe2ac347..91e11aafb9473f3379b63820028082668ffd925d 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -74,6 +74,10 @@
 
 #include "llagentui.h"
 #include "llslurl.h"
+// [RLVa:KB] - Checked: RLVa-1.2.2
+#include "rlvactions.h"
+// [/RLVa:KB]
+
 
 #define FRIEND_LIST_UPDATE_TIMEOUT	0.5
 #define NEARBY_LIST_UPDATE_INTERVAL 1
@@ -625,6 +629,9 @@ BOOL LLPanelPeople::postBuild()
 	mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
 	mNearbyList->setShowIcons("NearbyListShowIcons");
 	mNearbyList->setShowCompleteName(!gSavedSettings.getBOOL("NearbyListHideUsernames"));
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	mNearbyList->setRlvCheckShowNames(true);
+// [/RLVa:KB]
 	mMiniMap = (LLNetMap*)getChildView("Net Map",true);
 	mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? 
 		getString("AltMiniMapToolTipMsg") :	getString("MiniMapToolTipMsg"));
@@ -830,7 +837,18 @@ void LLPanelPeople::updateNearbyList()
 
 	std::vector<LLVector3d> positions;
 
-	LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	if (RlvActions::canShowNearbyAgents())
+	{
+// [/RLVa:KB]
+		LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
+// [RLVa:KB] - Checked: RLVa-2.0.3
+	}
+	else
+	{
+		mNearbyList->getIDs().clear();
+	}
+// [/RLVa:KB]
 	mNearbyList->setDirty();
 
 	DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs());
@@ -894,6 +912,9 @@ void LLPanelPeople::updateFacebookList(bool visible)
 void LLPanelPeople::updateButtons()
 {
 	std::string cur_tab		= getActiveTabName();
+// [RLVa:KB] - Checked: RLVa-1.4.9
+	bool nearby_tab_active = (cur_tab == NEARBY_TAB_NAME);
+// [/RLVa:KB]
 	bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME);
 	bool group_tab_active	= (cur_tab == GROUP_TAB_NAME);
 	//bool recent_tab_active	= (cur_tab == RECENT_TAB_NAME);
@@ -934,8 +955,12 @@ void LLPanelPeople::updateButtons()
 		LLPanel* cur_panel = mTabContainer->getCurrentPanel();
 		if (cur_panel)
 		{
+// [RLVa:KB] - Checked: RLVa-1.2.0
 			if (cur_panel->hasChild("add_friend_btn", TRUE))
-				cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self);
+				cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self && ((!nearby_tab_active) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, selected_id))));
+// [/RLBa:KB]
+//			if (cur_panel->hasChild("add_friend_btn", TRUE))
+//				cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self);
 
 			if (friends_tab_active)
 			{
@@ -948,6 +973,16 @@ void LLPanelPeople::updateButtons()
 			}
 		}
 	}
+
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	if ( (nearby_tab_active) && (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) )
+	{
+		bool fCanShowNames = true;
+		std::for_each(selected_uuids.begin(), selected_uuids.end(), [&fCanShowNames](const LLUUID& idAgent) { fCanShowNames &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); });
+		if (!fCanShowNames)
+			item_selected = multiple_selected = false;
+	}
+// [/RLBa:KB]
 }
 
 std::string LLPanelPeople::getActiveTabName() const
@@ -1158,6 +1193,13 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl)
 		return;
 	}
 	
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	if ( (RlvActions::isRlvEnabled()) && (NEARBY_TAB_NAME == getActiveTabName()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, clicked_id)) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 #if 0 // SJB: Useful for testing, but not currently functional or to spec
 	LLAvatarActions::showProfile(clicked_id);
 #else // spec says open IM window
@@ -1273,6 +1315,15 @@ void LLPanelPeople::onImButtonClicked()
 {
 	uuid_vec_t selected_uuids;
 	getCurrentItemIDs(selected_uuids);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	if ( (RlvActions::isRlvEnabled()) && (NEARBY_TAB_NAME == getActiveTabName()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) )
+	{
+		bool fCanShowNames = true;
+		std::for_each(selected_uuids.begin(), selected_uuids.end(), [&fCanShowNames](const LLUUID& idAgent) { fCanShowNames &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); });
+		if (!fCanShowNames)
+			return;
+	}
+// [/RLVa:KB]
 	if ( selected_uuids.size() == 1 )
 	{
 		// if selected only one person then start up IM
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index eb7e76a77299f0c042d5f26f46da3551a17c27fb..49901bb51fc10a935b06fa7b2526652507060614 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -59,6 +59,11 @@ class LLPanelPeople
 
     bool mTryToConnectToFacebook;
 
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	LLAvatarList* getNearbyList() { return mNearbyList; }
+	void          updateNearbyList();
+// [/RLVa:KB]
+
 	// internals
 	class Updater;
 
@@ -78,7 +83,7 @@ class LLPanelPeople
 	void					updateFriendListHelpText();
 	void					updateFriendList();
 	bool					updateSuggestedFriendList();
-	void					updateNearbyList();
+//	void					updateNearbyList();
 	void					updateRecentList();
 	void					updateFacebookList(bool visible);
 
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 65769ff526490982f8e6b07eb6d22f49ba67ae59..f54127931effe165919cccb3df1bc86c06c9f214 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -46,6 +46,9 @@
 #include "llviewerregion.h"
 #include "llvoavatarself.h"
 #include "roles_constants.h"
+// [RLVa:KB] - Checked: RLVa-2.0.1
+#include "rlvactions.h"
+// [/RLVa:KB]
 
 namespace LLPanelPeopleMenus
 {
@@ -189,7 +192,10 @@ bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata)
 
 		for (;id != uuids_end; ++id)
 		{
-			if ( LLAvatarActions::isFriend(*id) )
+//			if ( LLAvatarActions::isFriend(*id) )
+// [RLVa:KB] - Checked: 2014-03-31 (RLVa-2.0.1)
+			if ( (LLAvatarActions::isFriend(*id)) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, *id)) )
+// [/RLVa:KB]
 			{
 				result = false;
 				break;
@@ -212,7 +218,10 @@ bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata)
 
 		for (;id != uuids_end; ++id)
 		{
-			if ( !LLAvatarActions::isFriend(*id) )
+//			if ( !LLAvatarActions::isFriend(*id) )
+// [RLVa:KB] - Checked: 2014-03-31 (RLVa-2.0.1)
+			if ( (!LLAvatarActions::isFriend(*id)) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, *id)) )
+// [/RLVa:KB]
 			{
 				result = false;
 				break;
@@ -315,14 +324,29 @@ void PeopleContextMenu::requestTeleport()
 {
 	// boost::bind cannot recognize overloaded method LLAvatarActions::teleportRequest(),
 	// so we have to use a wrapper.
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	bool fRlvCanShowName = (!m_fRlvCheck) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mUUIDs.front()));
+	RlvActions::setShowName(RlvActions::SNC_TELEPORTREQUEST, fRlvCanShowName);
 	LLAvatarActions::teleportRequest(mUUIDs.front());
+	RlvActions::setShowName(RlvActions::SNC_TELEPORTREQUEST, true);
+// [/RLVa:KB]
+//	LLAvatarActions::teleportRequest(mUUIDs.front());
 }
 
 void PeopleContextMenu::offerTeleport()
 {
 	// boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(),
 	// so we have to use a wrapper.
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	bool fRlvCanShowName = true;
+	if ( (m_fRlvCheck) && (RlvActions::isRlvEnabled()) )
+		std::for_each(mUUIDs.begin(), mUUIDs.end(), [&fRlvCanShowName](const LLUUID& idAgent) { fRlvCanShowName &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); });
+
+	RlvActions::setShowName(RlvActions::SNC_TELEPORTOFFER, fRlvCanShowName);
 	LLAvatarActions::offerTeleport(mUUIDs);
+	RlvActions::setShowName(RlvActions::SNC_TELEPORTOFFER, true);
+// [/RLVa:KB]
+//	LLAvatarActions::offerTeleport(mUUIDs);
 }
 
 void PeopleContextMenu::eject()
@@ -378,7 +402,29 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
     menuentry_vec_t items;
     menuentry_vec_t disabled_items;
 	
-	if (flags & ITEM_IN_MULTI_SELECTION)
+// [RLVa:KB] - Checked: RLVa-1.5.0
+	bool fRlvCanShowName = true;
+	if ( (m_fRlvCheck) && (RlvActions::isRlvEnabled()) )
+		std::for_each(mUUIDs.begin(), mUUIDs.end(), [&fRlvCanShowName](const LLUUID& idAgent) { fRlvCanShowName &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); });
+
+	if (!fRlvCanShowName)
+	{
+		if (flags & ITEM_IN_MULTI_SELECTION)
+		{
+			items.push_back(std::string("offer_teleport"));
+		}
+		else
+		{
+			items.push_back(std::string("offer_teleport"));
+			items.push_back(std::string("request_teleport"));
+			items.push_back(std::string("separator_invite_to_group"));
+			items.push_back(std::string("zoom_in"));
+			items.push_back(std::string("block_unblock"));
+		}
+	}
+	else if (flags & ITEM_IN_MULTI_SELECTION)
+// [/RLVa:KB]
+//	if (flags & ITEM_IN_MULTI_SELECTION)
 	{
 		items.push_back(std::string("add_friends"));
 		items.push_back(std::string("remove_friends"));
diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h
index 5ed20e00640c0d0ecac0ce68dae818e6f161f066..8f88bf36adab57d3c3351a475293e24e160c7cb1 100644
--- a/indra/newview/llpanelpeoplemenus.h
+++ b/indra/newview/llpanelpeoplemenus.h
@@ -38,6 +38,9 @@ namespace LLPanelPeopleMenus
 class PeopleContextMenu : public LLListContextMenu
 {
 public:
+// [RLVa:KB] - Checked: RLVa-1.5.0
+	PeopleContextMenu() : m_fRlvCheck(false) {}
+// [/RLVa:KB]
 	/*virtual*/ LLContextMenu* createMenu();
 
 protected:
@@ -51,6 +54,11 @@ class PeopleContextMenu : public LLListContextMenu
 	void eject();
 	void startConference();
 	void requestTeleport();
+
+// [RLVa:KB] - Checked: RLVa-1.5.0
+protected:
+	bool m_fRlvCheck;
+// [/RLVa:KB]
 };
 
 /**
@@ -58,6 +66,10 @@ class PeopleContextMenu : public LLListContextMenu
  */
 class NearbyPeopleContextMenu : public PeopleContextMenu
 {
+// [RLVa:KB] - Checked: RLVa-1.5.0
+public:
+	NearbyPeopleContextMenu() : PeopleContextMenu() { m_fRlvCheck = true; }
+// [/RLVa:KB]
 protected:
 	/*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags);
 };
diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp
index 6e677bbce55228b0df138be22c258e5aeca0496c..da20378d13196cd041604fe2efd381dcad687a19 100644
--- a/indra/newview/llpanelpermissions.cpp
+++ b/indra/newview/llpanelpermissions.cpp
@@ -63,7 +63,11 @@
 #include "roles_constants.h"
 #include "llgroupactions.h"
 #include "lltrans.h"
-
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a)
+#include "llslurl.h"
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 U8 string_value_to_click_action(std::string p_value);
 std::string click_action_to_string_value( U8 action);
@@ -365,11 +369,18 @@ void LLPanelPermissions::refresh()
 	
 	// Update creator text field
 	getChildView("Creator:")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+	BOOL creators_identical = FALSE;
+// [/RLVa:KB]
 	std::string creator_name;
-	LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name);
+// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+	creators_identical = LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name);
+// [/RLVa:KB]
+//	LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name);
 
-	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
-	getChildView("Creator Name")->setEnabled(TRUE);
+//	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
+//	getChildView("Creator Name")->setEnabled(TRUE);
+// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row
 
 	// Update owner text field
 	getChildView("Owner:")->setEnabled(TRUE);
@@ -397,8 +408,28 @@ void LLPanelPermissions::refresh()
 			}
 		}
 	}
+//	getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
+//	getChildView("Owner Name")->setEnabled(TRUE);
+// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row
+
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) )
+	{
+		// Only anonymize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie
+		if ( (creators_identical) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, mCreatorID)) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) )
+			creator_name = LLSLURL("agent", mCreatorID, "rlvanonym").getSLURLString();
+
+		// Only anonymize the owner name if all of the selection is owned by the same avie and isn't group owned
+		if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, mOwnerID)) )
+			owner_name = LLSLURL("agent", mOwnerID, "rlvanonym").getSLURLString();
+	}
+
+	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
+	getChildView("Creator Name")->setEnabled(TRUE);
+
 	getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
 	getChildView("Owner Name")->setEnabled(TRUE);
+// [/RLVa:KB]
 
 	// update group text field
 	getChildView("Group:")->setEnabled(TRUE);
diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp
index 2fa4ee376a235a33824f14865476d3412f7f6beb..d5a17b77fb7aa5733a5cf7020ad10f6c9b1adfbf 100644
--- a/indra/newview/llpanelplaceprofile.cpp
+++ b/indra/newview/llpanelplaceprofile.cpp
@@ -52,6 +52,9 @@
 #include "llviewercontrol.h"
 #include "llviewerparcelmgr.h"
 #include "llviewerregion.h"
+// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 const F64 COVENANT_REFRESH_TIME_SEC = 60.0f;
 
@@ -613,7 +616,10 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
 	mLastSelectedRegionID = region->getRegionID();
 	LLPanelPlaceInfo::processParcelInfo(parcel_data);
 
-	mYouAreHerePanel->setVisible(is_current_parcel);
+//	mYouAreHerePanel->setVisible(is_current_parcel);
+// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.4.5) | Added: RLVa-1.2.1
+	mYouAreHerePanel->setVisible(is_current_parcel && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)));
+// [/RLVa:KB]
 	getChild<LLAccordionCtrlTab>("sales_tab")->setVisible(for_sale);
 	mAccordionCtrl->arrange();
 }
@@ -681,6 +687,9 @@ void LLPanelPlaceProfile::updateYouAreHereBanner(void* userdata)
 		BOOL display_banner = gAgent.getRegion()->getRegionID() == self->mLastSelectedRegionID &&
 										LLAgentUI::checkAgentDistance(self->mPosRegion, radius);
 
-		self->mYouAreHerePanel->setVisible(display_banner);
+//		self->mYouAreHerePanel->setVisible(display_banner);
+// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.4.5) | Added: RLVa-1.2.1
+		self->mYouAreHerePanel->setVisible(display_banner && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)));
+// [/RLVa:KB]
 	}
 }
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index d97f60ed229ab16320932951e9a13c896e9b7177..63690c0e533b961dcbea164b4130a660b4065944 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -52,13 +52,17 @@ class LLPanelProfile : public LLPanel
 
 	S32 notifyParent(const LLSD& info);
 
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RVLa-1.2.0f
+	const LLUUID& getAvatarId() const { return mAvatarId; }
+// [/RLVa:KB]
+
 protected:
 
 	LLPanelProfile();
 
 	virtual void onTabSelected(const LLSD& param);
 
-	const LLUUID& getAvatarId() { return mAvatarId; }
+//	const LLUUID& getAvatarId() { return mAvatarId; }
 
 	void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; }
 
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index 109013498ee71b17d8a4510383003113ae365939..b0dafe5a1195a396592fcb24bcfbeea7530f414f 100644
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -44,6 +44,9 @@
 #include "llviewermenu.h"
 #include "llviewerparcelmgr.h"
 #include "llviewerregion.h"
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 class LLPanelTopInfoBar::LLParcelChangeObserver : public LLParcelObserver
 {
@@ -452,28 +455,47 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item)
 {
 	if (item == "landmark")
 	{
-		LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
-
-		if(landmark == NULL)
-		{
-			LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
-		}
-		else
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
 		{
-			LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID()));
+// [/RLVa:KB]
+			LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
+
+			if(landmark == NULL)
+			{
+				LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
+			}
+			else
+			{
+				LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID()));
+			}
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
 		}
+// [/RLVa:KB]
 	}
 	else if (item == "copy")
 	{
-		LLSLURL slurl;
-		LLAgentUI::buildSLURL(slurl, false);
-		LLUIString location_str(slurl.getSLURLString());
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+// [/RLVa:KB]
+			LLSLURL slurl;
+			LLAgentUI::buildSLURL(slurl, false);
+			LLUIString location_str(slurl.getSLURLString());
 
-		LLClipboard::instance().copyToClipboard(location_str,0,location_str.length());
+			LLClipboard::instance().copyToClipboard(location_str,0,location_str.length());
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+		}
+// [/RLVa:KB]
 	}
 }
 
 void LLPanelTopInfoBar::onInfoButtonClicked()
 {
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		return;
+// [/RLVa:KB]
+
 	LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent"));
 }
diff --git a/indra/newview/llpaneltopinfobar.h b/indra/newview/llpaneltopinfobar.h
index f37bd9c048823990ffab34a7c02823ff958d5ca9..b6d2cd94df768540043cf118621e6a1e50063e9d 100644
--- a/indra/newview/llpaneltopinfobar.h
+++ b/indra/newview/llpaneltopinfobar.h
@@ -61,6 +61,12 @@ class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>,
 
 	boost::signals2::connection setResizeCallback( const resize_signal_t::slot_type& cb );
 
+// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10)
+	/**
+	 * Shorthand to call updateParcelInfoText() and updateParcelIcons().
+	 */
+	void update();
+// [/RLV:KB]
 private:
 	class LLParcelChangeObserver;
 
@@ -110,10 +116,10 @@ class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>,
 	 */
 	void onNavBarShowParcelPropertiesCtrlChanged();
 
-	/**
-	 * Shorthand to call updateParcelInfoText() and updateParcelIcons().
-	 */
-	void update();
+//	/**
+//	 * Shorthand to call updateParcelInfoText() and updateParcelIcons().
+//	 */
+//	void update();
 
 	/**
 	 * Updates parcel info text (mParcelInfoText).
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index d0353259a52f860da324a1383e7269cb3c115f9c..c7587b71635bfb5107af3a9b7984c01623a0bd26 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -40,6 +40,10 @@
 #include "llwearableitemslist.h"
 #include "llsdserialize.h"
 #include "llclipboard.h"
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Context menu and Gear menu helper.
 static void edit_outfit()
@@ -111,6 +115,9 @@ class LLWearingContextMenu : public LLListContextMenu
 		bool bp_selected			= false;	// true if body parts selected
 		bool clothes_selected		= false;
 		bool attachments_selected	= false;
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+		S32 rlv_locked_count = 0;
+// [/RLVa:KB]
 
 		// See what types of wearables are selected.
 		for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it)
@@ -136,14 +143,27 @@ class LLWearingContextMenu : public LLListContextMenu
 			{
 				attachments_selected = true;
 			}
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+			if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(item)) )
+			{
+				rlv_locked_count++;
+			}
+// [/RLVa:KB]
 		}
 
 		// Enable/disable some menu items depending on the selection.
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+		bool rlv_blocked = (mUUIDs.size() == rlv_locked_count);
+// [/RLVa:KB]
 		bool allow_detach = !bp_selected && !clothes_selected && attachments_selected;
 		bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected;
 
 		menu->setItemVisible("take_off",	allow_take_off);
 		menu->setItemVisible("detach",		allow_detach);
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+		menu->setItemEnabled("take_off",	!rlv_blocked);
+		menu->setItemEnabled("detach",		!rlv_blocked);
+// [/RLVa:KB]
 		menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach);
 		menu->setItemVisible("show_original", mUUIDs.size() == 1);
 	}
diff --git a/indra/newview/llparcelselection.h b/indra/newview/llparcelselection.h
index 1cbdfc6f74bd5eeeedfccdeb5845b240c6ab9a19..b2d64b2d6c4c54266091686eb9f1f29dad97f99c 100644
--- a/indra/newview/llparcelselection.h
+++ b/indra/newview/llparcelselection.h
@@ -45,7 +45,10 @@ class LLParcelSelection : public LLRefCount
 
 	// this can return NULL at any time, as parcel selection
 	// might have been invalidated.
-	LLParcel* getParcel() { return mParcel; }
+// [RLVa:KB] - Checked: 2012-02-09 (RLVa-1.4.5) | Modified: RLVa-1.4.5
+	LLParcel* getParcel() const { return mParcel; }
+// [/RLVa:KB]
+//	LLParcel* getParcel() { return mParcel; }
 
 	// Return the number of grid units that are owned by you within
 	// the selection (computed by server).
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 5b1b3565978b09ba7ad0b3ae0fadb8de209f6204..1e720c308ab6ce057625f95a131ec0aadb59db0b 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -87,6 +87,10 @@
 #include "llexperiencecache.h"
 #include "llfloaterexperienceprofile.h"
 #include "llviewerassetupload.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 const std::string HELLO_LSL =
 	"default\n"
@@ -2021,6 +2025,14 @@ void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata )
 	//self->mRunningCheckbox->get();
 	if( object )
 	{
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+		{
+			RlvUtil::notifyBlockedGeneric();
+			return;
+		}
+// [/RLVa:KB]
+
 		LLMessageSystem* msg = gMessageSystem;
 		msg->newMessageFast(_PREHASH_SetScriptRunning);
 		msg->nextBlockFast(_PREHASH_AgentData);
@@ -2046,6 +2058,14 @@ void LLLiveLSLEditor::onReset(void *userdata)
 	LLViewerObject* object = gObjectList.findObject( self->mObjectUUID );
 	if(object)
 	{
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+		{
+			RlvUtil::notifyBlockedGeneric();
+			return;
+		}
+// [/RLVa:KB]
+
 		LLMessageSystem* msg = gMessageSystem;
 		msg->newMessageFast(_PREHASH_ScriptReset);
 		msg->nextBlockFast(_PREHASH_AgentData);
@@ -2172,6 +2192,14 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
 		return;
 	}
 
+// [RLVa:KB] - Checked: 2010-11-25 (RLVa-1.2.2b) | Modified: RLVa-1.2.2b
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+	{
+		RlvUtil::notifyBlockedGeneric();
+		return;
+	}
+// [/RLVa:KB]
+
     // get the latest info about it. We used to be losing the script
     // name on save, because the viewer object version of the item,
     // and the editor version would get out of synch. Here's a good
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index ba2c37ce7cf376dd9a6e4fa35090d2cb960f1514..6448343f3e598c9bd9c772d4100fbabcd12178bc 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -1120,8 +1120,17 @@ LLToast* LLScreenChannel::getToastByNotificationID(LLUUID id)
 	std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(),
 			mStoredToastList.end(), id);
 
+//	if (it == mStoredToastList.end())
+//		return NULL;
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Modified: Catznip-2.5.0a
 	if (it == mStoredToastList.end())
-		return NULL;
+	{
+		// If we can't find it among the stored toasts then widen it to "all visible toasts"
+		it = find(mToastList.begin(), mToastList.end(), id);
+		if (it == mToastList.end())
+			return NULL;
+	}
+// [/SL:KB]
 
 	return it->getToast();
 }
diff --git a/indra/newview/llscriptruntimeperms.h b/indra/newview/llscriptruntimeperms.h
index 51f57afdc91a2f94a0df3dea63d09f6a51ccb3e6..9318cbb1d66e706a70913204d9eecbd8d5971d51 100644
--- a/indra/newview/llscriptruntimeperms.h
+++ b/indra/newview/llscriptruntimeperms.h
@@ -39,7 +39,14 @@ typedef struct _script_perm {
 
 const U32 NUM_SCRIPT_PERMISSIONS = 16;
 const S32 SCRIPT_PERMISSION_DEBIT = 0;
+// [RLVa:KB] - Checked: RLVa-2.0.0
+const S32 SCRIPT_PERMISSION_TAKE_CONTROLS = 1;
+// [/RLVa:KB]
 const S32 SCRIPT_PERMISSION_TRIGGER_ANIMATION = 3;
+// [RLVa:KB] - Checked: RLVa-2.0.0
+const S32 SCRIPT_PERMISSION_ATTACH = 4;
+const S32 SCRIPT_PERMISSION_TELEPORT = 11;
+// [/RLVa:KB]
 const S32 SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS = 14;
 
 static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSIONS = {{
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 15b24c3ace4ac3aebeb21a279bc8ebcd6a02c89b..00ddbc9c43115c523efd3c4623e0cb6944e07e19 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -93,6 +93,11 @@
 #include "pipeline.h"
 #include "llviewershadermgr.h"
 #include "llpanelface.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+// [/RLVa:KB]
 #include "llglheaders.h"
 
 LLViewerObject* getSelectedParentObject(LLViewerObject *object) ;
@@ -679,6 +684,16 @@ bool LLSelectMgr::enableLinkObjects()
 			new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
 		}
 	}
+// [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g
+	if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) )
+	{
+		// Allow only if the avie isn't sitting on any of the selected objects
+		LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+		RlvSelectIsSittingOn f(gAgentAvatarp);
+		if (hSel->getFirstRootNode(&f, TRUE) != NULL)
+			new_value = false;
+	}
+// [/RLVa:KB]
 	return new_value;
 }
 
@@ -691,7 +706,16 @@ bool LLSelectMgr::enableUnlinkObjects()
 		first_editable_object &&
 		!first_editable_object->isAttachment() && !first_editable_object->isPermanentEnforced() &&
 		((root_object == NULL) || !root_object->isPermanentEnforced());
-
+// [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g
+	if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) )
+	{
+		// Allow only if the avie isn't sitting on any of the selected objects
+		LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+		RlvSelectIsSittingOn f(gAgentAvatarp);
+		if (hSel->getFirstRootNode(&f, TRUE) != NULL)
+			new_value = false;
+	}
+// [/RLVa:KB]
 	return new_value;
 }
 
@@ -3500,6 +3524,16 @@ BOOL LLSelectMgr::selectGetPermissions(LLPermissions& result_perm)
 
 void LLSelectMgr::selectDelete()
 {
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) )
+	{
+		make_ui_sound("UISndInvalidOp");
+		if (!gFloaterTools->getVisible())
+			deselectAll();
+		return;
+	}
+// [/RLVa:KB]
+
 	S32 deleteable_count = 0;
 
 	BOOL locked_but_deleteable_object = FALSE;
@@ -3812,7 +3846,10 @@ struct LLDuplicateData
 
 void LLSelectMgr::selectDuplicate(const LLVector3& offset, BOOL select_copy)
 {
-	if (mSelectedObjects->isAttachment())
+//	if (mSelectedObjects->isAttachment())
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	if ( (mSelectedObjects->isAttachment()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) )
+// [/RLVa:KB]
 	{
 		//RN: do not duplicate attachments
 		make_ui_sound("UISndInvalidOp");
@@ -4269,11 +4306,36 @@ void LLSelectMgr::convertTransient()
 
 void LLSelectMgr::deselectAllIfTooFar()
 {
+// [RLVa:KB] - Checked: RLVa-1.3.0
+	if ( (!mSelectedObjects->isEmpty()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_EDITOBJ))) )
+	{
+		struct NotTransientOrFocusedMediaOrEditable : public LLSelectedNodeFunctor
+		{
+			bool apply(LLSelectNode* pNode)
+			{
+				const LLViewerObject* pObj = pNode->getObject();
+				return (!pNode->isTransient()) && (pObj) && (!RlvActions::canEdit(pObj)) && (pObj->getID() != LLViewerMediaFocus::getInstance()->getFocusedObjectID());
+			}
+		} f;
+		if (mSelectedObjects->getFirstRootNode(&f, TRUE))
+			deselectAll();
+	}
+// [/RLVa:KB]
+
 	if (mSelectedObjects->isEmpty() || mSelectedObjects->mSelectType == SELECT_TYPE_HUD)
 	{
 		return;
 	}
 
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	// [Fall-back code] Don't allow an active selection (except for HUD attachments - see above) when @interact restricted
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))
+	{
+		deselectAll();
+		return;
+	}
+// [/RLVa:KB]
+
 	// HACK: Don't deselect when we're navigating to rate an object's
 	// owner or creator.  JC
 	if (gMenuObject->getVisible())
@@ -4282,13 +4344,22 @@ void LLSelectMgr::deselectAllIfTooFar()
 	}
 
 	LLVector3d selectionCenter = getSelectionCenterGlobal();
-	if (gSavedSettings.getBOOL("LimitSelectDistance")
+//	if (gSavedSettings.getBOOL("LimitSelectDistance")
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f
+	static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST);
+
+	BOOL fRlvFartouch = gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH) && gFloaterTools->getVisible();
+	if ( (gSavedSettings.getBOOL("LimitSelectDistance") || (fRlvFartouch) )
+// [/RLVa:KB]
 		&& (!mSelectedObjects->getPrimaryObject() || !mSelectedObjects->getPrimaryObject()->isAvatar())
 		&& (mSelectedObjects->getPrimaryObject() != LLViewerMediaFocus::getInstance()->getFocusedObject())
 		&& !mSelectedObjects->isAttachment()
 		&& !selectionCenter.isExactlyZero())
 	{
-		F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance");
+//		F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance");
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f
+		F32 deselect_dist = (!fRlvFartouch) ? gSavedSettings.getF32("MaxSelectDistance") : s_nFartouchDist;
+// [/RLVa:KB]
 		F32 deselect_dist_sq = deselect_dist * deselect_dist;
 
 		LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter;
@@ -6797,7 +6868,10 @@ BOOL LLSelectMgr::canDoDelete() const
 			can_delete = true;
 		}
 	}
-	
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	can_delete &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn());
+// [/RLVa:KB]
+
 	return can_delete;
 }
 
@@ -6829,7 +6903,12 @@ void LLSelectMgr::deselect()
 //-----------------------------------------------------------------------------
 BOOL LLSelectMgr::canDuplicate() const
 {
-	return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG
+//	return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	return 
+		(const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL) &&
+		( (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()) );
+// [/RLVa:KB]
 }
 //-----------------------------------------------------------------------------
 // duplicate()
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 86135ee6e83a0df031548f01b87b12e6dd7b0ece..7058cd4be85aaf7cad75e596562cdb5dd0a37583 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -544,3 +544,15 @@ void LLSidepanelAppearance::updateScrollingPanelList()
 		mEditWearable->updateScrollingPanelList();
 	}
 }
+
+// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+bool LLSidepanelAppearance::isOutfitEditPanelVisible() const
+{
+	return (mOutfitEdit) && (mOutfitEdit->getVisible());
+}
+
+bool LLSidepanelAppearance::isWearableEditPanelVisible() const
+{
+	return (mEditWearable) && (mEditWearable->getVisible());
+}
+// [/RLVa:KB]
diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h
index 440fce07bbc281fdc70802b1efa582278d69a9f8..703b593a66088b392354d08a81b46aa6d14cb5ac 100644
--- a/indra/newview/llsidepanelappearance.h
+++ b/indra/newview/llsidepanelappearance.h
@@ -66,6 +66,14 @@ class LLSidepanelAppearance : public LLPanel
 	void updateToVisibility( const LLSD& new_visibility );
 	LLPanelEditWearable* getWearable(){ return mEditWearable; }
 
+// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	bool isOutfitEditPanelVisible() const;
+	bool isWearableEditPanelVisible() const;
+
+	LLPanelOutfitEdit*	 getOutfitEditPanel() { return mOutfitEdit; }
+	LLPanelEditWearable* getWearableEditPanel() { return mEditWearable; }
+// [/RLVa:KB]
+
 private:
 	void onFilterEdit(const std::string& search_string);
 	void onVisibilityChanged ( const LLSD& new_visibility );
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index 12cbff888d39cb7c1c916059b07342ddf72dbea1..c43fef98cc7a315fcfe3853bd6e4f12dbdff222d 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -46,7 +46,10 @@
 #include "llviewerobjectlist.h"
 #include "llexperiencecache.h"
 #include "lltrans.h"
-
+// [RLVa:KB] - Checked: RLVa-2.0.1
+#include "rlvactions.h"
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLItemPropertiesObserver
@@ -356,9 +359,20 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	if (item->getCreatorUUID().notNull())
 	{
 		LLUUID creator_id = item->getCreatorUUID();
-		std::string name =
-			LLSLURL("agent", creator_id, "completename").getSLURLString();
-		getChildView("BtnCreator")->setEnabled(TRUE);
+//		std::string name =
+//			LLSLURL("agent", creator_id, "completename").getSLURLString();
+//		getChildView("BtnCreator")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+		// If the object creator matches the object owner we need to anonymize the creator field as well
+		bool fRlvCanShowCreator = true;
+		if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, creator_id)) &&
+		     ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == creator_id) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) )
+		{
+			fRlvCanShowCreator = false;
+		}
+		std::string name = LLSLURL("agent", creator_id, (fRlvCanShowCreator) ? "completename" : "rlvanonym").getSLURLString();
+		getChildView("BtnCreator")->setEnabled(fRlvCanShowCreator);
+// [/RLVa:KB]
 		getChildView("LabelCreatorTitle")->setEnabled(TRUE);
 		getChildView("LabelCreatorName")->setEnabled(FALSE);
 		getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
@@ -376,6 +390,9 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 	////////////////
 	if(perm.isOwned())
 	{
+// [RLVa:KB] - Checked: RVLa-2.0.1
+		bool fRlvCanShowOwner = true;
+// [/RLVa:KB]
 		std::string name;
 		if (perm.isGroupOwned())
 		{
@@ -384,9 +401,16 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 		else
 		{
 			LLUUID owner_id = perm.getOwner();
-			name = LLSLURL("agent", owner_id, "completename").getSLURLString();
+//			name = LLSLURL("agent", owner_id, "completename").getSLURLString();
+// [RLVa:KB] - Checked: RLVa-2.0.1
+			fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id);
+			name = LLSLURL("agent", owner_id, (fRlvCanShowOwner) ? "completename" : "rlvanonym").getSLURLString();
+// [/RLVa:KB]
 		}
-		getChildView("BtnOwner")->setEnabled(TRUE);
+//		getChildView("BtnOwner")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+		getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner);
+// [/RLVa:KB]
 		getChildView("LabelOwnerTitle")->setEnabled(TRUE);
 		getChildView("LabelOwnerName")->setEnabled(FALSE);
 		getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
@@ -743,6 +767,17 @@ void LLSidepanelItemInfo::onClickCreator()
 	if(!item) return;
 	if(!item->getCreatorUUID().isNull())
 	{
+// [RLVa:KB] - Checked: RLVa-1.2.1
+		const LLUUID& idCreator = item->getCreatorUUID();
+		if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) )
+		{
+			const LLPermissions& perm = item->getPermissions();
+			if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == idCreator) ) || (RlvUtil::isNearbyAgent(idCreator)) )
+			{
+				return;
+			}
+		}
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getCreatorUUID());
 	}
 }
@@ -758,6 +793,10 @@ void LLSidepanelItemInfo::onClickOwner()
 	}
 	else
 	{
+// [RLVa:KB] - Checked: RLVa-1.0.0
+		if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getPermissions().getOwner())) )
+			return;
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getPermissions().getOwner());
 	}
 }
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 403ca7bcbf0a2adf39a30d72de180efbdf04174b..11ab8c9988729aaff575f1346c2052ca333d63a1 100644
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -64,6 +64,10 @@
 #include "lltextbase.h"
 #include "llstring.h"
 #include "lltrans.h"
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a)
+#include "llslurl.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 ///----------------------------------------------------------------------------
 /// Class llsidepaneltaskinfo
@@ -370,21 +374,28 @@ void LLSidepanelTaskInfo::refresh()
 	
 	// Update creator text field
 	getChildView("Creator:")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+	BOOL creators_identical = FALSE;
+// [/RLVa:KB]
 
 	std::string creator_name;
 	LLUUID creator_id;
-	LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name);
-
-	if(creator_id != mCreatorID )
-	{
-		mDACreatorName->setValue(creator_name);
-		mCreatorID = creator_id;
-	}
-	if(mDACreatorName->getValue().asString() == LLStringUtil::null)
-	{
-	    mDACreatorName->setValue(creator_name);
-	}
-	mDACreatorName->setEnabled(TRUE);
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+	creators_identical = LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name);
+// [/RLVa:KB]
+//	LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name);
+
+//	if(creator_id != mCreatorID )
+//	{
+//		mDACreatorName->setValue(creator_name);
+//		mCreatorID = creator_id;
+//	}
+//	if(mDACreatorName->getValue().asString() == LLStringUtil::null)
+//	{
+//	    mDACreatorName->setValue(creator_name);
+//	}
+//	mDACreatorName->setEnabled(TRUE);
+// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row
 
 	// Update owner text field
 	getChildView("Owner:")->setEnabled(TRUE);
@@ -414,17 +425,41 @@ void LLSidepanelTaskInfo::refresh()
 		}
 	}
 
-	if(owner_id.isNull() || (owner_id != mOwnerID))
+//	if(owner_id.isNull() || (owner_id != mOwnerID))
+//	{
+//		mDAOwnerName->setValue(owner_name);
+//		mOwnerID = owner_id;
+//	}
+//	if(mDAOwnerName->getValue().asString() == LLStringUtil::null)
+//	{
+//	    mDAOwnerName->setValue(owner_name);
+//	}
+//	getChildView("Owner Name")->setEnabled(TRUE);
+
+// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
 	{
-		mDAOwnerName->setValue(owner_name);
-		mOwnerID = owner_id;
+		// Only anonymize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie
+		if ( (creators_identical) && (mCreatorID != gAgent.getID()) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) )
+			creator_name = LLSLURL("agent", mCreatorID, "rlvanonym").getSLURLString();
+
+		// Only anonymize the owner name if all of the selection is owned by the same avie and isn't group owned
+		if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) && (mOwnerID != gAgent.getID()) )
+			owner_name = LLSLURL("agent", mOwnerID, "rlvanonym").getSLURLString();
 	}
-	if(mDAOwnerName->getValue().asString() == LLStringUtil::null)
+
+	if(mDACreatorName->getValue().asString() == LLStringUtil::null)
 	{
-	    mDAOwnerName->setValue(owner_name);
+		mDACreatorName->setValue(creator_name);
 	}
+	mDACreatorName->setEnabled(TRUE);
 
-	getChildView("Owner Name")->setEnabled(TRUE);
+	if(mDAOwnerName->getValue().asString() == LLStringUtil::null)
+	{
+		mDAOwnerName->setValue(owner_name);
+	}
+	mDAOwnerName->setEnabled(TRUE);
+// [/RLVa:KB]
 
 	// update group text field
 	getChildView("Group:")->setEnabled(TRUE);
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index a8e012bfa1881eafb5eb7b8391bf1c97d7096348..c7caa8f0433e33c626cb1f16a7590e1239f92ddb 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -34,6 +34,9 @@
 #include "llviewernetwork.h"
 #include "llfiltersd2xmlrpc.h"
 #include "curl/curl.h"
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 const char* LLSLURL::SLURL_HTTP_SCHEME		 = "http";
 const char* LLSLURL::SLURL_HTTPS_SCHEME		 = "https";
 const char* LLSLURL::SLURL_SECONDLIFE_SCHEME	 = "secondlife";
@@ -389,8 +392,13 @@ std::string LLSLURL::getSLURLString() const
 				S32 x = ll_round( (F32)mPosition[VX] );
 				S32 y = ll_round( (F32)mPosition[VY] );
 				S32 z = ll_round( (F32)mPosition[VZ] );	
-				return LLGridManager::getInstance()->getSLURLBase(mGrid) + 
-				LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); 
+//				return LLGridManager::getInstance()->getSLURLBase(mGrid) + 
+//				LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); 
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+				return LLGridManager::getInstance()->getSLURLBase(mGrid) +
+					( ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) || (!RlvUtil::isNearbyRegion(mRegion)))
+						? (LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z)) : RlvStrings::getString(RLV_STRING_HIDDEN_REGION) );
+// [/RLVa:KB]
 			}
 		case APP:
 		{
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index a2c8e7772e5e1480e4e4f32407f58a81cae21a76..178118e4bf699ff11e41d8d3558d3ba32942bd6e 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -188,6 +188,10 @@
 #include "llvoicechannel.h"
 #include "llpathfindingmanager.h"
 
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 #include "lllogin.h"
 #include "llevents.h"
 #include "llstartuplistener.h"
@@ -372,6 +376,13 @@ bool idle_startup()
 		std::string lastGPU = gSavedSettings.getString("LastGPUString");
 		std::string thisGPU = LLFeatureManager::getInstance()->getGPUString();
 		
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-0.2.1d
+		if ( (gSavedSettings.controlExists(RLV_SETTING_MAIN)) && (gSavedSettings.getBOOL(RLV_SETTING_MAIN)) )
+		{
+			rlv_handler_t::setEnabled(TRUE);
+		}
+// [/RLVa:KB]
+
 		if (LLFeatureManager::getInstance()->isSafe())
 		{
 			LLNotificationsUtil::add("DisplaySetToSafe");
@@ -957,6 +968,14 @@ bool idle_startup()
 		// their last location, or some URL "-url //sim/x/y[/z]"
 		// All accounts have both a home and a last location, and we don't support
 		// more locations than that.  Choose the appropriate one.  JC
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d
+		if ( (rlv_handler_t::isEnabled()) && (RlvSettings::getLoginLastLocation()) )
+		{
+			// Force login at the last location
+			LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
+		}
+// [/RLVa:KB]
+
 		switch (LLStartUp::getStartSLURL().getType())
 		  {
 		  case LLSLURL::LOCATION:
@@ -1784,6 +1803,14 @@ bool idle_startup()
 		LL_INFOS() << "Creating Inventory Views" << LL_ENDL;
 		LLFloaterReg::getInstance("inventory");
 		display_startup();
+
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0f
+		if (rlv_handler_t::isEnabled())
+		{
+			// Regularly process a select subset of retained commands during logon
+			gIdleCallbacks.addFunction(RlvHandler::onIdleStartup, new LLTimer());
+		}
+// [/RLVa:KB]
 		LLStartUp::setStartupState( STATE_MISC );
 		display_startup();
 		return FALSE;
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 041eae4b3c9cd36af417dd1fe2a02581f667c9a2..cb85d84b3969d2390b5d0ae3cd0c1c7ceaa03d09 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -85,7 +85,6 @@
 // system includes
 #include <iomanip>
 
-
 //
 // Globals
 //
diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index a20d69dd41c392e39589016e24d21e1dded23662..8a983e681efc00a0f4b0f9050f24f8c26b8f4fb2 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -39,6 +39,9 @@
 #include "llviewerregion.h"
 #include "llworldmap.h"
 #include "llagentui.h"
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //////////////////////////////////////////////////////////////////////////////
 // LLTeleportHistoryItem
@@ -149,8 +152,16 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 				mItems.erase (mItems.begin() + mCurrentItem + 1, mItems.end());
 			
 			// Append an empty item to the history and make it current.
-			mItems.push_back(LLTeleportHistoryItem("", LLVector3d()));
-			mCurrentItem++;
+//			mItems.push_back(LLTeleportHistoryItem("", LLVector3d()));
+//			mCurrentItem++;
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+			// Only append a new item if the list is currently empty or if not @showloc=n restricted and the last entry wasn't zero'ed out
+			if ( (mItems.size() == 0) || ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!mItems.back().mGlobalPos.isExactlyZero())) )
+			{
+				mItems.push_back(LLTeleportHistoryItem("", LLVector3d()));
+				mCurrentItem++;
+			}
+// [RLVa:KB]
 		}
 
 		// Update current history item.
@@ -160,11 +171,23 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 			llassert(!"Invalid current teleport history item");
 			return;
 		}
-		LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos);
-		mItems[mCurrentItem].mFullTitle = getCurrentLocationTitle(true, new_pos_local);
-		mItems[mCurrentItem].mTitle = getCurrentLocationTitle(false, new_pos_local);
-		mItems[mCurrentItem].mGlobalPos	= new_pos;
-		mItems[mCurrentItem].mRegionID = gAgent.getRegion()->getRegionID();
+
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+// [/RLVa:KB]
+			LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos);
+			mItems[mCurrentItem].mFullTitle = getCurrentLocationTitle(true, new_pos_local);
+			mItems[mCurrentItem].mTitle = getCurrentLocationTitle(false, new_pos_local);
+			mItems[mCurrentItem].mGlobalPos	= new_pos;
+			mItems[mCurrentItem].mRegionID = gAgent.getRegion()->getRegionID();
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+		}
+		else
+		{
+			mItems[mCurrentItem] = LLTeleportHistoryItem(RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL), LLVector3d::zero);
+		}
+// [/RLVa:KB]
 	}
 
 	dump();
diff --git a/indra/newview/llteleporthistory.h b/indra/newview/llteleporthistory.h
index e9c29c39bf3e945d91a57f4260d8ad705919f56d..401c340362b9a3092a6b3f94e6b3a6cc0c887721 100644
--- a/indra/newview/llteleporthistory.h
+++ b/indra/newview/llteleporthistory.h
@@ -234,6 +234,10 @@ class LLTeleportHistory: public LLSingleton<LLTeleportHistory>
 	 * Using this connection we get notified when a teleport fails.
 	 */
 	boost::signals2::connection	mTeleportFailedConn;
+
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+	friend class RlvUIEnabler;
+// [/RLVa:KB]
 };
 
 #endif
diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp
index 8a5704939a134f54c3ffda1aa2408f571a72c48f..593960fa6cc3a98e4a51156e9b3cea068ed9b2c7 100644
--- a/indra/newview/llteleporthistorystorage.cpp
+++ b/indra/newview/llteleporthistorystorage.cpp
@@ -33,6 +33,9 @@
 #include "lldir.h"
 #include "llteleporthistory.h"
 #include "llagent.h"
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Max offset for two global positions to consider them as equal
 const F64 MAX_GLOBAL_POS_OFFSET = 5.0f;
@@ -92,6 +95,13 @@ void LLTeleportHistoryStorage::onTeleportHistoryChange()
 	}
 
 	const LLTeleportHistoryItem &item = th->getItems()[th->getCurrentItemIndex()];
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+	// Make sure we don't attempt to save zero'ed out teleport history items
+	if (item.mGlobalPos.isExactlyZero())
+	{
+		return;
+	}
+// [/RLVa:KB]
 
 	addItem(item.mTitle, item.mGlobalPos);
 	save();
@@ -116,6 +126,13 @@ bool LLTeleportHistoryStorage::compareByTitleAndGlobalPos(const LLTeleportHistor
 
 void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos, const LLDate& date)
 {
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLTeleportHistoryPersistentItem item(title, global_pos, date);
 
 	slurl_list_t::iterator item_iter = std::find_if(mItems.begin(), mItems.end(),
diff --git a/indra/newview/llteleporthistorystorage.h b/indra/newview/llteleporthistorystorage.h
index cf4c85a9910106a91c9f69be4cfe62dea049cb0a..f0131ac897ce9939438262c6de97e15618e1bf2b 100644
--- a/indra/newview/llteleporthistorystorage.h
+++ b/indra/newview/llteleporthistorystorage.h
@@ -108,7 +108,11 @@ class LLTeleportHistoryStorage: public LLSingleton<LLTeleportHistoryStorage>
 	 */
 	void					goToItem(S32 idx);
 
-private:
+//private:
+// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+protected:
+	friend class RlvUIEnabler;
+// [/RLVa:KB]
 
 	void load();
 	void dump() const;
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index e1b764a9438c541f142126bf9c2dd04fde1b0cab..8994d4cab90be71aa6eab38c8daf3afaa5a2b04f 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -49,7 +49,10 @@ LLToastPanel::~LLToastPanel()
 std::string LLToastPanel::getTitle()
 {
 	// *TODO: create Title and localize it. If it will be required.
-	return mNotification->getMessage();
+//	return mNotification->getMessage();
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
+	return (mNotification->hasLabel()) ? mNotification->getLabel() : mNotification->getMessage();
+// [/SL:KB]
 }
 
 //virtual
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 3f9a1a089b4b9d936b1ba1a78258b85f0c678e32..376f51af806a3f04afd3015f2e00314d5f33a6fd 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -60,6 +60,10 @@
 #include "llvoavatarself.h"
 #include "llworld.h"
 #include "llpanelface.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 // syntactic sugar
 #define callMemberFunction(object,ptrToMember)  ((object).*(ptrToMember))
@@ -1236,6 +1240,15 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
 		return;
 	}
 
+
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+	// Fallback in case there's a new code path that leads here (see behaviour notes)
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	//LL_INFOS() << "Rezzing object" << LL_ENDL;
 	make_ui_sound("UISndObjectRezIn");
 	LLViewerInventoryItem* item;
@@ -1507,6 +1520,23 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
 	BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
 	BOOL attached = obj->isAttachment();
 	BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
+
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0c
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLViewerObject* pObjRoot = obj->getRootEdit();
+		if (gRlvAttachmentLocks.isLockedAttachment(pObjRoot))
+		{
+			return ACCEPT_NO_LOCKED;		// Disallow inventory drops on a locked attachment
+		}
+		else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+		{
+			if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObjRoot) )
+				return ACCEPT_NO_LOCKED;	// ... or on a linkset the avie is sitting on under @unsit=n/@sittp=n
+		}
+	}
+// [/RLVa:KB]
+
 	if(attached && !unrestricted)
 	{
 		return ACCEPT_NO_LOCKED;
@@ -1725,6 +1755,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 		return ACCEPT_NO;
 	}
 
+// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8)
+	bool fReplace = !(mask & MASK_CONTROL);
+	if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item, (fReplace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) )
+	{
+		return ACCEPT_NO_LOCKED;
+	}
+// [/RLVa:KB]
 
 	if( drop )
 	{
@@ -1733,7 +1770,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 //			LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0));
 // [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-2.2)
 			// Make this behave consistent with dad3dWearItem
-			LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, !(mask & MASK_CONTROL)));
+			LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, fReplace));
 // [/SL:KB]
 			copy_inventory_item(
 				gAgent.getID(),
@@ -1759,6 +1796,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
 {
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// RELEASE-RLVa: [SL-2.2.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnLand()
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) )
+	{
+		return ACCEPT_NO_LOCKED;
+	}
+// [/RLVa:KB]
+
 	if (mSource == SOURCE_WORLD)
 	{
 		return dad3dRezFromObjectOnLand(obj, face, mask, drop);
@@ -1821,6 +1866,18 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
 	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
 {
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// NOTE: if (mask & MASK_CONTROL) then it's a drop rather than a rez, so we let that pass through when @rez=n restricted
+	// (but not when @interact=n restricted unless the drop target is a HUD attachment)
+	// RELEASE-RLVa: [SL-2.2.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnObject()
+	if ( (rlv_handler_t::isEnabled()) &&
+		 ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) && ((mask & MASK_CONTROL) == 0) ) ||
+		   ( (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (((mask & MASK_CONTROL) == 0) || (!obj->isHUDAttachment())) ) ) )
+	{
+		return ACCEPT_NO_LOCKED;
+	}
+// [/RLVa:KB]
+
 	// handle objects coming from object inventory
 	if (mSource == SOURCE_WORLD)
 	{
@@ -2051,11 +2108,22 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem(
 			return ACCEPT_NO;
 		}
 
+// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8)
+		bool fReplace = (!(mask & MASK_CONTROL)) || (LLAssetType::AT_BODYPART == item->getType());	// Body parts should always replace
+		if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item, (fReplace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) )
+		{
+			return ACCEPT_NO_LOCKED;
+		}
+// [/RLVa:KB]
+
 		if( drop )
 		{
 			// TODO: investigate wearables may not be loaded at this point EXT-8231
 
-			LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL));
+// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8)
+			LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, fReplace);
+// [/RLVa:KB]
+//			LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL));
 		}
 		return ACCEPT_YES_MULTI;
 	}
diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp
index a00ac10698a9798958d9d435e483c01463eef503..c1707bba30d75a90eb4e157b12b7ef41038e0ed1 100644
--- a/indra/newview/lltoolface.cpp
+++ b/indra/newview/lltoolface.cpp
@@ -39,6 +39,10 @@
 #include "llviewerobject.h"
 #include "llviewerwindow.h"
 #include "llfloatertools.h"
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Member functions
@@ -90,6 +94,15 @@ void LLToolFace::pickCallback(const LLPickInfo& pick_info)
 			return;
 		}
 
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
+		if ( (rlv_handler_t::isEnabled()) &&
+			 ( (!RlvActions::canEdit(hit_obj)) || 
+			   ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(hit_obj, pick_info.mObjectOffset))) ) )
+		{
+			return;
+		}
+// [/RLVa:KB]
+
 		// ...clicked on a world object, try to pick the appropriate face
 
 		if (pick_info.mKeyMask & MASK_SHIFT)
diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp
index c0ca4d7a9a4737fa316e3622e3f5cbf577f124b6..ed71163cd8002d954b53063c97d58377faeee637 100644
--- a/indra/newview/lltoolgrab.cpp
+++ b/indra/newview/lltoolgrab.cpp
@@ -57,6 +57,9 @@
 #include "llvoavatarself.h"
 #include "llworld.h"
 #include "llmenugl.h"
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 const S32 SLOP_DIST_SQ = 4;
 
@@ -170,7 +173,11 @@ void LLToolGrab::pickCallback(const LLPickInfo& pick_info)
 	}
 
 	// if not over object, do nothing
-	if (!objectp)
+//	if (!objectp)
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.1.0l
+	// Block initiating a drag operation on an object that can't be touched
+	if ( (!objectp) || ((rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(objectp, pick_info.mObjectOffset))) )
+// [/RLVa:KB]
 	{
 		LLToolGrab::getInstance()->setMouseCapture(TRUE);
 		LLToolGrab::getInstance()->mMode = GRAB_NOOBJECT;
@@ -431,6 +438,22 @@ BOOL LLToolGrab::handleHover(S32 x, S32 y, MASK mask)
 		return TRUE;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// Block dragging an object beyond touch range when @fartouch=n restricted
+	if ( (rlv_handler_t::isEnabled()) && (GRAB_INACTIVE != mMode) && (GRAB_NOOBJECT != mMode) && (hasMouseCapture()) &&
+		 (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(mGrabPick.getObject(), mGrabPick.mObjectOffset)) )
+	{
+		if (gGrabTransientTool)
+		{
+			// Prevent the grab tool from popping up as soon as we kill the drag operation
+			gBasicToolset->selectTool(gGrabTransientTool);
+			gGrabTransientTool = NULL;
+		}
+		setMouseCapture(FALSE);
+		return TRUE;
+	}
+// [/RLVa:KB]
+
 	// Do the right hover based on mode
 	switch( mMode )
 	{
diff --git a/indra/newview/lltoolgun.cpp b/indra/newview/lltoolgun.cpp
index 6c9155be851675281d6fccc722c0cd2d25bc8571..3d72976c96f9780ac6b3984443ba440c19120148 100644
--- a/indra/newview/lltoolgun.cpp
+++ b/indra/newview/lltoolgun.cpp
@@ -39,6 +39,9 @@
 #include "llui.h"
 #include "llviewertexturelist.h"
 #include "llviewercamera.h"
+// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10)
+#include "llfocusmgr.h"
+// [/RLVa:KB]
 #include "llhudmanager.h"
 #include "lltoolmgr.h"
 #include "lltoolgrab.h"
@@ -54,10 +57,17 @@ LLToolGun::LLToolGun( LLToolComposite* composite )
 
 void LLToolGun::handleSelect()
 {
-	gViewerWindow->hideCursor();
-	gViewerWindow->moveCursorToCenter();
-	gViewerWindow->getWindow()->setMouseClipping(TRUE);
-	mIsSelected = TRUE;
+// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10)
+	if (gFocusMgr.getAppHasFocus())
+	{
+// [/RLVa:KB]
+		gViewerWindow->hideCursor();
+		gViewerWindow->moveCursorToCenter();
+		gViewerWindow->getWindow()->setMouseClipping(TRUE);
+		mIsSelected = TRUE;
+// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10)
+	}
+// [/RLVa:KB]
 }
 
 void LLToolGun::handleDeselect()
diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp
index b0e3b5bf898b2944c8a0a575c16b397596feea13..2dc4cc086fae4f3e3a2d47b68702aba1222f8658 100644
--- a/indra/newview/lltoolmgr.cpp
+++ b/indra/newview/lltoolmgr.cpp
@@ -57,7 +57,10 @@
 #include "llviewerjoystick.h"
 #include "llviewermenu.h"
 #include "llviewerparcelmgr.h"
-
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 // Used when app not active to avoid processing hover.
 LLTool*			gToolNull	= NULL;
@@ -82,9 +85,14 @@ LLToolMgr::LLToolMgr()
 {
 	// Not a panel, register these callbacks globally.
 	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Active", boost::bind(&LLToolMgr::inEdit, this));
-	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&LLToolMgr::canEdit, this));
-	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&LLToolMgr::buildEnabledOrActive, this));
-	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this, _2));
+//	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&LLToolMgr::canEdit, this));
+//	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&LLToolMgr::buildEnabledOrActive, this));
+//	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this, _2));
+// [RLVa:KB] - Checked: 2010-09-11 (RLVa-1.2.1d) | Added: RLVa-1.2.1d
+	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&RlvUIEnabler::isBuildEnabled));
+	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&RlvUIEnabler::isBuildEnabledOrActive));
+	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this));
+// [/RLVa:KB]
 	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Marketplace.Enabled", boost::bind(&LLToolMgr::canAccessMarketplace, this));
 	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Marketplace.Toggle", boost::bind(&LLToolMgr::toggleMarketplace, this, _2));
 	
@@ -265,20 +273,23 @@ bool LLToolMgr::canEdit()
 	return LLViewerParcelMgr::getInstance()->allowAgentBuild();
 }
 
-bool LLToolMgr::buildEnabledOrActive()
-{
-	return inEdit() || canEdit();
-}
+//bool LLToolMgr::buildEnabledOrActive()
+//{
+//	return inEdit() || canEdit();
+//}
 
-void LLToolMgr::toggleBuildMode(const LLSD& sdname)
+//void LLToolMgr::toggleBuildMode(const LLSD& sdname)
+// [RLVa:KB] - Checked: 2012-04-26 (RLVa-1.4.6) | Added: RLVa-1.4.6
+void LLToolMgr::toggleBuildMode()
+// [/RLVa:KB]
 {
-	const std::string& param = sdname.asString();
-
-	LLFloaterReg::toggleInstanceOrBringToFront("build");
-	if (param == "build" && !canEdit())
-	{
-		return;
-	}
+//	const std::string& param = sdname.asString();
+//
+//	LLFloaterReg::toggleInstanceOrBringToFront("build");
+//	if (param == "build" && !canEdit())
+//	{
+//		return;
+//	}
 
 	bool build_visible = LLFloaterReg::instanceVisible("build");
 	if (build_visible)
diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h
index e5b45750d900f6fb2eebe1faea562f736f0748ea..4944c6ed71c3d423d23a4b58e783a3a98d921d74 100644
--- a/indra/newview/lltoolmgr.h
+++ b/indra/newview/lltoolmgr.h
@@ -56,7 +56,10 @@ class LLToolMgr : public LLSingleton<LLToolMgr>
 	bool			canEdit();
 	bool 			buildEnabledOrActive();
     bool            canAccessMarketplace();
-	void			toggleBuildMode(const LLSD& sdname);
+// [RLVa:KB] - Checked: 2012-04-26 (RLVa-1.4.6) | Added: RLVa-1.4.6
+	void			toggleBuildMode();
+// [/RLVa:KB]
+//	void			toggleBuildMode(const LLSD& sdname);
 	void			toggleMarketplace(const LLSD& sdname);
 	
 	/* Determines if we are in Build mode or not. */
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index e17651dc911a11e2fb8fc5892711e5f9dda01f02..9f941c1aac350f1bfb9c4d61ebec88f4fe2671e6 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -70,6 +70,10 @@
 #include "llui.h"
 #include "llweb.h"
 #include "pipeline.h"	// setHighlightObject
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 extern BOOL gDebugClicks;
 
@@ -202,6 +206,15 @@ BOOL LLToolPie::handleLeftClickPick()
 	// If it's a left-click, and we have a special action, do it.
 	if (useClickAction(mask, object, parent))
 	{
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+		// Block left-click special actions when fartouch restricted
+		if ( (rlv_handler_t::isEnabled()) && 
+			 (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(object, mPick.mObjectOffset)) )
+		{
+			return TRUE;
+		}
+// [/RLVa:KB]
+
 		mClickAction = 0;
 		if (object && object->getClickAction()) 
 		{
@@ -323,6 +336,14 @@ BOOL LLToolPie::handleLeftClickPick()
 		((object->flagUsePhysics() || (parent && !parent->isAvatar() && parent->flagUsePhysics())) || touchable) 
 		)
 	{
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+		// Triggered by left-clicking on a touchable object
+		if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, mPick.mObjectOffset)) )
+		{
+			return LLTool::handleMouseDown(x, y, mask);
+		}
+// [/RLVa:KB]
+
 		gGrabTransientTool = this;
 		mMouseButtonDown = false;
 		LLToolGrab::getInstance()->setClickedInMouselook(gAgentCamera.cameraMouselook());
@@ -438,7 +459,11 @@ ECursorType LLToolPie::cursorFromObject(LLViewerObject* object)
 	{
 	case CLICK_ACTION_SIT:
 		{
-			if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting?
+//			if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting?
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0g
+			if ( (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) && 
+				 ((!rlv_handler_t::isEnabled()) || (RlvActions::canSit(object, LLToolPie::getInstance()->getHoverPick().mObjectOffset))) )
+// [/RLVa:KB]
 			{
 				cursor = UI_CURSOR_TOOLSIT;
 			}
@@ -555,7 +580,20 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 	mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE);
 	LLViewerObject *parent = NULL;
 	LLViewerObject *object = mHoverPick.getObject();
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// Block all special click action cursors when:
+	//   - @fartouch=n restricted and the object is out of range
+	//   - @interact=n restricted and the object isn't a HUD attachment
+	if ( (object) && (rlv_handler_t::isEnabled()) && 
+		( ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))) && (!gRlvHandler.canTouch(object, mHoverPick.mObjectOffset)) || 
+		  ((gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (!object->isHUDAttachment())) ) )
+	{
+		gViewerWindow->setCursor(UI_CURSOR_ARROW);
+		return TRUE;
+	}
+// [/RLVa:KB]
 	LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace);
+
 	if (object)
 	{
 		parent = object->getRootEdit();
@@ -609,7 +647,13 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 			gViewerWindow->setCursor(cursor);
 			LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
 		}
-		
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.1.0l
+		else if ( (object) && (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object)) )
+		{
+			// Block showing the "grab" or "touch" cursor if we can't touch the object (@fartouch=n is handled above)
+			gViewerWindow->setCursor(UI_CURSOR_ARROW);
+		}
+// [/RLVa:KB]
 		else if ((object && !object->isAvatar() && object->flagUsePhysics()) 
 				 || (parent && !parent->isAvatar() && parent->flagUsePhysics()))
 		{
@@ -686,10 +730,24 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
                                              FALSE /* ignore transparent */,
                                              FALSE /* ignore particles */);
 
-        if (!mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
-            && (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
-                || mPick.mObjectID.notNull()))				// or on an object
+//        if (!mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
+//            && (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
+//                || mPick.mObjectID.notNull()))				// or on an object
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		bool fValidPick = (!mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
+			&& (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
+				|| mPick.mObjectID.notNull()));				// or on an object
+
+		if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) )
+		{
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT);
+			fValidPick = false;
+		}
+
+		if (fValidPick)
+// [/RLVa:KB]
         {
+
             // handle special cases of steering picks
             LLViewerObject* avatar_object = mPick.getObject();
 
@@ -784,8 +842,20 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
             }
         }
 
-		if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
-			(mPick.mObjectID.notNull()  && !mPick.mPosGlobal.isExactlyZero()))
+//		if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
+//			(mPick.mObjectID.notNull()  && !mPick.mPosGlobal.isExactlyZero()))
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		bool fValidPick = ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
+			(mPick.mObjectID.notNull()  && !mPick.mPosGlobal.isExactlyZero()));
+
+		if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) )
+		{
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT);
+			fValidPick = false;
+		}
+
+		if (fValidPick)
+// [/RLVa:KB]
 		{
 			walkToClickedLocation();
 			return TRUE;
@@ -1052,7 +1122,10 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
 			LLAvatarName av_name;
 			if (LLAvatarNameCache::get(hover_object->getID(), &av_name))
 			{
-				final_name = av_name.getCompleteName();
+//				final_name = av_name.getCompleteName();
+// [RLVa:KB] - Checked: RLVa-1.2.2
+				final_name = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, hover_object->getID())) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name);
+// [/RLVa:KB]
 			}
 			else
 			{
@@ -1061,17 +1134,29 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
 
 			// *HACK: We may select this object, so pretend it was clicked
 			mPick = mHoverPick;
-			LLInspector::Params p;
-			p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
-			p.message(final_name);
-			p.image.name("Inspector_I");
-			p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
-			p.visible_time_near(6.f);
-			p.visible_time_far(3.f);
-			p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay"));
-			p.wrap(false);
-			
-			LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: RLVa-1.2.0
+			if ( (!rlv_handler_t::isEnabled()) || 
+			     ( (gRlvHandler.canTouch(hover_object, mHoverPick.mObjectOffset)) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, hover_object->getID())) ) )
+			{
+// [/RLVa:KB]
+				LLInspector::Params p;
+				p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+				p.message(final_name);
+				p.image.name("Inspector_I");
+				p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
+				p.visible_time_near(6.f);
+				p.visible_time_far(3.f);
+				p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay"));
+				p.wrap(false);
+				
+				LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.2a) | Added: RLVa-1.2.0e
+			}
+			else
+			{
+				LLToolTipMgr::instance().show(final_name);
+			}
+// [/RLVa:KB]
 		}
 	}
 	else
@@ -1174,22 +1259,34 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
 			{
 				// We may select this object, so pretend it was clicked
 				mPick = mHoverPick;
-				LLInspector::Params p;
-				p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
-				p.message(tooltip_msg);
-				p.image.name("Inspector_I");
-				p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace));
-				p.time_based_media(is_time_based_media);
-				p.web_based_media(is_web_based_media);
-				p.media_playing(is_media_playing);
-				p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick));
-				p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
-				p.visible_time_near(6.f);
-				p.visible_time_far(3.f);
-				p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay"));
-				p.wrap(false);
-				
-				LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Modified: RLVa-1.2.1g
+				if ( (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ||
+					 (gRlvHandler.canTouch(hover_object, mHoverPick.mObjectOffset)) )
+				{
+// [/RLVa:KB]
+					LLInspector::Params p;
+					p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+					p.message(tooltip_msg);
+					p.image.name("Inspector_I");
+					p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace));
+					p.time_based_media(is_time_based_media);
+					p.web_based_media(is_web_based_media);
+					p.media_playing(is_media_playing);
+					p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick));
+					p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
+					p.visible_time_near(6.f);
+					p.visible_time_far(3.f);
+					p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay"));
+					p.wrap(false);
+					
+					LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+				}
+				else
+				{
+					LLToolTipMgr::instance().show(tooltip_msg);
+				}
+// [/RLVa:KB]
 			}
 		}
 	}
@@ -1203,7 +1300,15 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask)
 	if (!mHoverPick.isValid()) return TRUE;
 
 	LLViewerObject* hover_object = mHoverPick.getObject();
-	
+
+// [RLVa:KB] - Checked: RLVa-1.2.0
+	// NOTE: handleTooltipObject() will block HUD tooltips anyway but technically interact should only interfere with world interaction
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (hover_object) && (!hover_object->isHUDAttachment()) )
+	{
+		return TRUE;
+	}
+// [/RLVa:KB]
+
 	// update hover object and hover parcel
 	LLSelectMgr::getInstance()->setHoverObject(hover_object, mHoverPick.mObjectFace);
 	
@@ -1788,16 +1893,29 @@ BOOL LLToolPie::handleRightClickPick()
 				mute_msg = LLTrans::getString("MuteAvatar");
 			}
 
-			if (is_other_attachment)
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+			// Don't show the context menu on empty selection when fartouch restricted [see LLToolSelect::handleObjectSelection()]
+			if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) ||
+				 (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) )
 			{
-				gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
-				gMenuAttachmentOther->show(x, y);
+// [/RLVa:KB]
+				if (is_other_attachment)
+				{
+					gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
+					gMenuAttachmentOther->show(x, y);
+				}
+				else
+				{
+					gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
+					gMenuAvatarOther->show(x, y);
+				}
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
 			}
 			else
 			{
-				gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
-				gMenuAvatarOther->show(x, y);
+				make_ui_sound("UISndInvalidOp");
 			}
+// [/RLVa:KB]
 		}
 		else if (object->isAttachment())
 		{
@@ -1813,9 +1931,23 @@ BOOL LLToolPie::handleRightClickPick()
 				name = node->mName;
 			}
 
-			gMenuObject->show(x, y);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l
+			// Don't show the pie menu on empty selection when fartouch/interaction restricted
+			// (not entirely accurate in case of Tools / Select Only XXX [see LLToolSelect::handleObjectSelection()]
+			if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) ||
+				 (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) )
+			{
+// [/RLVa:KB]
+				gMenuObject->show(x, y);
 
-			showVisualContextMenuEffect();
+				showVisualContextMenuEffect();
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l
+			}
+			else
+			{
+				make_ui_sound("UISndInvalidOp");
+			}
+// [/RLVa:KB]
 		}
 	}
 	else if (mPick.mParticleOwnerID.notNull())
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 6391e675c551a7c7ffbf846097adbea8034a8352..290c5976da1652b9e5f6e79a2058267eaaf15fc7 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -62,6 +62,9 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 	virtual LLTool*		getOverrideTool(MASK mask);
 
 	LLPickInfo&			getPick() { return mPick; }
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	LLPickInfo&			getHoverPick() { return mHoverPick; }
+// [/RLVa:KB]
 	U8					getClickAction() { return mClickAction; }
 	LLViewerObject*		getClickActionObject() { return mClickActionObject; }
 	LLObjectSelection*	getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; }
diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp
index 814bade56ad675f882e2cb763cd78b7de0349cac..ea819811ef2d339dd78cf5a33dd209e9f344d3a8 100644
--- a/indra/newview/lltoolplacer.cpp
+++ b/indra/newview/lltoolplacer.cpp
@@ -43,6 +43,10 @@
 #include "llviewerwindow.h"
 #include "llworld.h"
 #include "llui.h"
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+// [/RLVa:KB]
 
 //Headers added for functions moved from viewer.cpp
 #include "llvograss.h"
@@ -123,6 +127,16 @@ BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj,
 		return FALSE;
 	}
 
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f
+	// NOTE: don't use surface_pos_global since for prims it will be the center of the prim while we need center + offset
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))
+	{
+		static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST);
+		if (dist_vec_squared(gAgent.getPositionGlobal(), pick.mPosGlobal) > s_nFartouchDist * s_nFartouchDist)
+			return FALSE;
+	}
+// [/RLVa:KB]
+
 	// Find the sim where the surface lives.
 	LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global);
 	if (!regionp)
@@ -240,7 +254,10 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
 	{
 		flags |= FLAGS_USE_PHYSICS;
 	}
-	if (create_selected)
+//	if (create_selected)
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.0.0b
+	if ( (create_selected) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) )
+// [/RLVa:KB]
 	{
 		flags |= FLAGS_CREATE_SELECTED;
 	}
@@ -498,6 +515,13 @@ BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask)
 {
 	BOOL added = TRUE;
 	
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) )
+	{
+		return TRUE; // Callers seem to expect a "did you handle it?" so we return TRUE rather than FALSE
+	}
+// [/RLVa:KB]
+
 	if (gSavedSettings.getBOOL("CreateToolCopySelection"))
 	{
 		added = addDuplicate(x, y);
diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp
index 1fcc9a07113cd4f8f4948dc035e346bdabd68681..2cd221c351b9340098ff23cfec9e6d8cd823647d 100644
--- a/indra/newview/lltoolselect.cpp
+++ b/indra/newview/lltoolselect.cpp
@@ -47,6 +47,11 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: RLVa-2.0.0
+#include "rlvactions.h"
+#include "rlvhelper.h"
+#include "llfloaterreg.h"
+// [/RLVa:KB]
 
 // Globals
 //extern BOOL gAllowSelectAvatar;
@@ -80,6 +85,36 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi
 	{
 		object = object->getRootEdit();
 	}
+
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
+	if ( (object) && (RlvActions::isRlvEnabled()) )
+	{
+		if (!RlvActions::canEdit(object))
+		{
+			if (!temp_select)
+				return LLSelectMgr::getInstance()->getSelection();
+			else if (LLToolMgr::instance().inBuildMode())
+				LLToolMgr::instance().toggleBuildMode();
+		}
+
+		if ( (RlvActions::hasBehaviour(RLV_BHVR_FARTOUCH)) && ((!object->isAttachment()) || (!object->permYouOwner())) )
+		{
+			static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST);
+			float nFartouchDistSq = s_nFartouchDist * s_nFartouchDist;
+			// NOTE: recheck why we did it this way, might be able to simplify
+			if ( (dist_vec_squared(gAgent.getPositionAgent(), object->getPositionRegion()) > nFartouchDistSq) &&
+			     (dist_vec_squared(gAgent.getPositionAgent(), pick.mIntersection) > nFartouchDistSq) )
+			{
+				if ( (LLFloaterReg::instanceVisible("build")) && (pick.mKeyMask != MASK_SHIFT) && (pick.mKeyMask != MASK_CONTROL) )
+					LLSelectMgr::getInstance()->deselectAll();
+				return LLSelectMgr::getInstance()->getSelection();
+			}
+			else if (LLToolMgr::instance().inBuildMode())
+				LLToolMgr::instance().toggleBuildMode();
+		}
+	}
+// [/RLVa:KB]
+
 	BOOL select_owned = gSavedSettings.getBOOL("SelectOwnedOnly");
 	BOOL select_movable = gSavedSettings.getBOOL("SelectMovableOnly");
 	
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index b015cde45d699f75d62f78d4ea4dfefc7909181d..5ff2771922806af651491b47b189c4377d6ed440 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -62,6 +62,10 @@
 #include "llworldmapview.h"
 #include "llviewercontrol.h"
 
+// [RLVa:KB]
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 const F32 DESTINATION_REACHED_RADIUS    = 3.0f;
 const F32 DESTINATION_VISITED_RADIUS    = 6.0f;
 
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 57a0195d23ea41ed3074e0bbb4595422460b5146..4b0a36ddcd788dfffd63cd90ff2af304e808ecb8 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -41,6 +41,10 @@
 #include "llworld.h"
 #include "lltoolmgr.h"
 #include "llviewerjoystick.h"
+// [RLVa:KB] - RLVa-2.0.0
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Linden library includes
 #include "lldrawable.h"
@@ -359,6 +363,11 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 		{
 			z_far = gAgentCamera.mDrawDistance;
 		}
+
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		if (RlvActions::hasBehaviour(RLV_BHVR_FARTOUCH))
+			z_far = RlvActions::getModifierValue<float>(RLV_MODIFIER_FARTOUCHDIST);
+// [/RLVa:KB]
 	}
 	else
 	{
@@ -876,6 +885,12 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
 
 void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) 
 {
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	F32 nCamFOVMin, nCamFOVMax;
+	if ( (RlvActions::isRlvEnabled()) && (RlvActions::getCameraFOVLimits(nCamFOVMin, nCamFOVMax)) )
+		vertical_fov_rads = llclamp(vertical_fov_rads, nCamFOVMin, nCamFOVMax);
+// [/RLVa:KB]
+
 	vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
 	setView(vertical_fov_rads);
 	mCameraFOVDefault = vertical_fov_rads; 
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 16f40fb747393d55ff6f6c0f177040f065062470..e267a8f31e59c517e03fdc33023f6f21ce58f69c 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -75,6 +75,9 @@
 #include "llslurl.h"
 #include "llstartup.h"
 #include "llupdaterservice.h"
+// [RLVa:KB] - Checked: 2015-12-27 (RLVa-1.5.0)
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 // Third party library includes
 #include <boost/algorithm/string.hpp>
@@ -741,6 +744,9 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged));
 	gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged));
 	gSavedSettings.getControl("LoginLocation")->getSignal()->connect(boost::bind(&handleLoginLocationChanged));
+// [RLVa:KB] - Checked: 2015-12-27 (RLVa-1.5.0)
+	gSavedSettings.getControl("RestrainedLove")->getSignal()->connect(boost::bind(&RlvSettings::onChangedSettingMain, _2));
+// [/RLVa:KB]
 }
 
 #if TEST_CACHED_CONTROL
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index afa00e3e6e54dd6c68fe34250eda3c5536381e7b..f631ecc9c2b11e8d8bbf107f1a0a4f749f2d91ca 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -78,6 +78,10 @@
 #include "llwaterparammanager.h"
 #include "llpostprocess.h"
 #include "llscenemonitor.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 extern LLPointer<LLViewerTexture> gStartTexture;
 extern bool gShiftFrame;
@@ -493,6 +497,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			// No teleport in progress
 			gViewerWindow->setShowProgress(FALSE);
 			gTeleportDisplay = FALSE;
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+			LLViewerParcelMgr::getInstance()->onTeleportDone();
+// [/SL:KB]
 			break;
 		}
 	}
@@ -1073,7 +1080,11 @@ void render_hud_attachments()
 	glh::matrix4f current_mod = glh_get_current_modelview();
 
 	// clamp target zoom level to reasonable values
-	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
+//	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c
+	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, (!gRlvAttachmentLocks.hasLockedHUD()) ? 0.1f : 0.85f, 1.f);
+// [/RLVa:KB]
+
 	// smoothly interpolate current zoom level
 	gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLSmoothInterpolation::getInterpolant(0.03f));
 
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 6d13d28e18fa45722988fda61c823b15df151024..4a4975ee9ae37144b718abf6bf097c4b4ae11576 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -156,7 +156,9 @@
 #include "llsyswellwindow.h"
 
 // *NOTE: Please add files in alphabetical order to keep merges easy.
-
+// [RLVa:KB] - Checked: 2010-03-11
+#include "rlvfloaters.h"
+// [/RLVa:KB]
 // handle secondlife:///app/openfloater/{NAME} URLs
 class LLFloaterOpenHandler : public LLCommandHandler
 {
@@ -321,6 +323,12 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>);
 	LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>);
 	LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>);
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	LLFloaterReg::add("rlv_behaviours", "floater_rlv_behaviours.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterBehaviours>);
+	LLFloaterReg::add("rlv_console", "floater_rlv_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterConsole>);
+	LLFloaterReg::add("rlv_locks", "floater_rlv_locks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterLocks>);
+	LLFloaterReg::add("rlv_strings", "floater_rlv_strings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterStrings>);
+// [/RLVa:KB]
 	
 	LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>);
 	LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>);
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 4f5e2a6568447bf74549484292392f1b19066a05..67cea002204b259cabe26bb55a73ae998923e831 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -69,6 +69,9 @@
 #include "llfloaterperms.h"
 #include "llclipboard.h"
 #include "llhttpretrypolicy.h"
+// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11)
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 // do-nothing ops for use in callbacks.
 void no_op_inventory_func(const LLUUID&) {} 
@@ -1683,6 +1686,65 @@ void create_new_item(const std::string& name,
 						  cb);
 }	
 
+// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11)
+void sync_inventory_folder(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLInventoryModel::item_array_t& items_to_add, LLInventoryModel::item_array_t& items_to_remove)
+{
+	LLInventoryModel::item_array_t curItems, newItems = items;
+
+	// Grab the current contents
+	LLInventoryModel::cat_array_t cats;
+	gInventory.collectDescendents(folder_id, cats, curItems, LLInventoryModel::EXCLUDE_TRASH);
+
+	// Purge everything in curItems that isn't part of newItems
+	for (LLInventoryModel::item_array_t::const_iterator itCurItem = curItems.begin(); itCurItem != curItems.end(); ++itCurItem)
+	{
+		LLViewerInventoryItem* pItem = *itCurItem;
+		if (std::find_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) == newItems.end())
+		{
+			// Item doesn't exist in newItems => purge (if it's a link)
+			if ( (pItem->getIsLinkType()) && 
+				 (LLAssetType::AT_LINK_FOLDER != pItem->getActualType()) && 
+			     (items_to_remove.end() == std::find(items_to_remove.begin(), items_to_remove.end(), pItem)) )
+			{
+				items_to_remove.push_back(pItem);
+			}
+		}
+		else
+		{
+			// Item exists in newItems => remove *all* occurances in newItems (removes duplicate COF links to this item as well)
+			newItems.erase(std::remove_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), newItems.end());
+		}
+	}
+
+	// Whatever remains in newItems will need to have a link created
+	for (LLInventoryModel::item_array_t::const_iterator itNewItem = newItems.begin(); itNewItem != newItems.end(); ++itNewItem)
+	{
+		LLViewerInventoryItem* pItem = *itNewItem;
+		if (items_to_add.end() == std::find(items_to_add.begin(), items_to_add.end(), pItem))
+			items_to_add.push_back(pItem);
+	}
+}
+
+void link_inventory_items(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb)
+{
+	for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
+	{
+		const LLViewerInventoryItem* pItem = *itItem;
+		link_inventory_object(folder_id, pItem, cb);
+	}
+}
+
+void remove_inventory_items(const LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb)
+{
+	for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
+	{
+		const LLViewerInventoryItem* pItem = *itItem;
+		if (pItem->getIsLinkType())
+			remove_inventory_item(pItem->getUUID(), cb);
+	}
+}
+// [/RLVa:KB]
+
 void slam_inventory_folder(const LLUUID& folder_id,
 						   const LLSD& contents,
 						   LLPointer<LLInventoryCallback> cb)
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 11ee4768aaafea802940cefab0af232970a6dca5..c5d8487b6602620386b250647950c2fed83fdc7c 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -172,6 +172,12 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
 	if (isObjectAttached(object))
 	{
 		LL_INFOS() << "(same object re-attached)" << LL_ENDL;
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+		if ( (object->permYouOwner()) && (gAgentAvatarp) )
+		{
+			gAgentAvatarp->removePendingDetach(object->getID());
+		}
+// [/SL:KB]
 		removeObject(object);
 		// Pass through anyway to let setupDrawable()
 		// re-connect object to the joint correctly
diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp
index e44d80b7ceab33405c2bdbbc52c6cb9ffdea8ce3..06e1e64300527a18a9772fdee8bbef7f879903ff 100644
--- a/indra/newview/llviewerjoystick.cpp
+++ b/indra/newview/llviewerjoystick.cpp
@@ -326,8 +326,11 @@ void LLViewerJoystick::handleRun(F32 inc)
 		if (1 == mJoystickRun)
 		{
 			++mJoystickRun;
-			gAgent.setRunning();
-			gAgent.sendWalkRun(gAgent.getRunning());
+//			gAgent.setRunning();
+//			gAgent.sendWalkRun(gAgent.getRunning());
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+			gAgent.setTempRun();
+// [/RLVa:KB]
 		}
 		else if (0 == mJoystickRun)
 		{
@@ -342,8 +345,11 @@ void LLViewerJoystick::handleRun(F32 inc)
 			--mJoystickRun;
 			if (0 == mJoystickRun)
 			{
-				gAgent.clearRunning();
-				gAgent.sendWalkRun(gAgent.getRunning());
+//				gAgent.clearRunning();
+//				gAgent.sendWalkRun(gAgent.getRunning());
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+				gAgent.clearTempRun();
+// [/RLVa:KB]
 			}
 		}
 	}
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index 2186ed3c5297d508e58c800aa262d3a5ed132f23..d84c1c93c8790f747acba3aaedc0a7a0def9217e 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -42,6 +42,9 @@
 #include "llvoavatarself.h"
 #include "llfloatercamera.h"
 #include "llinitparam.h"
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Constants
@@ -89,14 +92,18 @@ void agent_push_down( EKeystate s )
 
 static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
 {
-	if (gAgent.mDoubleTapRunMode == mode &&
-		gAgent.getRunning() &&
-		!gAgent.getAlwaysRun())
-	{
-		// Turn off temporary running.
-		gAgent.clearRunning();
-		gAgent.sendWalkRun(gAgent.getRunning());
-	}
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+	if ( (gAgent.mDoubleTapRunMode == mode) && (gAgent.getTempRun()) )
+		gAgent.clearTempRun();
+// [/RLVa:KB]
+//	if (gAgent.mDoubleTapRunMode == mode &&
+//		gAgent.getRunning() &&
+//		!gAgent.getAlwaysRun())
+//	{
+//		// Turn off temporary running.
+//		gAgent.clearRunning();
+//		gAgent.sendWalkRun(gAgent.getRunning());
+//	}
 }
 
 static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
@@ -116,8 +123,11 @@ static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode m
 		{
 			// Same walk-key was pushed again quickly; this is a
 			// double-tap so engage temporary running.
-			gAgent.setRunning();
-			gAgent.sendWalkRun(gAgent.getRunning());
+//			gAgent.setRunning();
+//			gAgent.sendWalkRun(gAgent.getRunning());
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+			gAgent.setTempRun();
+// [/RLVa:KB]
 		}
 
 		// Pressing any walk-key resets the double-tap timer
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 6ed063e06637fd8c5238612c4d97742177370450..2fca1a7a13cd5163a4c31f6115895e7ffe1fed7c 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -2992,7 +2992,10 @@ void LLViewerMediaImpl::updateImagesMediaStreams()
 //////////////////////////////////////////////////////////////////////////////////////////
 LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
 {
-	if(mTextureId.isNull())
+//	if(mTextureId.isNull())
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	if ( (mTextureId.isNull()) || ((LLViewerFetchedTexture::sDefaultDiffuseImagep.notNull()) && (LLViewerFetchedTexture::sDefaultDiffuseImagep->getID() == mTextureId)) )
+// [/SL:KB]
 	{
 		// The code that created this instance will read from the plugin's bits.
 		return NULL;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 42c6cc7758f9bd372bbc25cab1a2a790fe2d8b10..f62fcd4d6c8109612a9d4901c1cdcfe844720a55 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -133,6 +133,11 @@
 #include "llpathfindingmanager.h"
 #include "llstartup.h"
 #include "boost/unordered_map.hpp"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 using namespace LLAvatarAppearanceDefines;
 
@@ -1208,7 +1213,24 @@ class LLAdvancedToggleWireframe : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		gUseWireframe = !(gUseWireframe);
+// [RLVa:KB] - Checked: RLVa-2.0.0
+		bool fRlvBlockWireframe = gRlvAttachmentLocks.hasLockedHUD();
+		if ( (!gUseWireframe) && (fRlvBlockWireframe) )
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_WIREFRAME);
+		set_use_wireframe( (!gUseWireframe) && (!fRlvBlockWireframe) );
+		return true;
+	}
+};
+
+// Called from rlvhandler.cpp
+void set_use_wireframe(BOOL useWireframe)
+	{
+		if (gUseWireframe == useWireframe)
+			return;
+
+		gUseWireframe = useWireframe;
+// [/RLVa:KB]
+//		gUseWireframe = !(gUseWireframe);
 
 		if (gUseWireframe)
 		{
@@ -1227,9 +1249,9 @@ class LLAdvancedToggleWireframe : public view_listener_t
 			LLViewerShaderMgr::instance()->setShaders();
 		}
 
-		return true;
+//		return true;
 	}
-};
+//};
 
 class LLAdvancedCheckWireframe : public view_listener_t
 {
@@ -2599,6 +2621,15 @@ void handle_object_touch()
 
 	LLPickInfo pick = LLToolPie::getInstance()->getPick();
 
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+		// NOTE: fallback code since we really shouldn't be getting an active selection if we can't touch this
+		if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, pick.mObjectOffset)) )
+		{
+			RLV_ASSERT(false);
+			return;
+		}
+// [/RLVa:KB]
+
 	// *NOTE: Hope the packets arrive safely and in order or else
 	// there will be some problems.
 	// *TODO: Just fix this bad assumption.
@@ -2646,6 +2677,14 @@ bool enable_object_touch(LLUICtrl* ctrl)
 		new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch());
 	}
 
+// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g
+	if ( (rlv_handler_t::isEnabled()) && (new_value) )
+	{
+		// RELEASE-RLVa: [RLVa-1.2.1] Make sure this stays in sync with handle_object_touch()
+		new_value = gRlvHandler.canTouch(obj, LLToolPie::getInstance()->getPick().mObjectOffset);
+	}
+// [/RLVa:KB]
+
 	std::string item_name = ctrl->getName();
 	init_default_item_label(item_name);
 
@@ -2678,7 +2717,11 @@ bool enable_object_touch(LLUICtrl* ctrl)
 
 void handle_object_open()
 {
-	LLFloaterReg::showInstance("openobject");
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+	if (enable_object_open())
+		LLFloaterReg::showInstance("openobject");
+// [/RLVa:KB]
+//	LLFloaterReg::showInstance("openobject");
 }
 
 bool enable_object_open()
@@ -2908,7 +2951,17 @@ bool enable_object_edit()
 	} 
 	else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound())
 	{
-		enable = true;
+//		enable = true;
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
+		bool fRlvCanEdit = (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDITOBJ));
+		if (!fRlvCanEdit)
+		{
+			LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+			RlvSelectIsEditable f;
+			fRlvCanEdit = (hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) == NULL);
+		}
+		enable = fRlvCanEdit;
+// [/RLVa:KB]
 	}
 
 	return enable;
@@ -2963,7 +3016,10 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t
 			{
 				LLVOAvatar::attachment_map_t::iterator curiter = iter++;
 				LLViewerJointAttachment* attachment = curiter->second;
-				if (attachment->getNumObjects() > 0)
+//				if (attachment->getNumObjects() > 0)
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+				if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) )
+// [/RLVa:KB]
 				{
 					new_value = true;
 					break;
@@ -3006,7 +3062,10 @@ bool enable_object_mute()
 		bool is_linden =
 			lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden");
 		bool is_self = avatar->isSelf();
-		return !is_linden && !is_self;
+//		return !is_linden && !is_self;
+// [RLVa:KB] - Checked: RLVa-1.2.1
+		return !is_linden && !is_self && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID()));
+// [/RLVa:KB]
 	}
 	else
 	{
@@ -3115,6 +3174,10 @@ class LLObjectMute : public view_listener_t
 			avatar->mNeedsImpostorUpdate = TRUE;
 
 			id = avatar->getID();
+// [RLVa:KB] - Checked: RLVa-1.0.0
+			if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, id))
+				return true;
+// [/RLVa:KB]
 
 			LLNameValue *firstname = avatar->getNVPair("FirstName");
 			LLNameValue *lastname = avatar->getNVPair("LastName");
@@ -3267,7 +3330,10 @@ void handle_avatar_freeze(const LLSD& avatar_id)
 			if (!fullname.empty())
 			{
 				LLSD args;
-				args["AVATAR_NAME"] = fullname;
+//				args["AVATAR_NAME"] = fullname;
+// [RLVa:KB] - Checked: RLVa-1.0.0
+				args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname);
+// [/RLVa:KB]
 				LLNotificationsUtil::add("FreezeAvatarFullname",
 							args,
 							payload,
@@ -3396,7 +3462,10 @@ void handle_avatar_eject(const LLSD& avatar_id)
 				if (!fullname.empty())
 				{
     				LLSD args;
-    				args["AVATAR_NAME"] = fullname;
+//					args["AVATAR_NAME"] = fullname;
+// [RLVa:KB] - Checked: RLVa-1.0.0
+					args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname);
+// [/RLVa:KB]
     				LLNotificationsUtil::add("EjectAvatarFullname",
     							args,
     							payload,
@@ -3416,7 +3485,10 @@ void handle_avatar_eject(const LLSD& avatar_id)
 				if (!fullname.empty())
 				{
     				LLSD args;
-    				args["AVATAR_NAME"] = fullname;
+//					args["AVATAR_NAME"] = fullname;
+// [RLVa:KB] - Checked: RLVa-1.0.0
+					args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname);
+// [/RLVa:KB]
     				LLNotificationsUtil::add("EjectAvatarFullnameNoBan",
     							args,
     							payload,
@@ -3647,7 +3719,10 @@ class LLSelfStandUp : public view_listener_t
 
 bool enable_standup_self()
 {
-    return isAgentAvatarValid() && gAgentAvatarp->isSitting();
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+	return isAgentAvatarValid() && gAgentAvatarp->isSitting() && !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT);
+// [/RLVa:KB]
+//	return isAgentAvatarValid() && gAgentAvatarp->isSitting();
 }
 
 class LLSelfSitDown : public view_listener_t
@@ -3661,7 +3736,10 @@ class LLSelfSitDown : public view_listener_t
 
 bool enable_sitdown_self()
 {
-    return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying();
+// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying() && !gRlvHandler.hasBehaviour(RLV_BHVR_SIT);
+// [/RLVa:KB]
+//    return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying();
 }
 
 class LLCheckPanelPeopleTab : public view_listener_t
@@ -3905,7 +3983,10 @@ class LLAvatarEnableAddFriend : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
-		bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID());
+//		bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID());
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID()));
+// [/RLVa:KB]
 		return new_value;
 	}
 };
@@ -3939,7 +4020,10 @@ class LLEditEnableCustomizeAvatar : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		bool new_value = gAgentWearables.areWearablesLoaded();
+//		bool new_value = gAgentWearables.areWearablesLoaded();
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+		bool new_value = gAgentWearables.areWearablesLoaded() && ((!rlv_handler_t::isEnabled()) || (RlvActions::canStand()));
+// [/RLVa:KB]
 		return new_value;
 	}
 };
@@ -3971,6 +4055,16 @@ class LLEnableEditPhysics : public view_listener_t
 
 bool is_object_sittable()
 {
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.1.0j
+	// RELEASE-RLVa: [SL-2.2.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLPickInfo& pick = LLToolPie::getInstance()->getPick();
+		if ( (pick.mObjectID.notNull()) && (!RlvActions::canSit(pick.getObject(), pick.mObjectOffset)) )
+			return false;
+	}
+// [/RLVa:KB]
+
 	LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
 
 	if (object && object->getPCode() == LL_PCODE_VOLUME)
@@ -4002,8 +4096,23 @@ void handle_object_sit_or_stand()
 
 	// get object selection offset 
 
-	if (object && object->getPCode() == LL_PCODE_VOLUME)
+//	if (object && object->getPCode() == LL_PCODE_VOLUME)
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+	if ( (object && object->getPCode() == LL_PCODE_VOLUME) && 
+		 ((!rlv_handler_t::isEnabled()) || (RlvActions::canSit(object, pick.mObjectOffset))) )
+// [/RLVa:KB]
 	{
+// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) )
+		{
+			if (gAgentAvatarp->isSitting())
+			{
+				gAgent.standUp();
+				return;
+			}
+			gRlvHandler.setSitSource(gAgent.getPositionGlobal());
+		}
+// [/RLVa:KB]
 
 		gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
 		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
@@ -4033,6 +4142,11 @@ class LLLandSit : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f
+		if ( (rlv_handler_t::isEnabled()) && ((!RlvActions::canStand()) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) )
+			return true;
+// [/RLVa:KB]
+
 		gAgent.standUp();
 		LLViewerParcelMgr::getInstance()->deselectLand();
 
@@ -4577,6 +4691,17 @@ void handle_take_copy()
 {
 	if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
 
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) )
+	{
+		// Allow only if the avie isn't sitting on any of the selected objects
+		LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+		RlvSelectIsSittingOn f(gAgentAvatarp);
+		if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != NULL) )
+			return;
+	}
+// [/RLVa:KB]
+
 	const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
 	derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
 }
@@ -4591,7 +4716,10 @@ class LLObjectReturn : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
-		
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.4.0a) | Modified: RLVa-1.0.0b
+		if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) return true;
+// [/RLVa:KB]
+
 		mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
 
 		// Save selected objects, so that we still know what to return after the confirmation dialog resets selection.
@@ -4638,6 +4766,12 @@ class LLObjectEnableReturn : public view_listener_t
 			// Do not enable if nothing selected
 			return false;
 		}
+// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
+		if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) )
+		{
+			return false;
+		}
+// [/RLVa:KB]
 #ifdef HACKED_GODLIKE_VIEWER
 		bool new_value = true;
 #else
@@ -4666,11 +4800,14 @@ void handle_take()
 {
 	// we want to use the folder this was derezzed from if it's
 	// available. Otherwise, derez to the normal place.
-	if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
+//	if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+	if ( (LLSelectMgr::getInstance()->getSelection()->isEmpty()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) )
+// [/RLVa:KB]
 	{
 		return;
 	}
-	
+
 	BOOL you_own_everything = TRUE;
 	BOOL locked_but_takeable_object = FALSE;
 	LLUUID category_id;
@@ -4813,7 +4950,10 @@ bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelect
 // one item selected can be copied to inventory.
 BOOL enable_take()
 {
-	if (sitting_on_selection())
+//	if (sitting_on_selection())
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+	if ( (sitting_on_selection()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) )
+// [/RLVa:KB]
 	{
 		return FALSE;
 	}
@@ -5279,8 +5419,12 @@ class LLToolsReleaseKeys : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		gAgent.forceReleaseControls();
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+			return true;
+// [/RLVa:KB]
 
+		gAgent.forceReleaseControls();
 		return true;
 	}
 };
@@ -5289,7 +5433,11 @@ class LLToolsEnableReleaseKeys : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		return gAgent.anyControlGrabbed();
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a
+		return (gAgent.anyControlGrabbed()) && 
+			( (!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) );
+// [/RLVa:KB]
+//		return gAgent.anyControlGrabbed();
 	}
 };
 
@@ -5686,6 +5834,11 @@ void show_debug_menus()
 
 		gMenuBarView->setItemVisible("Advanced", debug);
 // 		gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden
+
+// [RLVa:KB] - Checked: 2011-08-16 (RLVa-1.4.0b) | Modified: RLVa-1.4.0b
+		// NOTE: this is supposed to execute whether RLVa is enabled or not
+		rlvMenuToggleVisible();
+// [/RLVa:KB]
 		
 		gMenuBarView->setItemVisible("Debug", qamode);
 		gMenuBarView->setItemEnabled("Debug", qamode);
@@ -5801,16 +5954,16 @@ class LLWorldAlwaysRun : public view_listener_t
 		if (gAgent.getAlwaysRun())
 		{
 			gAgent.clearAlwaysRun();
-			gAgent.clearRunning();
+//			gAgent.clearRunning();
 		}
 		else
 		{
 			gAgent.setAlwaysRun();
-			gAgent.setRunning();
+//			gAgent.setRunning();
 		}
 
 		// tell the simulator.
-		gAgent.sendWalkRun(gAgent.getAlwaysRun());
+//		gAgent.sendWalkRun(gAgent.getAlwaysRun());
 
 		// Update Movement Controls according to AlwaysRun mode
 		LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun());
@@ -5865,6 +6018,11 @@ class LLWorldCreateLandmark : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.0.0
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+			return true;
+// [/RLVa:KB]
+
 		LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
 
 		return true;
@@ -5875,12 +6033,24 @@ class LLWorldPlaceProfile : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+			return true;
+// [/RLVa:KB]
+
 		LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent"));
 
 		return true;
 	}
 };
 
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+bool enable_place_profile()
+{
+	return LLFloaterSidePanelContainer::canShowPanel("places", LLSD().with("type", "agent"));
+}
+// [/RLVa:KB]
+
 void handle_look_at_selection(const LLSD& param)
 {
 	const F32 PADDING_FACTOR = 1.75f;
@@ -5950,7 +6120,10 @@ class LLAvatarInviteToGroup : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::inviteToGroup(avatar->getID());
 		}
@@ -5963,7 +6136,10 @@ class LLAvatarAddFriend : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar && !LLAvatarActions::isFriend(avatar->getID()))
+//		if(avatar && !LLAvatarActions::isFriend(avatar->getID()))
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		if ( (avatar && !LLAvatarActions::isFriend(avatar->getID())) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) )
+// [/RLVa:KB]
 		{
 			request_friendship(avatar->getID());
 		}
@@ -6004,7 +6180,10 @@ class LLAvatarAddContact : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) )
+// [/RLVa:KB]
 		{
 			create_inventory_callingcard(avatar->getID());
 		}
@@ -6068,7 +6247,10 @@ bool enable_pay_avatar()
 {
 	LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
 	LLVOAvatar* avatar = find_avatar_from_object(obj);
-	return (avatar != NULL);
+//	return (avatar != NULL);
+// [RLVa:KB] - Checked: RLVa-1.2.1
+	return (avatar != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID()));
+// [/RLVa:KB]
 }
 
 bool enable_pay_object()
@@ -6088,7 +6270,10 @@ bool enable_pay_object()
 bool enable_object_stand_up()
 {
 	// 'Object Stand Up' menu item is enabled when agent is sitting on selection
-	return sitting_on_selection();
+//	return sitting_on_selection();
+// [RLVa:KB] - Checked: 2010-07-24 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	return sitting_on_selection() && ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) );
+// [/RLVa:KB]
 }
 
 bool enable_object_sit(LLUICtrl* ctrl)
@@ -6113,6 +6298,17 @@ bool enable_object_sit(LLUICtrl* ctrl)
 			gMenuHolder->childSetValue(item_name, get_default_item_label(item_name));
 		}
 	}
+
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+		// RELEASE-RLVA: [SL-2.2.0] Make this match what happens in handle_object_sit_or_stand()
+		if (rlv_handler_t::isEnabled())
+		{
+			const LLPickInfo& pick = LLToolPie::getInstance()->getPick();
+			if (pick.mObjectID.notNull())
+				sitting_on_sel = !RlvActions::canSit(pick.getObject(), pick.mObjectOffset);
+		}
+// [/RLVa:KB]
+
 	return !sitting_on_sel && is_object_sittable();
 }
 
@@ -6367,7 +6563,10 @@ class LLShowAgentProfile : public view_listener_t
 		}
 
 		LLVOAvatar* avatar = find_avatar_from_object(agent_id);
-		if (avatar)
+//		if (avatar)
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		if ( (avatar) && ((RlvActions::canShowName(RlvActions::SNC_DEFAULT, agent_id)) || (gAgent.getID() == agent_id)) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::showProfile(avatar->getID());
 		}
@@ -6516,6 +6715,19 @@ class LLObjectAttachToAvatar : public view_listener_t
 			LLViewerJointAttachment* attachment_point = NULL;
 			if (index > 0)
 				attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL);
+
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f
+			// RELEASE-RLVa: [SL-2.2.0] If 'index != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()]
+			if ( (rlv_handler_t::isEnabled()) &&
+				 ( ((!index) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) ||		    // Can't wear on default
+				   ((index) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(attachment_point)) == 0)) ||	// or non-attachable attachpt
+				   (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) )											    // Attach on object == "Take"
+			{
+				setObjectSelection(NULL); // Clear the selection or it'll get stuck
+				return true;
+			}
+// [/RLVa:KB]
+
 			confirmReplaceAttachment(0, attachment_point);
 		}
 		return true;
@@ -6660,6 +6872,24 @@ class LLAttachmentDrop : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5
+		if (rlv_handler_t::isEnabled())
+		{
+			if (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE))
+			{
+				// NOTE: copy/paste of the code in enable_detach()
+				LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection();
+				RlvSelectHasLockedAttach f;
+				if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) )
+					return true;
+			}
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ))
+			{
+				return true;
+			}
+		}
+// [/RLVa:KB]
+
 		LLSD payload;
 		LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
 
@@ -6685,14 +6915,21 @@ class LLAttachmentDetachFromPoint : public view_listener_t
 	{
 		uuid_vec_t ids_to_remove;
 		const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL);
-		if (attachment->getNumObjects() > 0)
+//		if (attachment->getNumObjects() > 0)
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+		if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) )
+// [/RLVa:KB]
 		{
 			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin();
 				 iter != attachment->mAttachedObjects.end();
 				 iter++)
 			{
 				LLViewerObject *attached_object = (*iter);
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+				if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(attached_object)) )
+					continue;
 				ids_to_remove.push_back(attached_object->getAttachmentItemID());
+// [/RLVa:KB]
 			}
         }
 		if (!ids_to_remove.empty())
@@ -6705,6 +6942,10 @@ class LLAttachmentDetachFromPoint : public view_listener_t
 
 static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
 {
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f
+	// RELEASE-RLVa: [SL-2.2.0] When attaching to a specific point the object will be "add attached" [see LLSelectMgr::sendAttach()]
+	bool fRlvEnable = true;
+// [/RLVa:KB]
 	std::string label;
 	LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl);
 	if (menu)
@@ -6729,9 +6970,18 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
 				}
 			}
 		}
+
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f
+		if (rlv_handler_t::isEnabled())
+			fRlvEnable = (!gRlvAttachmentLocks.isLockedAttachmentPoint(attachment, RLV_LOCK_ADD));
+// [/RLVa:KB]
+
 		menu->setLabel(label);
 	}
-	return true;
+//	return true;
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	return fRlvEnable;
+// [/RLVa:KB]
 }
 
 class LLAttachmentDetach : public view_listener_t
@@ -6770,6 +7020,17 @@ class LLAttachmentDetach : public view_listener_t
 			return true;
 		}
 
+// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5
+		// NOTE: copy/paste of the code in enable_detach()
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+		{
+			LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection();
+			RlvSelectHasLockedAttach f;
+			if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) )
+				return true;
+		}
+// [/RLVa:KB]
+
 		LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID());
 
 		return true;
@@ -6846,7 +7107,10 @@ class LLAttachmentEnableDrop : public view_listener_t
 		}
 		
 		//now check to make sure that the item is actually in the inventory before we enable dropping it
-		bool new_value = enable_detach() && can_build && item;
+//		bool new_value = enable_detach() && can_build && item;
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b
+		bool new_value = enable_detach() && can_build && item && (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ));
+// [/RLVa:KB]
 
 		return new_value;
 	}
@@ -6871,6 +7135,20 @@ BOOL enable_detach(const LLSD&)
 		// ...if it's you, good to detach
 		if (avatar->getID() == gAgent.getID())
 		{
+// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5
+			// NOTE: this code is reused as-is in LLAttachmentDetach::handleEvent() and LLAttachmentDrop::handleEvent()
+			//       so any changes here should be reflected there as well
+
+			// RELEASE-RLVa: [SL-2.2.0] LLSelectMgr::sendDetach() and LLSelectMgr::sendDropAttachment() call sendListToRegions with
+			//                          SEND_ONLY_ROOTS so we only need to examine the roots which saves us time
+			if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+			{
+				LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection();
+				RlvSelectHasLockedAttach f;
+				if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) )
+					return FALSE;
+			}
+// [/RLVa:KB]
 			return TRUE;
 		}
 
@@ -6890,8 +7168,33 @@ class LLAttachmentEnableDetach : public view_listener_t
 };
 
 // Used to tell if the selected object can be attached to your avatar.
-BOOL object_selected_and_point_valid()
+//BOOL object_selected_and_point_valid()
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+BOOL object_selected_and_point_valid(const LLSD& sdParam)
+// [/RLVa:KB]
 {
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f
+	if (rlv_handler_t::isEnabled())
+	{
+		if (!isAgentAvatarValid())
+			return FALSE;
+
+		// RELEASE-RLVa: [SL-2.2.0] Look at the caller graph for this function on every new release
+		//   - object_is_wearable() => dead code [sdParam == 0 => default attach point => OK!]
+		//   - enabler set up in LLVOAvatarSelf::buildMenus() => Rezzed prim / Put On / "Attach To" [sdParam == idxAttachPt]
+		//   - "Object.EnableWear" enable => Rezzed prim / Put On / "Wear" or "Add" [sdParam blank]
+		// RELEASE-RLVa: [SL-2.2.0] If 'idxAttachPt != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()]
+		const LLViewerJointAttachment* pAttachPt = 
+			get_if_there(gAgentAvatarp->mAttachmentPoints, sdParam.asInteger(), (LLViewerJointAttachment*)NULL);
+		if ( ((!pAttachPt) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) ||		// Can't wear on default attach point
+			 ((pAttachPt) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(pAttachPt)) == 0)) ||	// or non-attachable attach point
+			 (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) )												// Attach on object == "Take"
+		{
+			return FALSE;
+		}
+	}
+// [/RLVa:KB]
+
 	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 	for (LLObjectSelection::root_iterator iter = selection->root_begin();
 		 iter != selection->root_end(); iter++)
@@ -6920,9 +7223,12 @@ BOOL object_selected_and_point_valid()
 }
 
 
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+/*
 BOOL object_is_wearable()
 {
-	if (!object_selected_and_point_valid())
+//	if (!object_selected_and_point_valid())
+	if (!object_selected_and_point_valid(LLSD(0)))
 	{
 		return FALSE;
 	}
@@ -6942,7 +7248,8 @@ BOOL object_is_wearable()
 	}
 	return FALSE;
 }
-
+*/
+// [/RLVa:KB]
 
 class LLAttachmentPointFilled : public view_listener_t
 {
@@ -6952,7 +7259,12 @@ class LLAttachmentPointFilled : public view_listener_t
 		LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger());
 		if (found_it != gAgentAvatarp->mAttachmentPoints.end())
 		{
-			enable = found_it->second->getNumObjects() > 0;
+//			enable = found_it->second->getNumObjects() > 0;
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+			// Enable the option if there is at least one attachment on this attachment point that can be detached
+			enable = (found_it->second->getNumObjects() > 0) && 
+				((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(found_it->second)));
+// [/RLVa:KB]
 		}
 		return enable;
 	}
@@ -6963,7 +7275,10 @@ class LLAvatarSendIM : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::startIM(avatar->getID());
 		}
@@ -6976,7 +7291,10 @@ class LLAvatarCall : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::startCall(avatar->getID());
 		}
@@ -6984,6 +7302,19 @@ class LLAvatarCall : public view_listener_t
 	}
 };
 
+// [RLVa:KB] - Checked: RLVa-1.2.1
+bool enable_avatar_call()
+{
+	if (RlvActions::isRlvEnabled())
+	{
+		const LLVOAvatar* pAvatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+		if ((!pAvatar) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, pAvatar->getID())))
+			return false;
+	}
+	return LLAvatarActions::canCall();
+}
+// [/RLVa:KB]
+
 namespace
 {
 	struct QueueObjects : public LLSelectedNodeFunctor
@@ -7051,6 +7382,17 @@ class LLToolsSelectedScriptAction : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a
+		// We'll allow resetting the scripts of objects on a non-attachable attach point since they wouldn't be able to circumvent anything
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+		{
+			LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+			RlvSelectHasLockedAttach f;
+			if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != NULL) )
+				return true;
+		}
+// [/RLVa:KB]
+
 		std::string action = userdata.asString();
 		bool mono = false;
 		std::string msg, name;
@@ -7194,12 +7536,30 @@ void handle_selected_material_info()
 
 void handle_test_male(void*)
 {
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	// TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this?
+	if ( (rlv_handler_t::isEnabled()) && 
+		 ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit");
 	//gGestureList.requestResetFromServer( TRUE );
 }
 
 void handle_test_female(void*)
 {
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	// TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this?
+	if ( (rlv_handler_t::isEnabled()) && 
+		 ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit");
 	//gGestureList.requestResetFromServer( FALSE );
 }
@@ -7368,6 +7728,22 @@ class LLSomethingSelectedNoHUD : public view_listener_t
 
 static bool is_editable_selected()
 {
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a
+	// RELEASE-RLVa: [SL-2.2.0] Check that this still isn't called by anything but script actions in the Build menu
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+	{
+		LLObjectSelectionHandle hSelection = LLSelectMgr::getInstance()->getSelection();
+
+		// NOTE: this is called for 5 different menu items so we'll trade accuracy for efficiency and only
+		//       examine root nodes (LLToolsSelectedScriptAction::handleEvent() will catch what we miss)
+		RlvSelectHasLockedAttach f;
+		if ( (hSelection->isAttachment()) && (hSelection->getFirstRootNode(&f)) )
+		{
+			return false;
+		}
+	}
+// [/RLVa:KB]
+
 	return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL);
 }
 
@@ -7412,7 +7788,11 @@ bool enable_object_take_copy()
 			{
 				virtual bool apply(LLViewerObject* obj)
 				{
-					return (!obj->permCopy() || obj->isAttachment());
+//					return (!obj->permCopy() || obj->isAttachment());
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+					return (!obj->permCopy() || obj->isAttachment()) || 
+						( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->getRoot() == obj) );
+// [/RLVa:KB]
 				}
 			} func;
 			const bool firstonly = true;
@@ -7517,7 +7897,10 @@ class LLWorldEnableCreateLandmark : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		return !LLLandmarkActions::landmarkAlreadyExists();
+//		return !LLLandmarkActions::landmarkAlreadyExists();
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.2.1
+		return (!LLLandmarkActions::landmarkAlreadyExists()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
 	}
 };
 
@@ -7538,6 +7921,10 @@ class LLWorldEnableTeleportHome : public view_listener_t
 		LLViewerRegion* regionp = gAgent.getRegion();
 		bool agent_on_prelude = (regionp && regionp->isPrelude());
 		bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude;
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f
+		enable_teleport_home &= 
+			(!rlv_handler_t::isEnabled()) || ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLM)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
+// [/RLVa:KB]
 		return enable_teleport_home;
 	}
 };
@@ -8008,7 +8395,10 @@ class LLViewHighlightTransparent : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
+//		LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
+		LLDrawPoolAlpha::sShowDebugAlpha = (!LLDrawPoolAlpha::sShowDebugAlpha) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT));
+// [/RLVa:KB]
 		return true;
 	}
 };
@@ -8220,6 +8610,11 @@ class LLViewShowHUDAttachments : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedHUD()) && (LLPipeline::sShowHUDAttachments) )
+			return true;
+// [/RLVa:KB]
+
 		LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments;
 		return true;
 	}
@@ -8240,8 +8635,15 @@ class LLEditEnableTakeOff : public view_listener_t
 	{
 		std::string clothing = userdata.asString();
 		LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
-		if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
+//		if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
+// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+		// NOTE: see below - enable if there is at least one wearable on this type that can be removed
+		if ( (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) && 
+			 ((!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(type))) )
+// [/RLVa:KB]
+		{
 			return LLAgentWearables::selfHasWearable(type);
+		}
 		return false;
 	}
 };
@@ -8262,6 +8664,22 @@ class LLEditTakeOff : public view_listener_t
 			{
 				// MULTI-WEARABLES: assuming user wanted to remove top shirt.
 				U32 wearable_index = gAgentWearables.getWearableCount(type) - 1;
+
+// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+				if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearable(type)) )
+				{
+					// We'll use the first wearable we come across that can be removed (moving from top to bottom)
+					for (; wearable_index >= 0; wearable_index--)
+					{
+						const LLViewerWearable* pWearable = gAgentWearables.getViewerWearable(type, wearable_index);
+						if (!gRlvWearableLocks.isLockedWearable(pWearable))
+							break;
+					}
+					if (wearable_index < 0)
+						return true;	// No wearable found that can be removed
+				}
+// [/RLVa:KB]
+
 				LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index);
 				LLAppearanceMgr::instance().removeItemFromAvatar(item_id);
 			}
@@ -8305,6 +8723,11 @@ class LLWorldEnvSettings : public view_listener_t
 {	
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV))
+			return true;
+// [/RLVa:KB]
+
 		std::string tod = userdata.asString();
 		
 		if (tod == "editor")
@@ -8569,6 +8992,9 @@ void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y)
 	{
 		landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
 	}
+// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+	landmark_item->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
 
 	if(gMenuHolder->hasVisibleMenu())
 	{
@@ -8724,6 +9150,9 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb");
 
 	view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark");
+// [RLVa:KB]
+	enable.add("World.EnablePlaceProfile", boost::bind(&enable_place_profile));
+// [/RLVa:KB]
 	view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation");
 	view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome");
 	view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand");
@@ -8989,7 +9418,10 @@ void initialize_menus()
 	commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector));
 	view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
 	view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
-	enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
+//	enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+	enable.add("Avatar.EnableCall", boost::bind(&enable_avatar_call));
+// [/RLVa:KB]
 	view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
 	view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile");
 	enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible));
@@ -9022,7 +9454,10 @@ void initialize_menus()
 	enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
 	enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
 	enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
-	enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+//	enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid, _2));
+// [/RLVa:KB]
 
 	enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up));
 	enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1));
@@ -9092,4 +9527,13 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected");
 	view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
 	view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
+
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	enable.add("RLV.MainToggleVisible", boost::bind(&rlvMenuMainToggleVisible, _1));
+	if (RlvActions::isRlvEnabled())
+	{
+		enable.add("RLV.CanShowName", boost::bind(&rlvMenuCanShowName));
+		enable.add("RLV.EnableIfNot", boost::bind(&rlvMenuEnableIfNot, _2));
+	}
+// [/RLVa:KB]
 }
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index b7bdf0015775bb61bfd4814f0019267c462ef3f1..36bf472cad58c5d37d0a9837e28d6b5f8e80fb15 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -38,6 +38,10 @@ class LLParcelSelection;
 class LLObjectSelection;
 class LLSelectNode;
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+void set_use_wireframe(BOOL useWireframe);
+// [/RLVa:KB]
+
 void initialize_edit_menu();
 void initialize_spellcheck_menu();
 void init_menus();
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 92df3866f72634a6bf7b78a7872f29aaf07f832e..8d1f3c1c2c27e8be052954bc295115ca56d3882d 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -114,6 +114,12 @@
 #include "llpanelplaceprofile.h"
 #include "llviewerregion.h"
 #include "llfloaterregionrestarting.h"
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvinventory.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 #include <boost/algorithm/string/split.hpp> //
 #include <boost/regex.hpp>
@@ -237,7 +243,18 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
 	    // modified_form->setElementEnabled("Accept", false);
 	    // modified_form->setElementEnabled("Decline", false);
 	    // notification_ptr->updateForm(modified_form);
-	    // notification_ptr->repost();
+// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5)
+//		// Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell
+//		/*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel();
+//		/*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL;
+//		if ( (!pToast) || (!pToast->getCanBeStored()) )
+//		{
+// [/SL:KB]
+//			notification_ptr->repost();
+// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5)
+//		}
+// [/SL:KB]
+
     }
 
 	return false;
@@ -1493,7 +1510,14 @@ void LLOfferInfo::send_auto_receive_response(void)
 	if(IM_INVENTORY_OFFERED == mIM)
 	{
 		// add buddy to recent people list
-		LLRecentPeople::instance().add(mFromID);
+//		LLRecentPeople::instance().add(mFromID);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+		// RELEASE-RLVa: [RLVa-2.0.1] Make sure this stays in sync with the condition in inventory_offer_handler()
+		bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) ||
+			(RlvActions::canShowName(RlvActions::SNC_DEFAULT, mFromID)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID)) || (RlvUIEnabler::hasOpenProfile(mFromID));
+		if (fRlvCanShowName)
+			LLRecentPeople::instance().add(mFromID);
+// [/RLVa:KB]
 	}
 }
 
@@ -1563,6 +1587,18 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 				// This is an offer from an agent. In this case, the back
 				// end has already copied the items into your inventory,
 				// so we can fetch it out of our inventory.
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0)
+				if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) )
+				{
+					RlvGiveToRLVAgentOffer* pOfferObserver = new RlvGiveToRLVAgentOffer(mObjectID);
+					pOfferObserver->startFetch();
+					if (pOfferObserver->isFinished())
+						pOfferObserver->done();
+					else
+						gInventory.addObserver(pOfferObserver);
+				}
+// [/RLVa:KB]
+
 				if (gSavedSettings.getBOOL("ShowOfferedInventory"))
 				{
 					LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
@@ -1744,6 +1780,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 		}
 		else
 		{
+/*
 			std::string full_name;
 			if (gCacheName->getFullName(mFromID, full_name))
 			{
@@ -1757,6 +1794,22 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 				+ mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser");
 				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser");
 			}
+*/
+// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+			std::string name_slurl = LLSLURL("agent", mFromID, "about").getSLURLString();
+
+// [RLVa:KB] - Checked: RLVa-2.0.1
+			// RELEASE-RLVa: [RLVa-2.0.1] Make sure this stays in sync with the condition in inventory_offer_handler()
+			bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) ||
+				(RlvActions::canShowName(RlvActions::SNC_DEFAULT, mFromID)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID)) || (RlvUIEnabler::hasOpenProfile(mFromID));
+			if (!fRlvCanShowName)
+				name_slurl = LLSLURL("agent", mFromID, "rlvanonym").getSLURLString();
+// [/RLVa:KB]
+
+			from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName 
+				+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + name_slurl;
+			chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + name_slurl;
+// [/SL:KB]
 		}
 	}
 	else
@@ -1766,12 +1819,38 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 	
 	bool is_do_not_disturb = gAgent.isDoNotDisturb();
 	
+// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1)
+	bool fRlvNotifyAccepted = false;
+// [/RLVa:KB]
 	switch(button)
 	{
 		case IOR_ACCEPT:
 			// ACCEPT. The math for the dialog works, because the accept
 			// for inventory_offered, task_inventory_offer or
 			// group_notice_inventory is 1 greater than the offer integer value.
+
+// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1)
+			// Only treat the offer as 'Give to #RLV' if:
+			//   - the user has enabled the feature
+			//   - the inventory offer came from a script (and specifies a folder)
+			//   - the name starts with the prefix - mDesc format: '[OBJECTNAME]'  ( http://slurl.com/... )
+			if ( (rlv_handler_t::isEnabled()) && (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) )
+			{
+				fRlvNotifyAccepted = true;
+				if (!RlvSettings::getForbidGiveToRLV())
+				{
+					const LLUUID& idRlvRoot = RlvInventory::instance().getSharedRootID();
+					if (idRlvRoot.notNull())
+						mFolderID = idRlvRoot;
+
+					fRlvNotifyAccepted = false;		// "accepted_in_rlv" is sent from RlvGiveToRLVTaskOffer *after* we have the folder
+
+					RlvGiveToRLVTaskOffer* pOfferObserver = new RlvGiveToRLVTaskOffer(mTransactionID);
+					gInventory.addObserver(pOfferObserver);
+				}
+			}
+// [/RLVa:KB]
+
 			// Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
 			// or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
 			msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
@@ -1780,6 +1859,15 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 			// send the message
 			msg->sendReliable(mHost);
 			
+// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1)
+			if (fRlvNotifyAccepted)
+			{
+				std::string::size_type idxToken = mDesc.find("'  ( http://");
+				if (std::string::npos != idxToken)
+					RlvBehaviourNotifyHandler::sendNotification("accepted_in_inv inv_offer " + mDesc.substr(1, idxToken - 1));
+			}
+// [/RLVa:KB]
+
 			//don't spam them if they are getting flooded
 			if (check_offer_throttle(mFromName, true))
 			{
@@ -1824,6 +1912,16 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 			msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
 			// send the message
 			msg->sendReliable(mHost);
+			
+// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e
+			if ( (rlv_handler_t::isEnabled()) && 
+				 (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) )
+			{
+				std::string::size_type idxToken = mDesc.find("'  ( http://");
+				if (std::string::npos != idxToken)
+					RlvBehaviourNotifyHandler::sendNotification("declined inv_offer " + mDesc.substr(1, idxToken - 1));
+			}
+// [/RLVa:KB]
 
 			if (gSavedSettings.getBOOL("LogInventoryDecline"))
 			{
@@ -1832,6 +1930,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 				log_message_args["NAME"] = mFromName;
 				log_message = LLTrans::getString("InvOfferDecline", log_message_args);
 
+
 				LLSD args;
 				args["MESSAGE"] = log_message;
 				LLNotificationsUtil::add("SystemMessageTip", args);
@@ -1959,6 +2058,9 @@ void inventory_offer_handler(LLOfferInfo* info)
 	}
 	else
 	{
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
+		args["NAME_LABEL"] = LLSLURL("agent", info->mFromID, "completename").getSLURLString();
+// [/SL:KB]
 		args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString();
 	}
 	std::string verb = "select?name=" + LLURI::escape(msg);
@@ -1969,6 +2071,15 @@ void inventory_offer_handler(LLOfferInfo* info)
 	// Object -> Agent Inventory Offer
 	if (info->mFromObject && !bAutoAccept)
 	{
+// [RLVa:KB] - Checked: RLVa-1.2.2
+		// Only filter if the object owner is a nearby agent
+		if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, info->mFromID)) && (RlvUtil::isNearbyAgent(info->mFromID)) )
+		{
+			payload["rlv_shownames"] = TRUE;
+			args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "rlvanonym").getSLURLString();
+		}
+// [/RLVa:KB]
+
 		// Inventory Slurls don't currently work for non agent transfers, so only display the object name.
 		args["ITEM_SLURL"] = msg;
 		// Note: sets inventory_task_offer_callback as the callback
@@ -1983,6 +2094,18 @@ void inventory_offer_handler(LLOfferInfo* info)
 	}
 	else // Agent -> Agent Inventory Offer
 	{
+// [RLVa:KB] - Checked: RLVa-2.0.1
+		// Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused)
+		bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) ||
+			(RlvActions::canShowName(RlvActions::SNC_DEFAULT, info->mFromID)) || (!RlvUtil::isNearbyAgent(info->mFromID)) || (RlvUIEnabler::hasOpenIM(info->mFromID)) || (RlvUIEnabler::hasOpenProfile(info->mFromID));
+		if (!fRlvCanShowName)
+		{
+			payload["rlv_shownames"] = TRUE;
+			args["NAME"] = RlvStrings::getAnonym(info->mFromName);
+			args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "rlvanonym").getSLURLString();
+		}
+// [/RLVa:KB]
+
 		p.responder = info;
 		// Note: sets inventory_offer_callback as the callback
 		// *TODO fix memory leak
@@ -2067,7 +2190,18 @@ bool lure_callback(const LLSD& notification, const LLSD& response)
 		modified_form->setElementEnabled("Teleport", false);
 		modified_form->setElementEnabled("Cancel", false);
 		notification_ptr->updateForm(modified_form);
-		notification_ptr->repost();
+
+// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5)
+		// Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell
+		/*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel();
+		/*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL;
+		if ( (!pToast) || (!pToast->getCanBeStored()) )
+		{
+// [/SL:KB]
+			notification_ptr->repost();
+// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5)
+		}
+// [/SL:KB]
 	}
 
 	return false;
@@ -2439,10 +2573,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 			// do nothing -- don't distract newbies in
 			// Prelude with global IMs
 		}
+// [RLVa:KB] - Checked: RLVa-2.0.3
+		else if ( (RlvActions::isRlvEnabled()) && (RlvSettings::getEnableIMQuery()) && (offline == IM_ONLINE) && ("@version" == message) && (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) )
+		{
+			RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(LLUUID::null), session_id);
+		}
+// [/RLVa:KB]
+//		else if (offline == IM_ONLINE 
+//					&& is_do_not_disturb
+//					&& from_id.notNull() //not a system message
+//					&& to_id.notNull()) //not global message
+// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0)
 		else if (offline == IM_ONLINE 
 					&& is_do_not_disturb
 					&& from_id.notNull() //not a system message
-					&& to_id.notNull()) //not global message
+					&& to_id.notNull() //not global message
+					&& RlvActions::canReceiveIM(from_id))
+// [/RLVa:KB]
 		{
 
 			// now store incoming IM in chat history
@@ -2512,6 +2659,17 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 				mute_im = true;
 			}
+
+// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0)
+			// Don't block offline IMs, or IMs from Lindens
+			if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!LLMuteList::getInstance()->isLinden(original_name) ))
+			{
+				if (!mute_im)
+					RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id);
+				buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM);
+			}
+// [/RLVa:KB]
+
 			if (!mute_im) 
 			{
 				gIMMgr->addMessage(
@@ -2812,7 +2970,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 	case IM_INVENTORY_ACCEPTED:
 	{
-		args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
+//		args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
+// [RLVa:KB] - Checked: RLVa-1.2.2
+		// Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open
+		bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) ||
+			(RlvActions::canShowName(RlvActions::SNC_DEFAULT, from_id)) || (!RlvUtil::isNearbyAgent(from_id)) || (RlvUIEnabler::hasOpenProfile(from_id)) || (RlvUIEnabler::hasOpenIM(from_id));
+		args["NAME"] = LLSLURL("agent", from_id, (fRlvCanShowName) ? "completename" : "rlvanonym").getSLURLString();;
+// [/RLVa:KB]
 		LLSD payload;
 		payload["from_id"] = from_id;
 		// Passing the "SESSION_NAME" to use it for IM notification logging
@@ -2823,7 +2987,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 	}
 	case IM_INVENTORY_DECLINED:
 	{
-		args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
+//		args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
+// [RLVa:KB] - Checked: RLVa-1.2.2
+		// Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open
+		bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) ||
+			(RlvActions::canShowName(RlvActions::SNC_DEFAULT, from_id)) || (!RlvUtil::isNearbyAgent(from_id)) || (RlvUIEnabler::hasOpenProfile(from_id)) || (RlvUIEnabler::hasOpenIM(from_id));
+		args["NAME"] = LLSLURL("agent", from_id, (fRlvCanShowName) ? "completename" : "rlvanonym").getSLURLString();;
+// [/RLVa:KB]
 		LLSD payload;
 		payload["from_id"] = from_id;
 		LLNotificationsUtil::add("InventoryDeclined", args, payload);
@@ -2885,6 +3055,25 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 			LLSD query_string;
 			query_string["owner"] = from_id;
+// [RLVa:KB] - Checked: RLVa-1.2.0
+			if (RlvActions::isRlvEnabled())
+			{
+				// NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat()
+				if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) )
+				{
+					query_string["rlv_shownames"] = TRUE;
+
+					RlvUtil::filterNames(name);
+					chat.mFromName = name;
+				}
+				if (!RlvActions::canShowLocation())
+				{
+					std::string::size_type idxPos = location.find('/');
+					if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) )
+						location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+				}
+			}
+// [/RLVa:KB]
 			query_string["slurl"] = location;
 			query_string["name"] = name;
 			if (from_group)
@@ -2892,7 +3081,10 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				query_string["groupowned"] = "true";
 			}	
 
-			chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString();
+//			chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString();
+// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+			chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString();
+// [/SL:KB]
 			chat.mText = message;
 
 			// Note: lie to Nearby Chat, pretending that this is NOT an IM, because
@@ -3034,11 +3226,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 	case IM_LURE_USER:
 	case IM_TELEPORT_REQUEST:
 		{
+// [RLVa:KB] - Checked: RLVa-1.4.9
+			// If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later)
+			bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) &&
+				( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) ||
+				  ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) );
+// [/RLVa:KB]
+
 			if (is_muted)
 			{ 
 				return;
 			}
-			else if (is_do_not_disturb) 
+//			else if (is_do_not_disturb) 
+// [RLVa:KB] - Checked: RLVa-1.4.9
+			else if ( (is_do_not_disturb) && (!fRlvAutoAccept) )
+// [/RLVa:KB]
 			{
 				send_do_not_disturb_message(msg, from_id);
 			}
@@ -3101,8 +3303,32 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 					}
 				}
 
+// [RLVa:KB] - Checked: RLVa-1.4.9
+				if (rlv_handler_t::isEnabled())
+				{
+					if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) ||
+					     ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) )
+					{
+						RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE));
+						if (is_do_not_disturb)
+							send_do_not_disturb_message(msg, from_id);
+						return;
+					}
+
+					// Censor message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer/request and @showloc=n restricted
+					if ( (!RlvActions::canReceiveIM(from_id)) || 
+						 ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (IM_LURE_USER == dialog || IM_TELEPORT_REQUEST == dialog)) )
+					{
+						message = RlvStrings::getString(RLV_STRING_HIDDEN);
+					}
+				}
+// [/RLVa:KB]
+
 				LLSD args;
 				// *TODO: Translate -> [FIRST] [LAST] (maybe)
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
+				args["NAME_LABEL"] = LLSLURL("agent", from_id, "completename").getSLURLString();
+// [/SL:KB]
 				args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
 				args["MESSAGE"] = message;
 				args["MATURITY_STR"] = region_access_str;
@@ -3144,10 +3370,25 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 						params.functor.name = "TeleportRequest";
 					}
 
-			    params.substitutions = args;
-			    params.payload = payload;
-			    LLPostponedNotification::add<LLPostponedOfferNotification>(	params, from_id, false);
-			}
+					params.substitutions = args;
+					params.payload = payload;
+
+// [RLVa:KB] - Checked: RLVa-1.4.9
+					if (fRlvAutoAccept)
+					{
+						if (IM_LURE_USER == dialog)
+							gRlvHandler.setCanCancelTp(false);
+						if (is_do_not_disturb)
+							send_do_not_disturb_message(msg, from_id);
+						LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0);
+					}
+					else
+					{
+						LLPostponedNotification::add<LLPostponedOfferNotification>(params, from_id, false);
+					}
+// [/RLVa:KB]
+//					LLPostponedNotification::add<LLPostponedOfferNotification>(	params, from_id, false);
+				}
 			}
 		}
 		break;
@@ -3299,6 +3540,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				{
 					send_do_not_disturb_message(msg, from_id);
 				}
+// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
+				args["NAME_LABEL"] = LLSLURL("agent", from_id, "completename").getSLURLString();
+// [/SL:KB]
 				args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
 
 				if (add_notification)
@@ -3581,9 +3825,14 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 		chat.mPosAgent = chatter->getPositionAgent();
 
 		// Make swirly things only for talking objects. (not script debug messages, though)
-		if (chat.mSourceType == CHAT_SOURCE_OBJECT 
-			&& chat.mChatType != CHAT_TYPE_DEBUG_MSG
-			&& gSavedSettings.getBOOL("EffectScriptChatParticles") )
+//		if (chat.mSourceType == CHAT_SOURCE_OBJECT 
+//			&& chat.mChatType != CHAT_TYPE_DEBUG_MSG
+//			&& gSavedSettings.getBOOL("EffectScriptChatParticles") )
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g
+		if ( ((chat.mSourceType == CHAT_SOURCE_OBJECT) && (chat.mChatType != CHAT_TYPE_DEBUG_MSG)) && 
+			 (gSavedSettings.getBOOL("EffectScriptChatParticles")) &&
+			 ((!rlv_handler_t::isEnabled()) || (CHAT_TYPE_OWNER != chat.mChatType)) )
+// [/RLVa:KB]
 		{
 			LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
 			psc->setSourceObject(chatter);
@@ -3613,6 +3862,75 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 		color.setVec(1.f,1.f,1.f,1.f);
 		msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg);
 
+// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		if ( (rlv_handler_t::isEnabled()) && (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) )
+		{
+			// NOTE: chatter can be NULL (may not have rezzed yet, or could be another avie's HUD attachment)
+			BOOL is_attachment = (chatter) ? chatter->isAttachment() : FALSE;
+			BOOL is_owned_by_me = (chatter) ? chatter->permYouOwner() : FALSE;
+
+			// Filtering "rules":
+			//   avatar  => filter all avie text (unless it's this avie or they're an exemption)
+			//   objects => filter everything except attachments this avie owns (never filter llOwnerSay or llRegionSayTo chat)
+			if ( ( (CHAT_SOURCE_AGENT == chat.mSourceType) && (from_id != gAgent.getID()) ) || 
+				 ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && ((!is_owned_by_me) || (!is_attachment)) && 
+				   (CHAT_TYPE_OWNER != chat.mChatType) && (CHAT_TYPE_DIRECT != chat.mChatType) ) )
+			{
+				bool fIsEmote = RlvUtil::isEmote(mesg);
+				if ((!fIsEmote) &&
+					(((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHAT)) && (!gRlvHandler.isException(RLV_BHVR_RECVCHAT, from_id))) ||
+					 ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHATFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVCHATFROM, from_id))) ))
+				{
+					if ( (gRlvHandler.filterChat(mesg, false)) && (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) )
+						return;
+				}
+				else if ((fIsEmote) &&
+					     (((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTE)) && (!gRlvHandler.isException(RLV_BHVR_RECVEMOTE, from_id))) ||
+					      ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTEFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVEMOTEFROM, from_id))) ))
+ 				{
+					if (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis"))
+						return;
+					mesg = "/me ...";
+				}
+			}
+
+			// Filtering "rules":
+			//   avatar => filter only their name (unless it's this avie)
+			//   other  => filter everything
+			if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT))
+			{
+				if (CHAT_SOURCE_AGENT != chat.mSourceType)
+				{
+					RlvUtil::filterNames(chat.mFromName);
+				}
+				else if (chat.mFromID != gAgent.getID())
+				{
+					chat.mFromName = RlvStrings::getAnonym(chat.mFromName);
+					chat.mRlvNamesFiltered = TRUE;
+				}
+			}
+
+			// Create an "objectim" URL for objects if we're either @shownames or @showloc restricted
+			// (we need to do this now because we won't be have enough information to do it later on)
+			if ( (CHAT_SOURCE_OBJECT == chat.mSourceType) &&
+			     ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) || (!RlvActions::canShowLocation()) ) )
+			{
+				LLSD sdQuery;
+				sdQuery["name"] = chat.mFromName;
+				sdQuery["owner"] = owner_id;
+
+				if ( (!RlvActions::canShowName(RlvActions::SNC_COUNT, owner_id)) && (!is_owned_by_me) )
+					sdQuery["rlv_shownames"] = true;
+
+				const LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+				if (pRegion)
+					sdQuery["slurl"] = LLSLURL(pRegion->getName(), chat.mPosAgent).getLocationString();
+
+				chat.mURL = LLSLURL("objectim", from_id, LLURI::mapToQueryString(sdQuery)).getSLURLString();
+			}
+		}
+// [/RLVa:KB]
+
 		BOOL ircstyle = FALSE;
 
 		// Look for IRC-style emotes here so chatbubbles work
@@ -3663,8 +3981,100 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 			case CHAT_TYPE_WHISPER:
 				chat.mText = LLTrans::getString("whisper") + " ";
 				break;
-			case CHAT_TYPE_DEBUG_MSG:
 			case CHAT_TYPE_OWNER:
+// [RLVa:KB] - Checked: 2010-02-XX (RLVa-1.2.0a) | Modified: RLVa-1.1.0f
+				// TODO-RLVa: [RLVa-1.2.0] consider rewriting this before a RLVa-1.2.0 release
+				if ( (rlv_handler_t::isEnabled()) && (mesg.length() > 3) && (RLV_CMD_PREFIX == mesg[0]) && (CHAT_TYPE_OWNER == chat.mChatType) &&
+					 ((!chatter) || (!chatter->isAttachment()) || (!chatter->isTempAttachment()) || (RlvSettings::getEnableTemporaryAttachments())) )
+				{
+					mesg.erase(0, 1);
+					LLStringUtil::toLower(mesg);
+
+					std::string strExecuted, strFailed, strRetained, *pstr;
+
+					boost_tokenizer tokens(mesg, boost::char_separator<char>(",", "", boost::drop_empty_tokens));
+					for (boost_tokenizer::iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken)
+					{
+						std::string strCmd = *itToken;
+
+						ERlvCmdRet eRet = gRlvHandler.processCommand(from_id, strCmd, true);
+						if ( (RlvSettings::getDebug()) &&
+							 ( (!RlvSettings::getDebugHideUnsetDup()) || 
+							   ((RLV_RET_SUCCESS_UNSET != eRet) && (RLV_RET_SUCCESS_DUPLICATE != eRet)) ) )
+						{
+							if ( RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS) )	
+								pstr = &strExecuted;
+							else if ( RLV_RET_FAILED == (eRet & RLV_RET_FAILED) )
+								pstr = &strFailed;
+							else if (RLV_RET_RETAINED == eRet)
+								pstr = &strRetained;
+							else
+							{
+								RLV_ASSERT(false);
+								pstr = &strFailed;
+							}
+
+							const char* pstrSuffix = RlvStrings::getStringFromReturnCode(eRet);
+							if (pstrSuffix)
+								strCmd.append(" (").append(pstrSuffix).append(")");
+
+							if (!pstr->empty())
+								pstr->push_back(',');
+							pstr->append(strCmd);
+						}
+					}
+
+					if (RlvForceWear::instanceExists())
+						RlvForceWear::instance().done();
+
+					if ( (!RlvSettings::getDebug()) || ((strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty())) )
+						return;
+
+					// Silly people want comprehensive debug messages, blah :p
+					if ( (!strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty()) )
+					{
+						chat.mText = " executes: @";
+						mesg = strExecuted;
+					}
+					else if ( (strExecuted.empty()) && (!strFailed.empty()) && (strRetained.empty()) )
+					{
+						chat.mText = " failed: @";
+						mesg = strFailed;
+					}
+					else if ( (strExecuted.empty()) && (strFailed.empty()) && (!strRetained.empty()) )
+					{
+						chat.mText = " retained: @";
+						mesg = strRetained;
+					}
+					else
+					{
+						chat.mText = ": @";
+						if (!strExecuted.empty())
+							mesg += "\n    - executed: @" + strExecuted;
+						if (!strFailed.empty())
+							mesg += "\n    - failed: @" + strFailed;
+						if (!strRetained.empty())
+							mesg += "\n    - retained: @" + strRetained;
+					}
+
+					break;
+				}
+// [/RLVa:KB]
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g
+				// Copy/paste from above
+				if  ( (rlv_handler_t::isEnabled()) && (chatter) && (chat.mSourceType == CHAT_SOURCE_OBJECT) &&
+					  (gSavedSettings.getBOOL("EffectScriptChatParticles")) )
+				{
+					LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
+					psc->setSourceObject(chatter);
+					psc->setColor(color);
+					//We set the particles to be owned by the object's owner, 
+					//just in case they should be muted by the mute list
+					psc->setOwnerUUID(owner_id);
+					LLViewerPartSim::getInstance()->addPartSource(psc);
+				}
+// [/RLVa:KB]
+			case CHAT_TYPE_DEBUG_MSG:
 			case CHAT_TYPE_NORMAL:
 			case CHAT_TYPE_DIRECT:
 				break;
@@ -3783,7 +4193,10 @@ void process_teleport_start(LLMessageSystem *msg, void**)
 	// *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM
 	LLViewerMessage::getInstance()->mTeleportStartedSignal();
 
-	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+//	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
+	if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) )
+// [/RLVa:KB]
 	{
 		gViewerWindow->setProgressCancelButtonVisible(FALSE);
 	}
@@ -3825,7 +4238,10 @@ void process_teleport_progress(LLMessageSystem* msg, void**)
 	}
 	U32 teleport_flags = 0x0;
 	msg->getU32("Info", "TeleportFlags", teleport_flags);
-	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+//	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
+	if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) )
+// [/RLVa:KB]
 	{
 		gViewerWindow->setProgressCancelButtonVisible(FALSE);
 	}
@@ -4246,7 +4662,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)
 	}
 	
 	// send walk-vs-run status
-	gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun());
+//	gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun());
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+	gAgent.sendWalkRun();
+// [/RLVa:KB]
 
 	// If the server version has changed, display an info box and offer
 	// to display the release notes, unless this is the initial log in.
@@ -4660,6 +5079,14 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 			LLViewerObject *objectp = gObjectList.findObject(id);
 			if (objectp)
 			{
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+				if ( (objectp->isAttachment()) && (gAgentAvatarp) && (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) && (objectp->permYouOwner()) )
+				{
+					gAgentAvatarp->addPendingDetach(objectp->getRootEdit()->getID());
+					continue;
+				}
+// [/SL:KB]
+
 				// Display green bubble on kill
 				if ( gShowObjectUpdates )
 				{
@@ -6135,6 +6562,15 @@ void process_alert_core(const std::string& message, BOOL modal)
 		}
 
 			std::string new_msg =LLNotifications::instance().getGlobalString(text);
+// [RLVa:KB] - Checked: RLVa-1.4.5
+			if ( (new_msg == text) && (RlvActions::isRlvEnabled()) )
+			{
+				if (!RlvActions::canShowLocation())
+					RlvUtil::filterLocation(new_msg);
+				if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT))
+					RlvUtil::filterNames(new_msg);
+			}
+// [/RLVa:KB]
 			args["MESSAGE"] = new_msg;
 			LLNotificationsUtil::add("SystemMessage", args);
 		}
@@ -6142,6 +6578,15 @@ void process_alert_core(const std::string& message, BOOL modal)
 	{
 		LLSD args;
 		std::string new_msg =LLNotifications::instance().getGlobalString(message);
+// [RLVa:KB] - Checked: RLVa-1.4.5
+		if ( (new_msg == message) && (RlvActions::isRlvEnabled()) )
+		{
+			if (!RlvActions::canShowLocation())
+				RlvUtil::filterLocation(new_msg);
+			if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT))
+				RlvUtil::filterNames(new_msg);
+		}
+// [/RLVa:KB]
 		args["ERROR_MESSAGE"] = new_msg;
 		LLNotificationsUtil::add("ErrorMessage", args);
 	}
@@ -6157,6 +6602,16 @@ void process_alert_core(const std::string& message, BOOL modal)
 			std::string localized_msg;
 			bool is_message_localized = LLTrans::findString(localized_msg, new_msg);
 
+// [RLVa:KB] - Checked: RLVa-1.4.5
+			if ( (new_msg == message) && (RlvActions::isRlvEnabled()) )
+			{
+				if (!RlvActions::canShowLocation())
+					RlvUtil::filterLocation(new_msg);
+				if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT))
+					RlvUtil::filterNames(new_msg);
+			}
+// [/RLVa:KB]
+
 			args["MESSAGE"] = is_message_localized ? localized_msg : new_msg;
 			LLNotificationsUtil::add("SystemMessageTip", args);
 		}
@@ -6317,7 +6772,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
 			if (viewregion)
 			{
 				// got the region, so include the region and 3d coordinates of the object
-				notice.setArg("[REGIONNAME]", viewregion->getName());				
+				notice.setArg("[REGIONNAME]", viewregion->getName());
 				std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]);
 				notice.setArg("[REGIONPOS]", formatpos);
 
@@ -6325,7 +6780,15 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
 			}
 		}
 
-		if (!foundpos)
+// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.0.0a
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+			notice.setArg("[REGIONNAME]", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+			notice.setArg("[REGIONPOS]", RlvStrings::getString(RLV_STRING_HIDDEN));
+		}
+		else if (!foundpos)
+// [/RLVa:KB]
+//		if (!foundpos)
 		{
 			// unable to determine location of the object
 			notice.setArg("[REGIONNAME]", "(unknown region)");
@@ -6339,8 +6802,12 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
 		std::string perms;
 		BOOST_FOREACH(script_perm_t script_perm, SCRIPT_PERMISSIONS)
 		{
-			if ((orig_questions & script_perm.permbit)
-				&& script_perm.caution)
+//			if ((orig_questions & script_perm.permbit)
+//				&& script_perm.caution)
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+			if ( (orig_questions & script_perm.permbit) &&
+ 				 ((script_perm.caution) || (notification["payload"]["rlv_notify"].asBoolean())) )
+// [/RLVa:KB]
 			{
 				count++;
 				caution = TRUE;
@@ -6360,11 +6827,25 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
 
 		// log a chat message as long as at least one requested permission
 		// is a caution permission
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
 		if (caution)
 		{
-			LLChat chat(notice.getString());
-	//		LLFloaterChat::addChat(chat, FALSE, FALSE);
+			LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
+			if(nearby_chat)
+			{
+				LLChat chat_msg(notice.getString());
+				chat_msg.mFromName = SYSTEM_FROM;
+				chat_msg.mFromID = LLUUID::null;
+				chat_msg.mSourceType = CHAT_SOURCE_SYSTEM;
+				nearby_chat->addMessage(chat_msg);
+			}
 		}
+// [/RLVa:KB]
+//		if (caution)
+//		{
+//			LLChat chat(notice.getString());
+//	//		LLFloaterChat::addChat(chat, FALSE, FALSE);
+//		}
 	}
 }
 
@@ -6439,12 +6920,22 @@ bool script_question_cb(const LLSD& notification, const LLSD& response)
 	msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
 
 	// only log a chat message if caution prompts are enabled
-	if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+//	if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+	if ( (gSavedSettings.getBOOL("PermissionsCautionEnabled")) || (notification["payload"]["rlv_notify"].asBoolean()) )
+// [/RLVa:KB]
 	{
 		// log a chat message, if appropriate
 		notify_cautioned_script_question(notification, response, orig, allowed);
 	}
 
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+	if ( (allowed) && (notification["payload"].has("rlv_blocked")) )
+	{
+		RlvUtil::notifyBlocked(notification["payload"]["rlv_blocked"], LLSD().with("OBJECT", notification["payload"]["object_name"]));
+	}
+// [/RLVa:KB]
+
 	if ( response["Mute"] ) // mute
 	{
 		script_question_mute(task_id,notification["payload"]["object_name"].asString());
@@ -6628,6 +7119,38 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
 			payload["object_name"] = object_name;
 			payload["owner_name"] = owner_name;
 
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+			if (rlv_handler_t::isEnabled())
+			{
+				RlvUtil::filterScriptQuestions(questions, payload);
+
+				if ( (questions) && (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) )
+				{
+					const LLViewerObject* pObj = gObjectList.findObject(taskid);
+					if (pObj)
+					{
+						if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) )
+						{
+ 							questions &= ~(SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TAKE_CONTROLS].permbit | 
+ 								SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit);
+						}
+						else
+						{
+							questions &= ~(SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TAKE_CONTROLS].permbit);
+						}
+						payload["rlv_notify"] = !pObj->permYouOwner();
+					}
+				}
+			}
+
+			if ( (!caution) && (!questions) )
+			{
+				LLNotifications::instance().forceResponse(
+					LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/);
+				return;
+			}
+// [/RLVa:KB]
+
 			// check whether cautions are even enabled or not
 			const char* notification = "ScriptQuestion";
 
@@ -6992,6 +7515,16 @@ void send_lures(const LLSD& notification, const LLSD& response)
 	LLAgentUI::buildSLURL(slurl);
 	text.append("\r\n").append(slurl.getSLURLString());
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	// Filter the lure message if any of the recipients are IM-blocked
+	const LLSD& sdRecipients = notification["payload"]["ids"];
+	if ( (gRlvHandler.isEnabled()) && 
+	     (std::any_of(sdRecipients.beginArray(), sdRecipients.endArray(), [](const LLSD& id) { return !RlvActions::canStartIM(id.asUUID()) || !RlvActions::canSendIM(id.asUUID()); })) )
+	{
+		text = RlvStrings::getString(RLV_STRING_HIDDEN);
+	}
+// [/RLVa:KB]
+
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_StartLure);
 	msg->nextBlockFast(_PREHASH_AgentData);
@@ -7011,10 +7544,16 @@ void send_lures(const LLSD& notification, const LLSD& response)
 
 		// Record the offer.
 		{
+// [RLVa:KB] - Checked: RLVa-2.0.1
+			bool fRlvCanShowName = (!notification["payload"].has("rlv_shownames")) ? true : !notification["payload"]["rlv_shownames"].asBoolean();
+// [/RLVa:KB]
 			std::string target_name;
 			gCacheName->getFullName(target_id, target_name);  // for im log filenames
 			LLSD args;
-			args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
+// [RLVa:KB] - Checked: RLVa-2.0.1
+			args["TO_NAME"] = LLSLURL("agent", target_id, (fRlvCanShowName) ? "displayname" : "rlvanonym").getSLURLString();;
+// [/RLVa:KB]
+//			args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
 	
 			LLSD payload;
 				
@@ -7024,7 +7563,11 @@ void send_lures(const LLSD& notification, const LLSD& response)
 			LLNotificationsUtil::add("TeleportOfferSent", args, payload);
 
 			// Add the recepient to the recent people list.
-			LLRecentPeople::instance().add(target_id);
+// [RLVa:KB] - Checked: RLVa-2.0.1
+			if (fRlvCanShowName)
+				LLRecentPeople::instance().add(target_id);
+// [/RLVa:KB]
+//			LLRecentPeople::instance().add(target_id);
 		}
 	}
 	gAgent.sendReliableMessage();
@@ -7069,15 +7612,38 @@ void handle_lure(const uuid_vec_t& ids)
 	if (!gAgent.getRegion()) return;
 
 	LLSD edit_args;
-	edit_args["REGION"] = gAgent.getRegion()->getName();
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a
+	edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN);
+// [/RLVa:KB]
+//	edit_args["REGION"] = gAgent.getRegion()->getName();
 
 	LLSD payload;
-	for (std::vector<LLUUID>::const_iterator it = ids.begin();
-		it != ids.end();
-		++it)
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	bool fRlvShouldHideNames = false;
+	for (const LLUUID& idAgent : ids)
 	{
-		payload["ids"].append(*it);
+		// Only allow offering teleports if everyone is a @tplure exception or able to map this avie under @showloc=n
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+			const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idAgent);
+			if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, RLV_CHECK_PERMISSIVE)) &&
+				 ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) )
+			{
+				RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT_OFFER);
+				return;
+			}
+		}
+		fRlvShouldHideNames |= !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER, idAgent);
+		payload["ids"].append(idAgent);
 	}
+	payload["rlv_shownames"] = fRlvShouldHideNames;
+// [/RLVa:KB]
+// 	for (std::vector<LLUUID>::const_iterator it = ids.begin();
+// 		it != ids.end();
+// 		++it)
+// 	{
+// 		payload["ids"].append(*it);
+// 	}
 	if (gAgent.isGodlike())
 	{
 		LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback);
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 5edc3c9745378c85e01928eb43d3ca760f434539..09ebecec2c04194e875a992d13c789720da19656 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -102,6 +102,11 @@
 #include "llmediaentry.h"
 #include "llfloaterperms.h"
 #include "llvocache.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -692,6 +697,12 @@ bool LLViewerObject::isReturnable()
 		return false;
 	}
 		
+// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+	if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn(this)) )
+	{
+		return false;
+	}
+// [/RLVa:KB]
 	std::vector<LLBBox> boxes;
 	boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned());
 	for (child_list_t::iterator iter = mChildList.begin();
@@ -909,7 +920,10 @@ void LLViewerObject::addThisAndNonJointChildren(std::vector<LLViewerObject*>& ob
 	}
 }
 
-BOOL LLViewerObject::isChild(LLViewerObject *childp) const
+//BOOL LLViewerObject::isChild(LLViewerObject *childp) const
+// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+BOOL LLViewerObject::isChild(const LLViewerObject *childp) const
+// [/RLVa:KB]
 {
 	for (child_list_t::const_iterator iter = mChildList.begin();
 		 iter != mChildList.end(); iter++)
@@ -1428,6 +1442,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					coloru.mV[3] = 255 - coloru.mV[3];
 					mText->setColor(LLColor4(coloru));
 					mText->setString(temp_string);
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f
+					if (rlv_handler_t::isEnabled())
+					{
+						mText->setObjectText(temp_string);
+					}
+// [/RLVa:KB]
 
 					mHudText = temp_string;
 					mHudTextColor = LLColor4(coloru);
@@ -1806,6 +1826,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					coloru.mV[3] = 255 - coloru.mV[3];
 					mText->setColor(LLColor4(coloru));
 					mText->setString(temp_string);
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f
+					if (rlv_handler_t::isEnabled())
+					{
+						mText->setObjectText(temp_string);
+					}
+// [/RLVa:KB]
 
                     mHudText = temp_string;
                     mHudTextColor = LLColor4(coloru);
@@ -1994,6 +2020,25 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 								gObjectList.killObject(this);
 								return retval;
 							}
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.1.0k) | Added: RLVa-1.1.0k
+							if ( (rlv_handler_t::isEnabled()) && (sent_parentp->isAvatar()) && (sent_parentp->getID() == gAgent.getID()) )
+							{
+								// Rezzed object that's being worn as an attachment (we're assuming this will be due to llAttachToAvatar())
+								S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getState());
+								if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD))
+								{
+									// If this will end up on an "add locked" attachment point then treat the attach as a user action
+									LLNameValue* nvItem = getNVPair("AttachItemID");
+									if (nvItem)
+									{
+										LLUUID idItem(nvItem->getString());
+										// URGENT-RLVa: [RLVa-1.2.0] At the moment llAttachToAvatar always seems to *add*
+										if (idItem.notNull())
+											RlvAttachmentLockWatchdog::instance().onWearAttachment(idItem, RLV_WEAR_ADD);
+									}
+								}
+							}
+// [/RLVa:KB]
 							sent_parentp->addChild(this);
 							// make sure this object gets a non-damped update
 							if (sent_parentp->mDrawable.notNull())
@@ -5786,7 +5831,10 @@ BOOL LLViewerObject::permTransfer() const
 // given you modify rights to.  JC
 BOOL LLViewerObject::allowOpen() const
 {
-	return !flagInventoryEmpty() && (permYouOwner() || permModify());
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
+	return !flagInventoryEmpty() && (permYouOwner() || permModify()) && ((!RlvActions::isRlvEnabled()) || (RlvActions::canEdit(this)));
+// [/RLVa:KB]
+//	return !flagInventoryEmpty() && (permYouOwner() || permModify());
 }
 
 LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo()
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index cb8acfdcf82dd9ca0fadd4889a88c329c4aec8db..c0b0209728717ecf845c5b777d5499f30e3039ef 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -259,7 +259,10 @@ class LLViewerObject
 	S32 numChildren() const { return mChildList.size(); }
 	void addThisAndAllChildren(std::vector<LLViewerObject*>& objects);
 	void addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects);
-	BOOL isChild(LLViewerObject *childp) const;
+//	BOOL isChild(LLViewerObject *childp) const;
+// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
+	BOOL isChild(const LLViewerObject *childp) const;
+// [/RLVa:KB]
 	BOOL isSeat() const;
 	
 
@@ -372,7 +375,10 @@ class LLViewerObject
 
 	void sendShapeUpdate();
 
-	U8 getState()							{ return mState; }
+//	U8 getState()							{ return mState; }
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	U8 getState() const						{ return mState; }
+// [/RLVa:KB]
 
 	F32 getAppAngle() const					{ return mAppAngle; }
 	F32 getPixelArea() const				{ return mPixelArea; }
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 8f98d66c0c334e9acd37ed12897fcf7580426ca1..1227303497c11148585da989e4beb656c72a1e4f 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -723,6 +723,29 @@ void LLViewerObjectList::dirtyAllObjectInventory()
 	}
 }
 
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+void LLViewerObjectList::setAllObjectDefaultTextures(U32 nChannel, bool fShowDefault)
+{
+	LLPipeline::sRenderTextures = !fShowDefault;
+
+	for (LLViewerObject* pObj : mObjects)
+	{
+		LLDrawable* pDrawable = pObj->mDrawable;
+		if ( (pDrawable) && (!pDrawable->isDead()) )
+		{
+			for (int idxFace = 0, cntFace = pDrawable->getNumFaces(); idxFace < cntFace; idxFace++)
+			{
+				if (LLFace* pFace = pDrawable->getFace(idxFace))
+					pFace->setDefaultTexture(nChannel, fShowDefault);
+			}
+
+			if (LLVOVolume* pVoVolume = pDrawable->getVOVolume())
+				pVoVolume->markForUpdate(true);
+		}
+	}
+}
+// [/SL:KB]
+
 void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 {
 	S32 i;
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 94c751acc66b3d40b84626b60099a779d60edc08..c88bc00ac7af0df7751f50f3526715b2cdec2b33 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -123,6 +123,9 @@ class LLViewerObjectList
 	void resetObjectBeacons();
 
 	void dirtyAllObjectInventory();
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	void setAllObjectDefaultTextures(U32 nChannel, bool fShowDefault);
+// [/SL:KB]
 
 	void removeFromActiveList(LLViewerObject* objectp);
 	void updateActive(LLViewerObject *objectp);
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index dddfb6745e48887d7b0c27a6800c834eb58fc2c2..123c4bf17a80972ba92dd2236d54931fc3784a6e 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -2487,6 +2487,13 @@ boost::signals2::connection LLViewerParcelMgr::setTeleportFailedCallback(telepor
 	return mTeleportFailedSignal.connect(cb);
 }
 
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+boost::signals2::connection LLViewerParcelMgr::setTeleportDoneCallback(teleport_done_callback_t cb)
+{
+	return mTeleportDoneSignal.connect(cb);
+}
+// [/SL:KB]
+
 /* Ok, we're notified that teleport has been finished.
  * We should now propagate the notification via mTeleportFinishedSignal
  * to all interested parties.
@@ -2514,3 +2521,10 @@ void LLViewerParcelMgr::onTeleportFailed()
 {
 	mTeleportFailedSignal();
 }
+
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+void LLViewerParcelMgr::onTeleportDone()
+{
+	mTeleportDoneSignal();
+}
+// [/SL:KB]
diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h
index bb6bbf33083127c29b7e04d8cf7d1c65b7d70ae5..9d89e6a0608ad8913ddd2c5370a223245bb09fdd 100644
--- a/indra/newview/llviewerparcelmgr.h
+++ b/indra/newview/llviewerparcelmgr.h
@@ -81,6 +81,10 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr>
 	typedef boost::signals2::signal<void (const LLVector3d&, const bool&)> teleport_finished_signal_t;
 	typedef boost::function<void()> teleport_failed_callback_t;
 	typedef boost::signals2::signal<void()> teleport_failed_signal_t;
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+	typedef boost::function<void()> teleport_done_callback_t;
+	typedef boost::signals2::signal<void()> teleport_done_signal_t;
+// [/SL:KB]
 
 	LLViewerParcelMgr();
 	~LLViewerParcelMgr();
@@ -284,8 +288,14 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr>
 
 	boost::signals2::connection setTeleportFinishedCallback(teleport_finished_callback_t cb);
 	boost::signals2::connection setTeleportFailedCallback(teleport_failed_callback_t cb);
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+	boost::signals2::connection setTeleportDoneCallback(teleport_done_callback_t cb);
+// [/SL:KB]
 	void onTeleportFinished(bool local, const LLVector3d& new_pos);
 	void onTeleportFailed();
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+	void onTeleportDone();
+// [/SL:KB]
 
 	static BOOL isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power);
 	static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power);
@@ -340,6 +350,9 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr>
 	LLVector3d					mTeleportInProgressPosition;
 	teleport_finished_signal_t	mTeleportFinishedSignal;
 	teleport_failed_signal_t	mTeleportFailedSignal;
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+	teleport_done_signal_t		mTeleportDoneSignal;
+// [/SL:KB]
 
 	// Array of pieces of parcel edges to potentially draw
 	// Has (parcels_per_edge + 1) * (parcels_per_edge + 1) elements so
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index ed719ae41827b8127bc55ec813f1c541eb6a4164..f644a1c602d9186268e766b0421c07bf862b5629 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -76,6 +76,9 @@ LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sWhiteImagep = NULL;
 LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultImagep = NULL;
 LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sSmokeImagep = NULL;
 LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sFlatNormalImagep = NULL;
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultDiffuseImagep = NULL;
+// [/SL:KB]
 LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap;
 LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL;
 const std::string sTesterName("TextureTester");
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 8017d8260418e27b9a366af9c848535739d40771..b5d3b556fcfdc108de67faf4e7c48f5efa3a08c5 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -525,6 +525,9 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local.
 	static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture
 	static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	static LLPointer<LLViewerFetchedTexture> sDefaultDiffuseImagep;
+// [/SL:KB]
 };
 
 //
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index cd9ab3e6724b7b61169919cb12b98d45f63102dd..d196b6f1edf36259b8f3d90914dc0d7ad9c00827 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -209,6 +209,10 @@
 #include "llviewerwindowlistener.h"
 #include "llpaneltopinfobar.h"
 
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 #if LL_WINDOWS
 #include <tchar.h> // For Unicode conversion methods
 #endif
@@ -3757,6 +3761,15 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls,
 						{
 							moveable_object_selected = TRUE;
 							this_object_movable = TRUE;
+
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g
+							if ( (rlv_handler_t::isEnabled()) && 
+								 ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) )
+							{
+								if ((isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()))
+									moveable_object_selected = this_object_movable = FALSE;
+							}
+// [/RLVa:KB]
 						}
 						all_selected_objects_move = all_selected_objects_move && this_object_movable;
 						all_selected_objects_modify = all_selected_objects_modify && object->permModify();
@@ -4049,6 +4062,13 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 		found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end, pick_transparent,
 													face_hit, intersection, uv, normal, tangent);
 
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+		if ( (rlv_handler_t::isEnabled()) && (found) &&
+			 (LLToolCamera::getInstance()->hasMouseCapture()) && (gKeyboard->currentMask(TRUE) & MASK_ALT) )
+		{
+			found = NULL;
+		}
+// [/RLVa:KB]
 		if (!found) // if not found in HUD, look in world:
 		{
 			found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged,
@@ -4058,6 +4078,23 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 				gDebugRaycastIntersection = *intersection;
 			}
 		}
+
+// [RLVa:KB] - Checked: RLVa-1.2.0
+		if ( (found) && ((gTeleportDisplay) || ((rlv_handler_t::isEnabled()) && (found) && (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)))) )
+		{
+			// Allow picking if:
+			//   - the drag-and-drop tool is active (allows inventory offers)
+			//   - the camera tool is active
+			//   - the pie tool is active *and* we picked our own avie (allows "mouse steering" and the self pie menu)
+			LLTool* pCurTool = LLToolMgr::getInstance()->getCurrentTool();
+			if ( (LLToolDragAndDrop::getInstance() != pCurTool) && 
+			     (!LLToolCamera::getInstance()->hasMouseCapture()) &&
+			     ((LLToolPie::getInstance() != pCurTool) || (gAgent.getID() != found->getID())) )
+			{
+				found = NULL;
+			}
+		}
+// [/RLVa:KB]
 	}
 
 	return found;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f4010b0412de4ddd29f0d70da6dcd83d61484e01..0c27296482e02c283773cfde71ddcbffabe45b99 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -97,6 +97,10 @@
 #include "llanimstatelabels.h"
 #include "lltrans.h"
 #include "llappearancemgr.h"
+// [RLVa:KB] - Checked: RLVa-2.0.1
+#include "rlvactions.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "llgesturemgr.h" //needed to trigger the voice gesticulations
 #include "llvoiceclient.h"
@@ -2621,12 +2625,23 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 	const F32 time_visible = mTimeVisible.getElapsedTimeF32();
 	const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime");	// seconds
 	const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	bool fRlvShowAvTag = true, fRlvShowAvName = true;
+	if (RlvActions::isRlvEnabled())
+	{
+		fRlvShowAvTag = RlvActions::canShowName(RlvActions::SNC_NAMETAG, getID());
+		fRlvShowAvName = (fRlvShowAvTag) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID()));
+	}
+// [/RLVa:KB]
 	BOOL visible_avatar = isVisible() || mNeedsAnimUpdate;
 	BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping);
 	BOOL render_name =	visible_chat ||
-		(visible_avatar &&
-		 ((sRenderName == RENDER_NAME_ALWAYS) ||
-		  (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
+		                (visible_avatar &&
+// [RLVa:KB] - Checked: RLVa-2.0.1
+						(fRlvShowAvTag) &&
+// [/RLVa:KB]
+		                ((sRenderName == RENDER_NAME_ALWAYS) ||
+		                 (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
 	// If it's your own avatar, don't draw in mouselook, and don't
 	// draw if we're specifically hiding our own name.
 	if (isSelf())
@@ -2656,7 +2671,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 		new_name = TRUE;
 	}
 
-	if (sRenderGroupTitles != mRenderGroupTitles)
+// [RLVa:KB] - Checked: RLVa-0.2.0
+	if (!fRlvShowAvName)
+	{
+		if (mRenderGroupTitles)
+		{
+			mRenderGroupTitles = FALSE;
+			new_name = TRUE;
+		}
+	}
+	else if (sRenderGroupTitles != mRenderGroupTitles)
+// [/RLVa]
+//	if (sRenderGroupTitles != mRenderGroupTitles)
 	{
 		mRenderGroupTitles = sRenderGroupTitles;
 		new_name = TRUE;
@@ -2723,6 +2749,9 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
 	// Avatars must have a first and last name
 	if (!firstname || !lastname) return;
 
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	bool fRlvShowAvName = RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID());
+// [/RLVa:KB]
 	bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY)  != mSignaledAnimations.end();
 	bool is_do_not_disturb = mSignaledAnimations.find(ANIM_AGENT_DO_NOT_DISTURB) != mSignaledAnimations.end();
 	bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end();
@@ -2735,7 +2764,10 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
 	{
 		is_muted = isInMuteList();
 	}
-	bool is_friend = LLAvatarTracker::instance().isBuddy(getID());
+//	bool is_friend = LLAvatarTracker::instance().isBuddy(getID());
+// [RLVa:KB] - Checked: RLVa-1.2.2
+	bool is_friend = (fRlvShowAvName) && (LLAvatarTracker::instance().isBuddy(getID()));
+// [/RLVa:KB]
 	bool is_cloud = getIsCloud();
 
 	if (is_appearance != mNameAppearance)
@@ -2800,7 +2832,10 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
 				LLFontGL::getFontSansSerifSmall());
 		}
 
-		if (sRenderGroupTitles
+//		if (sRenderGroupTitles
+// [RLVa:KB] - Checked: RLVa-1.2.2
+		if (sRenderGroupTitles && fRlvShowAvName
+// [/RLVa:KB]
 			&& title && title->getString() && title->getString()[0] != '\0')
 		{
 			std::string title_str = title->getString();
@@ -2822,25 +2857,42 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
 				clearNameTag();
 			}
 
-			// Might be blank if name not available yet, that's OK
-			if (show_display_names)
+// [RLVa:KB] - Checked: RLVa-1.2.2
+			if ( (fRlvShowAvName) || (isSelf()) )
 			{
-				addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL,
-					LLFontGL::getFontSansSerif());
+// [/RLVa:KB]
+				// Might be blank if name not available yet, that's OK
+				if (show_display_names)
+				{
+					addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL,
+						LLFontGL::getFontSansSerif());
+				}
+				// Suppress SLID display if display name matches exactly (ugh)
+				if (show_usernames && !av_name.isDisplayNameDefault())
+				{
+					// *HACK: Desaturate the color
+					LLColor4 username_color = name_tag_color * 0.83f;
+					addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL,
+					LLFontGL::getFontSansSerifSmall());
+				}
+// [RLVa:KB] - Checked: RLVa-1.2.2
 			}
-			// Suppress SLID display if display name matches exactly (ugh)
-			if (show_usernames && !av_name.isDisplayNameDefault())
+			else
 			{
-				// *HACK: Desaturate the color
-				LLColor4 username_color = name_tag_color * 0.83f;
-				addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL,
-					LLFontGL::getFontSansSerifSmall());
+				addNameTagLine(RlvStrings::getAnonym(av_name), name_tag_color, LLFontGL::NORMAL, LLFontGL::getFontSansSerif());
 			}
+// [/RLVa:KB]
 		}
 		else
 		{
 			const LLFontGL* font = LLFontGL::getFontSansSerif();
 			std::string full_name = LLCacheName::buildFullName( firstname->getString(), lastname->getString() );
+// [RLVa:KB] - Checked: RLVa-1.2.2
+			if ( (!fRlvShowAvName) && (!isSelf()) )
+			{
+				full_name = RlvStrings::getAnonym(full_name);
+			}
+// [/RLVa:KB]
 			addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font);
 		}
 
@@ -5973,6 +6025,13 @@ void LLVOAvatar::sitDown(BOOL bSitting)
 	{
 		// Update Movement Controls according to own Sitting mode
 		LLFloaterMove::setSittingMode(bSitting);
+
+// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+		if (rlv_handler_t::isEnabled())
+		{
+			gRlvHandler.onSitOrStand(bSitting);
+		}
+// [/RLVa:KB]
 	}
 }
 
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 5f48898cb165319a53b9594cfe3d247a8b501b9a..16cbdbeeafb66506bfd545047d1a8f4eea874435 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -66,6 +66,15 @@
 #include "llstartup.h"
 #include "llsdserialize.h"
 #include "llcorehttputil.h"
+// [RLVa:KB] - Checked: RLVa-2.0.2
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+#include "llviewerparcelmgr.h"
+extern BOOL gTeleportDisplay;
+// [/SL:KB]
 
 #if LL_MSVC
 // disable boost::lexical_cast warning
@@ -161,6 +170,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
 							   const LLPCode pcode,
 							   LLViewerRegion* regionp) :
 	LLVOAvatar(id, pcode, regionp),
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+	mAttachmentSignal(NULL),
+// [/RLVa:KB]
 	mScreenp(NULL),
 	mLastRegionHandle(0),
 	mRegionCrossingCount(0),
@@ -222,6 +234,10 @@ void LLVOAvatarSelf::initInstance()
 		mInitialBakeIDs[i] = LLUUID::null;
 	}
 
+// [RLVa:KB] - Checked: 2010-12-12 (RLVa-1.2.2c) | Added: RLVa-1.2.2c
+	RlvAttachPtLookup::initLookupTable();
+// [/RLVa:KB]
+
 	status &= buildMenus();
 	if (!status)
 	{
@@ -438,6 +454,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 					item_params.name =(item_params.label );
 					item_params.on_click.function_name = "Object.AttachToAvatar";
 					item_params.on_click.parameter = iter->first;
+					// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 					item_params.on_enable.function_name = "Object.EnableWear";
 					item_params.on_enable.parameter = iter->first;
 					LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
@@ -509,6 +526,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 			item_params.name =(item_params.label );
 			item_params.on_click.function_name = "Object.AttachToAvatar";
 			item_params.on_click.parameter = iter->first;
+			// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 			item_params.on_enable.function_name = "Object.EnableWear";
 			item_params.on_enable.parameter = iter->first;
 			LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
@@ -552,6 +570,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 			item_params.name =(item_params.label );
 			item_params.on_click.function_name = "Object.AttachToAvatar";
 			item_params.on_click.parameter = iter->first;
+			// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 			item_params.on_enable.function_name = "Object.EnableWear";
 			item_params.on_enable.parameter = iter->first;
 			//* TODO: Skinning:
@@ -618,6 +637,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 				item_params.label = LLTrans::getString(attachment->getName());
 				item_params.on_click.function_name = "Object.AttachToAvatar";
 				item_params.on_click.parameter = attach_index;
+				// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 				item_params.on_enable.function_name = "Object.EnableWear";
 				item_params.on_enable.parameter = attach_index;
 
@@ -647,6 +667,10 @@ void LLVOAvatarSelf::cleanup()
 LLVOAvatarSelf::~LLVOAvatarSelf()
 {
 	cleanup();
+
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+	delete mAttachmentSignal;
+// [/RLVa:KB]
 }
 
 /**
@@ -1030,12 +1054,25 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
 		}
 		else
 		{
+// [RLVa:KB] - Checked: RLVa-2.0.2
+			bool fRlvCanShowAttachment = true;
+			if (rlv_handler_t::isEnabled())
+			{
+				fRlvCanShowAttachment =
+					(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELF)) &&
+					( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELFHEAD)) || (RLV_ATTACHGROUP_HEAD != rlvAttachGroupFromIndex(attachment->getGroup())) );
+			}
+// [/RLVa:KB]
+
 			switch (camera_mode)
 			{
 				case CAMERA_MODE_MOUSELOOK:
 					if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson())
 					{
-						attachment->setAttachmentVisibility(TRUE);
+// [RLVa:KB] - Checked: RLVa-2.0.2
+						attachment->setAttachmentVisibility(fRlvCanShowAttachment);
+// [/RLVa:KB]
+//						attachment->setAttachmentVisibility(TRUE);
 					}
 					else
 					{
@@ -1043,7 +1080,10 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
 					}
 					break;
 				default:
-					attachment->setAttachmentVisibility(TRUE);
+// [RLVa:KB] - Checked: RLVa-2.0.2
+					attachment->setAttachmentVisibility(fRlvCanShowAttachment);
+// [/RLVa:KB]
+//					attachment->setAttachmentVisibility(TRUE);
 					break;
 			}
 		}
@@ -1124,6 +1164,28 @@ LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id)
 	return NULL;
 }
 
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+boost::signals2::connection LLVOAvatarSelf::setAttachmentCallback(const attachment_signal_t::slot_type& cb)
+{
+	if (!mAttachmentSignal)
+		mAttachmentSignal = new attachment_signal_t();
+	return mAttachmentSignal->connect(cb);
+}
+// [/RLVa:KB]
+// [RLVa:KB] - Checked: 2010-03-14 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+LLViewerJointAttachment* LLVOAvatarSelf::getWornAttachmentPoint(const LLUUID& idItem) const
+{
+	const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem);
+	for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt)
+	{
+		LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+ 		if (pAttachPt->getAttachedObject(idItemBase))
+			return pAttachPt;
+	}
+	return NULL;
+}
+// [/RLVa:KB]
+
 bool LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const
 {
 	if (!gInventory.getItem(inv_item_id))
@@ -1172,6 +1234,22 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 		const LLUUID& attachment_id = viewer_object->getAttachmentItemID();
 		LLAppearanceMgr::instance().registerAttachment(attachment_id);
 		updateLODRiggedAttachments();		
+
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+		// NOTE: RLVa event handlers should be invoked *after* LLVOAvatar::attachObject() calls LLViewerJointAttachment::addObject()
+		if (mAttachmentSignal)
+		{
+			(*mAttachmentSignal)(viewer_object, attachment, ACTION_ATTACH);
+		}
+		if (rlv_handler_t::isEnabled())
+		{
+			RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment);
+			gRlvHandler.onAttach(viewer_object, attachment);
+
+			if ( (attachment->getIsHUDAttachment()) && (!gRlvAttachmentLocks.hasLockedHUD()) )
+				gRlvAttachmentLocks.updateLockedHUD();
+		}
+// [/RLVa:KB]
 	}
 
 	return attachment;
@@ -1181,6 +1259,27 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 {
 	const LLUUID attachment_id = viewer_object->getAttachmentItemID();
+
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	// NOTE: RLVa event handlers should be invoked *before* LLVOAvatar::detachObject() calls LLViewerJointAttachment::removeObject()
+	if (rlv_handler_t::isEnabled())
+	{
+		for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt)
+		{
+			const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+			if (pAttachPt->isObjectAttached(viewer_object))
+			{
+				RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt);
+				gRlvHandler.onDetach(viewer_object, pAttachPt);
+			}
+			if (mAttachmentSignal)
+			{
+				(*mAttachmentSignal)(viewer_object, pAttachPt, ACTION_DETACH);
+			}
+		}
+	}
+// [/RLVa:KB]
+
 	if ( LLVOAvatar::detachObject(viewer_object) )
 	{
 		// the simulator should automatically handle permission revocation
@@ -1213,6 +1312,11 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 			LLAppearanceMgr::instance().unregisterAttachment(attachment_id);
 		}
 		
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+		if ( (rlv_handler_t::isEnabled()) && (viewer_object->isHUDAttachment()) && (gRlvAttachmentLocks.hasLockedHUD()) )
+			gRlvAttachmentLocks.updateLockedHUD();
+// [/RLVa:KB]
+
 		return TRUE;
 	}
 	return FALSE;
@@ -1222,7 +1326,10 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id)
 {
 	LLInventoryItem* item = gInventory.getItem(item_id);
-	if (item)
+//	if (item)
+// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+	if ( (item) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(item))) )
+// [/RLVa:KB]
 	{
 		gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
 		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
@@ -2831,3 +2938,57 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
 	}
 	apr_file_printf( file, "\n</wearable_info>\n" );
 }
+
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+void LLVOAvatarSelf::addPendingDetach(const LLUUID& idObject)
+{
+	if (mPendingObjectDetach.end() == std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject))
+		mPendingObjectDetach.push_back(idObject);
+
+	if ((!mPendingObjectDetach.empty()) && (!mTeleportDoneConn.connected()))
+		mTeleportDoneConn = LLViewerParcelMgr::instance().setTeleportDoneCallback(boost::bind(&LLVOAvatarSelf::onTeleportDone, this));
+}
+
+bool LLVOAvatarSelf::isPendingDetach(const LLUUID& idObject) const
+{
+	return mPendingObjectDetach.end() != std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject);
+}
+
+void LLVOAvatarSelf::removePendingDetach(const LLUUID& idObject)
+{
+	auto itPendingDetach = std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject);
+	if (mPendingObjectDetach.end() != itPendingDetach)
+		mPendingObjectDetach.erase(itPendingDetach);
+
+	if (mPendingObjectDetach.empty())
+		mTeleportDoneConn.disconnect();
+}
+
+void LLVOAvatarSelf::onTeleportDone()
+{
+	mTeleportDoneConn.disconnect();
+	doAfterInterval(boost::bind(&LLVOAvatarSelf::checkPendingDetach, this), 30.f);
+}
+
+void LLVOAvatarSelf::checkPendingDetach()
+{
+	if (gTeleportDisplay)
+		return;
+
+	for (const LLUUID& idObj : mPendingObjectDetach)
+	{
+		LLViewerObject* pObject = gObjectList.findObject(idObj);
+		if (pObject)
+		{
+			gObjectList.killObject(pObject);
+			if (gShowObjectUpdates)
+			{
+				LLColor4 color(0.f, 1.f, 0.f, 1.f);
+				gPipeline.addDebugBlip(pObject->getPositionAgent(), color);
+			}
+			LLSelectMgr::getInstance()->removeObjectFromSelections(idObj);
+		}
+	}
+	mPendingObjectDetach.clear();
+}
+// [/SL:KB]
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index a9c4ab26a9ac0762f1131ebefd092f2ba3dd1e9d..ad80dedb9787e2a1eccb664af4c42205c784bc1d 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -296,10 +296,21 @@ class LLVOAvatarSelf :
 	BOOL 				isWearingAttachment(const LLUUID& inv_item_id) const;
 	LLViewerObject* 	getWornAttachment(const LLUUID& inv_item_id);
 	bool				getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const;
+// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i
+	LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id) const;
+// [/RLVa:KB]
 	/*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object);
 	/*virtual*/ BOOL 	detachObject(LLViewerObject *viewer_object);
 	static BOOL			detachAttachmentIntoInventory(const LLUUID& item_id);
 
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+	enum EAttachAction { ACTION_ATTACH, ACTION_DETACH };
+	typedef boost::signals2::signal<void (LLViewerObject*, const LLViewerJointAttachment*, EAttachAction)> attachment_signal_t;
+	boost::signals2::connection setAttachmentCallback(const attachment_signal_t::slot_type& cb);
+// [/RLVa:KB]
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+	attachment_signal_t* mAttachmentSignal;
+// [/RLVa:KB]
 	//--------------------------------------------------------------------
 	// HUDs
 	//--------------------------------------------------------------------
@@ -396,6 +407,18 @@ class LLVOAvatarSelf :
 	F32 					mDebugBakedTextureTimes[LLAvatarAppearanceDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture
 	void					debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
 
+// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0
+public:
+	void addPendingDetach(const LLUUID& idObject);
+	bool isPendingDetach(const LLUUID& idObject) const;
+	void removePendingDetach(const LLUUID& idObject);
+	void checkPendingDetach();
+	void onTeleportDone();
+protected:
+	std::list<LLUUID>           mPendingObjectDetach;
+	boost::signals2::connection mTeleportDoneConn;
+// [/SL:KB]
+
     void                    appearanceChangeMetricsCoro(std::string url);
     bool                    mInitialMetric;
     S32                     mMetricSequence;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e69a8d1d1d121bd137753571bd8ad6830d41a9cc..0711677566e736af2c36fe2a76f8b5d91c352890 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -77,6 +77,10 @@
 #include "llvoavatar.h"
 #include "llvocache.h"
 #include "llmaterialmgr.h"
+// [RLVa:KB] - Checked: RLVa-2.0.0
+#include "rlvactions.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
 const F32 FORCE_CULL_AREA = 8.f;
@@ -4432,7 +4436,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL;
 	}
 
-	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
+//	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
+// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c
+	const LLViewerObject* pObj = facep->getViewerObject();
+	if ( (pObj->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) &&
+		 ( (!RlvActions::isRlvEnabled()) ||
+		   ( ((!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) &&
+		     (RlvActions::canEdit(pObj)) ) ) )
+// [/RVLa:KB]
 	{
 		return;
 	}
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index f8981d0c51501cc03aba1e25a6237f3d8e1a8912..3324d05a93201fab6dfdadc1035654ad310c76ee 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -39,6 +39,10 @@
 #include "lltransutil.h"
 #include "llviewerattachmenu.h"
 #include "llvoavatarself.h"
+// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 class LLFindOutfitItems : public LLInventoryCollectFunctor
 {
@@ -848,6 +852,13 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
 
 	bool can_be_worn = true;
 
+// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	// We'll enable a menu option if at least one item in the selection is wearable/removable
+	bool rlvCanWearReplace = !rlv_handler_t::isEnabled();
+	bool rlvCanWearAdd = !rlv_handler_t::isEnabled();
+	bool rlvCanRemove = !rlv_handler_t::isEnabled();
+// [/RLVa:KB]
+
 	for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
 	{
 		LLUUID id = *it;
@@ -888,6 +899,29 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
 		{
 			can_be_worn = get_can_item_be_worn(item->getLinkedUUID());
 		}
+
+// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+		if (rlv_handler_t::isEnabled())
+		{
+			ERlvWearMask eWearMask = RLV_WEAR_LOCKED;
+			switch (item->getType())
+			{
+				case LLAssetType::AT_BODYPART:
+				case LLAssetType::AT_CLOTHING:
+					eWearMask = gRlvWearableLocks.canWear(item);
+					rlvCanRemove |= (is_worn) ? gRlvWearableLocks.canRemove(item) : false;
+					break;
+				case LLAssetType::AT_OBJECT:
+					eWearMask = gRlvAttachmentLocks.canAttach(item);
+					rlvCanRemove |= (is_worn) ? gRlvAttachmentLocks.canDetach(item) : false;
+					break;
+				default:
+					break;
+			}
+			rlvCanWearReplace |= ((eWearMask & RLV_WEAR_REPLACE) == RLV_WEAR_REPLACE);
+			rlvCanWearAdd |= ((eWearMask & RLV_WEAR_ADD) == RLV_WEAR_ADD);
+		}
+// [/RLVa:KB]
 	} // for
 
 	bool standalone = mParent ? mParent->isStandalone() : false;
@@ -895,10 +929,15 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
 
 	// *TODO: eliminate multiple traversals over the menu items
 	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);
+//	setMenuItemEnabled(menu, "wear_wear", 			n_already_worn == 0 && n_worn == 0);
 	setMenuItemVisible(menu, "wear_add",			wear_add_visible);
-	setMenuItemEnabled(menu, "wear_add",			LLAppearanceMgr::instance().canAddWearables(ids));
+//	setMenuItemEnabled(menu, "wear_add",			LLAppearanceMgr::instance().canAddWearables(ids));
 	setMenuItemVisible(menu, "wear_replace",		n_worn == 0 && n_already_worn != 0 && can_be_worn);
+// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	setMenuItemEnabled(menu, "wear_wear", 			n_already_worn == 0 && n_worn == 0 && rlvCanWearReplace);
+	setMenuItemEnabled(menu, "wear_add",			LLAppearanceMgr::instance().canAddWearables(ids) && rlvCanWearAdd);
+	setMenuItemEnabled(menu, "wear_replace",		rlvCanWearReplace);
+// [/RLVa:KB]
 	//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);
@@ -909,7 +948,12 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
 	setMenuItemVisible(menu, "take_off",			mask == MASK_CLOTHING && n_worn == n_items);
 	setMenuItemVisible(menu, "detach",				mask == MASK_ATTACHMENT && n_worn == n_items);
 	setMenuItemVisible(menu, "take_off_or_detach",	mask == (MASK_ATTACHMENT|MASK_CLOTHING));
-	setMenuItemEnabled(menu, "take_off_or_detach",	n_worn == n_items);
+//	setMenuItemEnabled(menu, "take_off_or_detach",	n_worn == n_items);
+// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	setMenuItemEnabled(menu, "take_off",			rlvCanRemove);
+	setMenuItemEnabled(menu, "detach",				rlvCanRemove);
+	setMenuItemEnabled(menu, "take_off_or_detach",	(n_worn == n_items) && (rlvCanRemove));
+// [/RLVa:KB]
 	setMenuItemVisible(menu, "object_profile",		!standalone);
 	setMenuItemEnabled(menu, "object_profile",		n_items == 1);
 	setMenuItemVisible(menu, "--no options--", 		FALSE);
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index 2b6d88efef7ecc2b5e98fd9cd3e2eea3b0c32e09..37eaa9425cf12e175d5100211476081a08522a66 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -61,6 +61,10 @@
 #include "curl/curl.h"
 #include "llstreamtools.h"
 
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+#include <boost/algorithm/string.hpp>
+// [/RLVa:KB]
+
 LLWLParamManager::LLWLParamManager() :
 
 	//set the defaults for the controls
@@ -644,6 +648,19 @@ void LLWLParamManager::getPresetNames(preset_name_list_t& region, preset_name_li
 	}
 }
 
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+const std::string& LLWLParamManager::findPreset(const std::string& strPresetName, LLEnvKey::EScope eScope)
+{
+	for (std::map<LLWLParamKey, LLWLParamSet>::const_iterator itList = mParamList.begin(); itList != mParamList.end(); itList++)
+	{
+		const LLWLParamKey& wlKey = itList->first;
+		if ( (wlKey.scope == eScope) && (boost::iequals(wlKey.name, strPresetName)) )
+			return wlKey.name;
+	}
+	return LLStringUtil::null;
+}
+// [/RLVa:KB]
+
 void LLWLParamManager::getUserPresetNames(preset_name_list_t& user) const
 {
 	preset_name_list_t region, sys; // unused
diff --git a/indra/newview/llwlparammanager.h b/indra/newview/llwlparammanager.h
index e13aed98edfc507d5bec39592e9fdc8493cc67a1..43baae3d41f599f7f482ce775043b9cb22d1cb4a 100644
--- a/indra/newview/llwlparammanager.h
+++ b/indra/newview/llwlparammanager.h
@@ -287,6 +287,10 @@ class LLWLParamManager : public LLSingleton<LLWLParamManager>
 	/// @return user and system preset names as a single list
 	void getPresetNames(preset_name_list_t& region, preset_name_list_t& user, preset_name_list_t& sys) const;
 
+// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+	const std::string& findPreset(const std::string& strPresetName, LLEnvKey::EScope eScope);
+// [/RLVa:KB]
+
 	/// @return user preset names
 	void getUserPresetNames(preset_name_list_t& user) const;
 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 11d3706821fa5cf20411502ce71ddd05f57c526a..a98c4145099b7062cdcbb1a070575ed78dbd7616 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1327,6 +1327,35 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi
 	}
 }
 
+// [RLVa:KB] - Checked: RLVa-2.0.1
+bool LLWorld::getAvatar(const LLUUID& idAvatar, LLVector3d& posAvatar) const
+{
+	for (const LLCharacter* pCharacter : LLCharacter::sInstances)
+	{
+		const LLVOAvatar* pAvatar = static_cast<const LLVOAvatar*>(pCharacter);
+		if ( (!pAvatar->isDead()) && (!pAvatar->mIsDummy) && (!pAvatar->isOrphaned()) && (idAvatar == pAvatar->getID()) )
+		{
+			posAvatar = pAvatar->getPositionGlobal();
+			return true;
+		}
+	}
+
+	for (const LLViewerRegion* pRegion : LLWorld::getInstance()->getRegionList())
+	{
+		for (S32 idxAgent = 0, cntAgent = pRegion->mMapAvatarIDs.size(); idxAgent < cntAgent; ++idxAgent)
+		{
+			if (idAvatar == pRegion->mMapAvatarIDs[idxAgent])
+			{
+				posAvatar = unpackLocalToGlobalPosition(pRegion->mMapAvatars[idxAgent], pRegion->getOriginGlobal());
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+// [/RLVa:KB]
+
 bool LLWorld::isRegionListed(const LLViewerRegion* region) const
 {
 	region_list_t::const_iterator it = find(mRegionList.begin(), mRegionList.end(), region);
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index b2d84180648ddfadc41c3ce0185f9354153451d8..325a120f55b6e921c29144fc0bda040ff3a12f33 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -162,6 +162,9 @@ class LLWorld : public LLSingleton<LLWorld>
 		uuid_vec_t* avatar_ids = NULL,
 		std::vector<LLVector3d>* positions = NULL, 
 		const LLVector3d& relative_to = LLVector3d(), F32 radius = FLT_MAX) const;
+// [RLVa:KB] - Checked: RLVa-2.0.1
+	bool getAvatar(const LLUUID& idAvatar, LLVector3d& posAvatar) const;
+// [/RLVa:KB]
 
 	// Returns 'true' if the region is in mRegionList,
 	// 'false' if the region has been removed due to region change
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 62fad322467a1387af688ae0f98d4774956d77ac..4b61841600f81bc1933fbfd32ce4a3ba7fbd8d5b 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -55,6 +55,9 @@
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
 #include "lltrans.h"
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "llglheaders.h"
 
@@ -459,7 +462,10 @@ void LLWorldMapView::draw()
 			{
 				mesg = info->getName();
 			}
-			if (!mesg.empty())
+//			if (!mesg.empty())
+// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
+			if ( (!mesg.empty()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) )
+// [/RLVa:KB]
 			{
 				font->renderUTF8(
 					mesg, 0,
@@ -993,7 +999,10 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4&
 	text_x = llclamp(text_x, half_text_width + TEXT_PADDING, getRect().getWidth() - half_text_width - TEXT_PADDING);
 	text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, getRect().getHeight() - font->getLineHeight() - TEXT_PADDING - vert_offset);
 
-	if (label != "")
+//	if (label != "")
+// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.4.5) | Added: RLVa-1.0.0
+	if ( (label != "") && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) )
+// [/RLVa:KB]
 	{
 		font->renderUTF8(
 			label, 0,
@@ -1053,7 +1062,12 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
 	{
 		LLViewerRegion *region = gAgent.getRegion();
 
-		std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.4.5) | Modified: RLVa-1.4.5
+		std::string message = llformat("%s (%s)", 
+			(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? info->getName().c_str() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION).c_str(), 
+			info->getAccessString().c_str());
+// [/RLVa:KB]
+//		std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
 
 		if (!info->isDown())
 		{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index c6bbfb1c8ffd975cd57f9642b4319dec6a68927c..a5ffdd5da99930578ddab2796df818d3ac62849a 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -114,6 +114,10 @@
 #include "llpathfindingpathtool.h"
 #include "llscenemonitor.h"
 #include "llprogressview.h"
+// [RLVa:KB] - Checked: RLVa-2.0.0
+#include "rlvactions.h"
+#include "rlvlocks.h"
+// [/RLVa:KB]
 
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
@@ -397,6 +401,9 @@ BOOL    LLPipeline::sMemAllocationThrottled = FALSE;
 S32		LLPipeline::sVisibleLightCount = 0;
 F32		LLPipeline::sMinRenderSize = 0.f;
 BOOL	LLPipeline::sRenderingHUDs;
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+bool	LLPipeline::sRenderTextures = true;
+// [/SL:KB]
 
 // EventHost API LLPipeline listener.
 static LLPipelineListener sPipelineListener;
@@ -784,7 +791,17 @@ void LLPipeline::resizeScreenTexture()
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
 		GLuint resY = gViewerWindow->getWorldViewHeightRaw();
 	
-		if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight()))
+// [RLVa:KB] - Checked: 2014-02-23 (RLVa-1.4.10)
+		U32 resMod = RenderResolutionDivisor, resAdjustedX = resX, resAdjustedY = resY;
+		if ( (resMod > 1) && (resMod < resX) && (resMod < resY) )
+		{
+			resAdjustedX /= resMod;
+			resAdjustedY /= resMod;
+		}
+
+		if ( (resAdjustedX != mScreen.getWidth()) || (resAdjustedY != mScreen.getHeight()) )
+// [/RLVa:KB]
+//		if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight()))
 		{
 			releaseScreenBuffers();
 		if (!allocateScreenBuffer(resX,resY))
@@ -3528,8 +3545,15 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 	
 	if (LLSelectMgr::getInstance()->mHideSelectedObjects)
 	{
-		if (drawablep->getVObj().notNull() &&
-			drawablep->getVObj()->isSelected())
+//		if (drawablep->getVObj().notNull() &&
+//			drawablep->getVObj()->isSelected())
+// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f
+		const LLViewerObject* pObj = drawablep->getVObj();
+		if ( (pObj) && (pObj->isSelected()) && 
+			 ( (!RlvActions::isRlvEnabled()) || 
+			   ( ((!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) && 
+			     (RlvActions::canEdit(pObj)) ) ) )
+// [/RVLa:KB]
 		{
 			return;
 		}
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index bba36351d9f374e9d18fd4f82a0fcd2f78493ac5..eb21b552d7cb0e2e88db81a3afba83ef581a833f 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -587,6 +587,9 @@ class LLPipeline
 	static S32				sVisibleLightCount;
 	static F32				sMinRenderSize;
 	static BOOL				sRenderingHUDs;
+// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0)
+	static bool				sRenderTextures;
+// [/SL:KB]
 
 	static LLTrace::EventStatHandle<S64> sStatBatchSize;
 
diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..913ded899cb48f47d7cefb0f0a255730f5b08335
--- /dev/null
+++ b/indra/newview/rlvactions.cpp
@@ -0,0 +1,370 @@
+/**
+ *
+ * Copyright (c) 2009-2016, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ *
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to
+ * abide by those obligations.
+ *
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llimview.h"
+#include "llviewercamera.h"
+#include "llvoavatarself.h"
+#include "llworld.h"
+#include "rlvactions.h"
+#include "rlvhelper.h"
+#include "rlvhandler.h"
+
+// ============================================================================
+// Camera
+//
+
+bool RlvActions::canChangeCameraFOV(const LLUUID& idRlvObject)
+{
+	// NOTE: if an object has exclusive camera control then all other objects are locked out
+	return (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM));
+}
+
+bool RlvActions::canChangeCameraPreset(const LLUUID& idRlvObject)
+{
+	// NOTE: if an object has exclusive camera control then all other objects are locked out
+	return
+		( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM)) ) &&
+		(!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET));
+}
+
+bool RlvActions::canChangeToMouselook()
+{
+	// User can switch to mouselook if:
+	//   - not specifically prevented from going into mouselook (NOTE: if an object has exclusive camera control only that object can prevent mouselook)
+	//   - there is no minimum camera distance defined (or it's higher than > 0m)
+	const RlvBehaviourModifier* pCamDistMinModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMIN);
+	return
+		( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) ? !gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_MOUSELOOK) : !gRlvHandler.hasBehaviour(pCamDistMinModifier->getPrimaryObject(), RLV_BHVR_SETCAM_MOUSELOOK) ) &&
+		( (!pCamDistMinModifier->hasValue()) || (pCamDistMinModifier->getValue<float>() == 0.f) );
+}
+
+bool RlvActions::isCameraDistanceClamped()
+{
+	return
+		(gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX)) ||
+		(gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMAX));
+}
+
+bool RlvActions::isCameraFOVClamped()
+{
+	return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX));
+}
+
+bool RlvActions::isCameraPresetLocked()
+{
+	return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET));
+}
+
+bool RlvActions::getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax)
+{
+	bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX);
+	if ( (fDistMin) || (fDistMax) )
+	{
+		static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_AVDISTMIN);
+		static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_AVDISTMAX);
+
+		nDistMax = (fDistMax) ? sCamDistMax : F32_MAX;
+		nDistMin = (fDistMin) ? sCamDistMin : 0.0;
+		return true;
+	}
+	return false;
+}
+
+bool RlvActions::getCameraOriginDistanceLimits(float& nDistMin, float& nDistMax)
+{
+	bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMAX);
+	if ( (fDistMin) || (fDistMax) )
+	{
+		static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_ORIGINDISTMIN);
+		static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_ORIGINDISTMAX);
+
+		nDistMax = (fDistMax) ? sCamDistMax : F32_MAX;
+		nDistMin = (fDistMin) ? sCamDistMin : 0.0;
+		return true;
+	}
+	return false;
+}
+
+bool RlvActions::getCameraFOVLimits(F32& nFOVMin, F32& nFOVMax)
+{
+	bool fClampMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN), fClampMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX);
+	if ( (fClampMin) || (fClampMax) )
+	{
+		static RlvCachedBehaviourModifier<float> sCamFovMin(RLV_MODIFIER_SETCAM_FOVMIN);
+		static RlvCachedBehaviourModifier<float> sCamFovMax(RLV_MODIFIER_SETCAM_FOVMAX);
+
+		nFOVMin = (fClampMin) ? sCamFovMin : LLViewerCamera::getInstance()->getMinView();
+		nFOVMax = (fClampMax) ? sCamFovMax : LLViewerCamera::getInstance()->getMaxView();
+		return true;
+	}
+	return false;
+}
+
+// ============================================================================
+// Communication/Avatar interaction
+//
+
+bool RlvActions::s_BlockNamesContexts[SNC_COUNT] = { 0 };
+
+bool RlvActions::canChangeActiveGroup(const LLUUID& idRlvObject)
+{
+	// User can change their active group if:
+	//   - not specifically restricted (by another object that the one specified) from changing their active group
+	return (idRlvObject.isNull()) ? !gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP) : !gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETGROUP, idRlvObject);
+}
+
+// Little helper function to check the IM exclusion range for @recvim, @sendim and @startim (returns: min_dist <= (pos user - pos target) <= max_dist)
+static bool rlvCheckAvatarIMDistance(const LLUUID& idAvatar, ERlvBehaviourModifier eModDistMin, ERlvBehaviourModifier eModDistMax)
+{
+	LLVector3d posAgent;
+	const RlvBehaviourModifier *pBhvrModDistMin = RlvBehaviourDictionary::instance().getModifier(eModDistMin), *pBhvrModDistMax = RlvBehaviourDictionary::instance().getModifier(eModDistMax);
+	if ( ((pBhvrModDistMin->hasValue()) || (pBhvrModDistMax->hasValue())) && (LLWorld::getInstance()->getAvatar(idAvatar, posAgent)) )
+	{
+		float nDist = llabs(dist_vec_squared(gAgent.getPositionGlobal(), posAgent));
+		return (nDist >= pBhvrModDistMin->getValue<float>()) && (nDist <= pBhvrModDistMax->getValue<float>());
+	}
+	return false;
+}
+
+bool RlvActions::canReceiveIM(const LLUUID& idSender)
+{
+	// User can receive an IM from "sender" (could be an agent or a group) if:
+	//   - not generally restricted from receiving IMs (or the sender is an exception or inside the exclusion range)
+	//   - not specifically restricted from receiving an IM from the sender
+	return
+		(!isRlvEnabled()) ||
+		( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.isException(RLV_BHVR_RECVIM, idSender)) || (rlvCheckAvatarIMDistance(idSender, RLV_MODIFIER_RECVIMDISTMIN, RLV_MODIFIER_RECVIMDISTMAX)) ) &&
+		  ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM)) || (!gRlvHandler.isException(RLV_BHVR_RECVIMFROM, idSender)) ) );
+}
+
+bool RlvActions::canPlayGestures()
+{
+	return (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDGESTURE));
+}
+
+bool RlvActions::canSendChannel(int nChannel)
+{
+	return
+		( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) || (gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, nChannel)) ) &&
+		( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNELEXCEPT)) || (!gRlvHandler.isException(RLV_BHVR_SENDCHANNELEXCEPT, nChannel)) );
+}
+
+bool RlvActions::canSendIM(const LLUUID& idRecipient)
+{
+	// User can send an IM to "recipient" (could be an agent or a group) if:
+	//   - not generally restricted from sending IMs (or the recipient is an exception or inside the exclusion range)
+	//   - not specifically restricted from sending an IM to the recipient
+	return
+		(!isRlvEnabled()) ||
+		( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) || (gRlvHandler.isException(RLV_BHVR_SENDIM, idRecipient)) || (rlvCheckAvatarIMDistance(idRecipient, RLV_MODIFIER_SENDIMDISTMIN, RLV_MODIFIER_SENDIMDISTMAX)) ) &&
+		  ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIMTO)) || (!gRlvHandler.isException(RLV_BHVR_SENDIMTO, idRecipient)) ) );
+}
+
+bool RlvActions::canStartIM(const LLUUID& idRecipient)
+{
+	// User can start an IM session with "recipient" (could be an agent or a group) if:
+	//   - not generally restricted from starting IM sessions (or the recipient is an exception or inside the exclusion range)
+	//   - not specifically restricted from starting an IM session with the recipient
+	//   - the session already exists
+	return
+		(!isRlvEnabled()) ||
+		( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIM)) || (gRlvHandler.isException(RLV_BHVR_STARTIM, idRecipient)) || (rlvCheckAvatarIMDistance(idRecipient, RLV_MODIFIER_STARTIMDISTMIN, RLV_MODIFIER_STARTIMDISTMAX)) ) &&
+		  ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIMTO)) || (!gRlvHandler.isException(RLV_BHVR_STARTIMTO, idRecipient)) ) ) ||
+		( (hasOpenP2PSession(idRecipient)) || (hasOpenGroupSession(idRecipient)) );
+}
+
+bool RlvActions::canShowName(EShowNamesContext eContext, const LLUUID& idAgent)
+{
+	// Handle most common case upfront
+	if (!s_BlockNamesContexts[eContext])
+		return true;
+
+	if (idAgent.notNull())
+	{
+		switch (eContext)
+		{
+			// Show/hide avatar nametag
+			case SNC_NAMETAG:
+				return (gRlvHandler.isException(RLV_BHVR_SHOWNAMETAGS, idAgent)) || (gAgentID == idAgent);
+			// Show/hide avatar name
+			case SNC_DEFAULT:
+			case SNC_TELEPORTOFFER:
+			case SNC_TELEPORTREQUEST:
+				return gRlvHandler.isException(RLV_BHVR_SHOWNAMES, idAgent);
+		}
+	}
+	return false;
+}
+
+bool RlvActions::canShowNearbyAgents()
+{
+	return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNEARBY);
+}
+
+// ============================================================================
+// Movement
+//
+
+bool RlvActions::canAcceptTpOffer(const LLUUID& idSender)
+{
+	return ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) || (gRlvHandler.isException(RLV_BHVR_TPLURE, idSender))) && (canStand());
+}
+
+bool RlvActions::autoAcceptTeleportOffer(const LLUUID& idSender)
+{
+	return ((idSender.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, idSender))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP));
+}
+
+bool RlvActions::canAcceptTpRequest(const LLUUID& idSender)
+{
+	return (!gRlvHandler.hasBehaviour(RLV_BHVR_TPREQUEST)) || (gRlvHandler.isException(RLV_BHVR_TPREQUEST, idSender));
+}
+
+bool RlvActions::autoAcceptTeleportRequest(const LLUUID& idRequester)
+{
+	return ((idRequester.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTPREQUEST, idRequester))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTPREQUEST));
+}
+
+// ============================================================================
+// Teleporting
+//
+
+bool RlvActions::canTeleportToLocal(const LLVector3d& posGlobal)
+{
+	// User can initiate a local teleport if:
+	//   - not restricted from "sit teleporting" (or the destination is within the allowed xy-radius)
+	//   - not restricted from teleporting locally (or the destination is within the allowed xy-radius)
+	//   - can stand up (or isn't sitting)
+	// NOTE: if we're teleporting due to an active command we should disregard any restrictions from the same object
+	const LLUUID& idRlvObjExcept = gRlvHandler.getCurrentObject();
+	bool fCanStand = RlvActions::canStand(idRlvObjExcept);
+	if ( (fCanStand) && ((gRlvHandler.hasBehaviourExcept(RLV_BHVR_SITTP, gRlvHandler.getCurrentObject())) || (gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOCAL, gRlvHandler.getCurrentObject()))) )
+	{
+		// User can stand up but is either @sittp or @tplocal restricted so we need to distance check
+		const F32 nDistSq = (LLVector2(posGlobal.mdV[0], posGlobal.mdV[1]) - LLVector2(gAgent.getPositionGlobal().mdV[0], gAgent.getPositionGlobal().mdV[1])).lengthSquared();
+		F32 nMaxDist = llmin(RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_TPLOCALDIST)->getValue<float>(), RLV_MODIFIER_TPLOCAL_DEFAULT);
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))
+			nMaxDist = llmin(nMaxDist, RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SITTPDIST)->getValue<F32>());
+		return (nDistSq < nMaxDist * nMaxDist);
+	}
+	return fCanStand;
+}
+
+bool RlvActions::canTeleportToLocation()
+{
+	// NOTE: if we're teleporting due to an active command we should disregard any restrictions from the same object
+	const LLUUID& idRlvObjExcept = gRlvHandler.getCurrentObject();
+	return (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOC, idRlvObjExcept)) && (RlvActions::canStand(idRlvObjExcept));
+}
+
+bool RlvActions::isLocalTp(const LLVector3d& posGlobal)
+{
+	const F32 nDistSq = (LLVector2(posGlobal.mdV[0], posGlobal.mdV[1]) - LLVector2(gAgent.getPositionGlobal().mdV[0], gAgent.getPositionGlobal().mdV[1])).lengthSquared();
+	return nDistSq < RLV_MODIFIER_TPLOCAL_DEFAULT * RLV_MODIFIER_TPLOCAL_DEFAULT;
+}
+
+// ============================================================================
+// World interaction
+//
+
+bool RlvActions::canEdit(const LLViewerObject* pObj)
+{
+	// User can edit the specified object if:
+	//   - not generally restricted from editing (or the object's root is an exception)
+	//   - not specifically restricted from editing this object's root
+	return
+		(pObj) &&
+		((!hasBehaviour(RLV_BHVR_EDIT)) || (gRlvHandler.isException(RLV_BHVR_EDIT, pObj->getRootEdit()->getID()))) &&
+		((!hasBehaviour(RLV_BHVR_EDITOBJ)) || (!gRlvHandler.isException(RLV_BHVR_EDITOBJ, pObj->getRootEdit()->getID())));
+}
+
+
+bool RlvActions::canSit(const LLViewerObject* pObj, const LLVector3& posOffset /*= LLVector3::zero*/)
+{
+	// User can sit on the specified object if:
+	//   - not prevented from sitting
+	//   - not prevented from standing up or not currently sitting
+	//   - not standtp restricted or not currently sitting (if the user is sitting and tried to sit elsewhere the tp would just kick in)
+	//   - not a regular sit (i.e. due to @sit:<uuid>=force)
+	//   - not @sittp=n or @fartouch=n restricted or if they clicked on a point within the allowed radius
+	static RlvCachedBehaviourModifier<float> s_nFarTouchDist(RLV_MODIFIER_FARTOUCHDIST);
+	static RlvCachedBehaviourModifier<float> s_nSitTpDist(RLV_MODIFIER_SITTPDIST);
+	return
+		( (pObj) && (LL_PCODE_VOLUME == pObj->getPCode()) ) &&
+		(!hasBehaviour(RLV_BHVR_SIT)) &&
+		( ((!hasBehaviour(RLV_BHVR_UNSIT)) && (!hasBehaviour(RLV_BHVR_STANDTP))) ||
+		  ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())) ) &&
+		( ( (NULL != gRlvHandler.getCurrentCommand()) && (RLV_BHVR_SIT == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) ||
+		  ( ((!hasBehaviour(RLV_BHVR_SITTP)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < s_nSitTpDist * s_nSitTpDist)) &&
+		    ((!hasBehaviour(RLV_BHVR_FARTOUCH)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < s_nFarTouchDist * s_nFarTouchDist)) ) );
+}
+
+bool RlvActions::canStand()
+{
+	// NOTE: return FALSE only if we're @unsit=n restricted and the avie is currently sitting on something and TRUE for everything else
+	return (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting()));
+}
+
+bool RlvActions::canStand(const LLUUID& idRlvObjExcept)
+{
+	// NOTE: must match generic function above
+	return (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_UNSIT, idRlvObjExcept)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting()));
+}
+
+// Checked: 2014-02-24 (RLVa-1.4.10)
+bool RlvActions::canShowLocation()
+{
+	return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+}
+
+// ============================================================================
+// Helper functions
+//
+
+template<>
+const float& RlvActions::getModifierValue<float>(ERlvBehaviourModifier eBhvrMod)
+{
+	return RlvBehaviourDictionary::instance().getModifier(eBhvrMod)->getValue<float>();
+}
+
+// Checked: 2013-05-10 (RLVa-1.4.9)
+bool RlvActions::hasBehaviour(ERlvBehaviour eBhvr)
+{
+	return gRlvHandler.hasBehaviour(eBhvr);
+}
+
+// Checked: 2013-05-09 (RLVa-1.4.9)
+bool RlvActions::hasOpenP2PSession(const LLUUID& idAgent)
+{
+	const LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent);
+	return (idSession.notNull()) && (LLIMMgr::instance().hasSession(idSession));
+}
+
+// Checked: 2013-05-09 (RLVa-1.4.9)
+bool RlvActions::hasOpenGroupSession(const LLUUID& idGroup)
+{
+	return (idGroup.notNull()) && (LLIMMgr::instance().hasSession(idGroup));
+}
+
+// Checked: 2013-11-08 (RLVa-1.4.9)
+bool RlvActions::isRlvEnabled()
+{
+	return RlvHandler::isEnabled();
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h
new file mode 100644
index 0000000000000000000000000000000000000000..c034e829a1a960b178975f5eeed6403497fd5cd5
--- /dev/null
+++ b/indra/newview/rlvactions.h
@@ -0,0 +1,224 @@
+/**
+ *
+ * Copyright (c) 2009-2016, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ *
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to
+ * abide by those obligations.
+ *
+ */
+
+#ifndef RLV_ACTIONS_H
+#define RLV_ACTIONS_H
+
+#include "rlvdefines.h"
+
+// ============================================================================
+// RlvActions class declaration - developer-friendly non-RLVa code facing class, use in lieu of RlvHandler whenever possible
+//
+
+class RlvActions
+{
+	// ======
+	// Camera
+	// ======
+public:
+	/*
+	 * Returns true if the specified object cannot manipulate the camera FOV
+	 */
+	static bool canChangeCameraFOV(const LLUUID& idRlvObject);
+
+	/*
+	 * Returns true if the specified object can manipulate the camera offset and/or focus offset values
+	 */
+	static bool canChangeCameraPreset(const LLUUID& idRlvObject);
+
+	/*
+	 * Returns true if the user can switch to mouselook
+	 */
+	static bool canChangeToMouselook();
+
+	/*
+	 * Returns true if the camera's distance (from either the avatar of the focus) is currently restricted/clamped
+	 */
+	static bool isCameraDistanceClamped();
+
+	/*
+	 * Returns true if the camera's FOV is currently restricted/clamped
+	 */
+	static bool isCameraFOVClamped();
+
+	/*
+	 * Returns true if the camera offset and focus offset are locked (prevents changing the current camera preset)
+	 */
+	static bool isCameraPresetLocked();
+
+	/*
+	 * Retrieves the current (avatar or focus) camera distance limits
+	 */
+	static bool getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax);
+	static bool getCameraOriginDistanceLimits(float& nDistMin, float& nDistMax);
+
+	/*
+	 * Retrieves the current camera FOV limits - returns isCameraFOVClamped()
+	 */
+	static bool getCameraFOVLimits(float& nFOVMin, float& nFOVMax);
+
+	// ================================
+	// Communication/Avatar interaction
+	// ================================
+public:
+	/*
+	 * Returns true if the user is allowed to change their currently active group
+	 */
+	static bool canChangeActiveGroup(const LLUUID& idRlvObject = LLUUID::null);
+
+	/*
+	 * Returns true if the user is allowed to receive IMs from the specified sender (can be an avatar or a group)
+	 */
+	static bool canReceiveIM(const LLUUID& idSender);
+
+	/*
+	 * Returns true if the user is allowed to send/play gestures (whether active ones from the chat bar or using the gesture preview floater)
+	 */
+	static bool canPlayGestures();
+
+	/*
+	 * Returns true if the user is allowed to chat on the specified channel
+	 */
+	static bool canSendChannel(int nChannel);
+
+	/*
+	 * Returns true if the user is allowed to send IMs to the specified recipient (can be an avatar or a group)
+	 */
+	static bool canSendIM(const LLUUID& idRecipient);
+
+	/*
+	 * Returns true if the user is allowed to start a - P2P or group - conversation with the specified UUID (or if the session already exists)
+	 */
+	static bool canStartIM(const LLUUID& idRecipient);
+
+	/*
+	 * Returns true if an avatar's name should be hidden for the requested operation/context
+	 * (This is used to hide an avatar name in one case but not a near-identical case - such as teleporting a friend vs a nearby agent -
+	 *  in a way that limits the amount of code that needs to be changed to carry context from one function to another)
+	 */
+	enum EShowNamesContext { SNC_DEFAULT = 0, SNC_NAMETAG, SNC_TELEPORTOFFER, SNC_TELEPORTREQUEST, SNC_COUNT };
+	static bool canShowName(EShowNamesContext eContext, const LLUUID& idAgent = LLUUID::null);
+	static void setShowName(EShowNamesContext eContext, bool fCanShowName) { if ( (eContext < SNC_COUNT) && (isRlvEnabled()) ) { s_BlockNamesContexts[eContext] = !fCanShowName; } }
+
+	/*
+	 * Returns true if the user is allowed to see the presence of nearby avatars in UI elements (anonymized or otherwise)
+	 */
+	static bool canShowNearbyAgents();
+
+protected:
+	// Backwards logic so that we can initialize to 0 and it won't block when we forget to/don't check if RLVa is disabled
+	static bool s_BlockNamesContexts[SNC_COUNT];
+
+	// ========
+	// Movement
+	// ========
+public:
+	/*
+	 * Returns true if the user can accept an incoming teleport offer from the specified avatar
+	 */
+	static bool canAcceptTpOffer(const LLUUID& idSender);
+
+	/*
+	 * Returns true if a teleport offer from the specified avatar should be auto-accepted
+	 * (pass the null UUID to check if all teleport offers should be auto-accepted regardless of sender)
+	 */
+	static bool autoAcceptTeleportOffer(const LLUUID& idSender);
+
+	/*
+	 * Returns true if the user can accept an incoming teleport request from the specified avatar
+	 */
+	static bool canAcceptTpRequest(const LLUUID& idSender);
+
+	/*
+	 * Returns true if a teleport request from the specified avatar should be auto-accepted
+	 * (pass the null UUID to check if all teleport requests should be auto-accepted regardless of requester)
+	 */
+	static bool autoAcceptTeleportRequest(const LLUUID& idRequester);
+
+	// ===========
+	// Teleporting
+	// ===========
+public:
+	/*
+	 * Returns true if the user can teleport locally (short distances)
+	 */
+	static bool canTeleportToLocal(const LLVector3d& posGlobal);
+
+	/*
+	 * Returns true if the user can teleport to a (remote) location
+	 */
+	static bool canTeleportToLocation();
+
+	/*
+	 * Returns true if the teleport is considered local (e.g. double-click tp)
+	 */
+	static bool isLocalTp(const LLVector3d& posGlobal);
+
+	// =================
+	// World interaction
+	// =================
+public:
+	/*
+	 * Returns true if the user can edit the specified object
+	 */
+	static bool canEdit(const LLViewerObject* pObj);
+
+	/*
+	 * Returns true if the user can sit up on the specified object
+	 */
+	static bool canSit(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero);
+
+	/*
+	 * Returns true if the user can stand up (returns true if the user isn't currently sitting)
+	 */
+	static bool canStand();
+	static bool canStand(const LLUUID& idRlvObjExcept);
+
+	/*
+	 * Returns true if the user can see their in-world location
+	 */
+	static bool canShowLocation();
+
+	// ================
+	// Helper functions
+	// ================
+public:
+	/*
+	 * Convenience function to get the current/active value of a behaviour modifier
+	 */
+	template<typename T> static const T& getModifierValue(ERlvBehaviourModifier eBhvrMod);
+
+	/*
+	 * Convenience function to check for a behaviour without having to include rlvhandler.h.
+	 * Do NOT call this function if speed is important (i.e. per-frame)
+	 */
+	static bool hasBehaviour(ERlvBehaviour eBhvr);
+
+	/*
+	 * Returns true if a - P2P or group - IM session is open with the specified UUID
+	 */
+	static bool hasOpenP2PSession(const LLUUID& idAgent);
+	static bool hasOpenGroupSession(const LLUUID& idGroup);
+
+	/*
+	 * Convenience function to check if RLVa is enabled without having to include rlvhandler.h
+	 */
+	static bool isRlvEnabled();
+};
+
+// ============================================================================
+
+#endif // RLV_ACTIONS_H
diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..88fde865d24e97901862ffc2ed73cf3eda8d8fca
--- /dev/null
+++ b/indra/newview/rlvcommon.cpp
@@ -0,0 +1,846 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llagentui.h"
+#include "llavatarnamecache.h"
+#include "llinstantmessage.h"
+#include "llnotificationsutil.h"
+#include "llregionhandle.h"
+#include "llscriptruntimeperms.h"
+#include "llsdserialize.h"
+#include "lltrans.h"
+#include "llversioninfo.h"
+#include "llviewerparcelmgr.h"
+#include "llviewermenu.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llworld.h"
+
+#include "rlvactions.h"
+#include "rlvcommon.h"
+#include "rlvhelper.h"
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/regex.hpp>
+
+
+// ============================================================================
+// Forward declarations
+//
+
+// llviewermenu.cpp
+LLVOAvatar* find_avatar_from_object(LLViewerObject* object);
+
+// ============================================================================
+// RlvNotifications
+//
+
+// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b
+/*
+void RlvNotifications::warnGiveToRLV()
+{
+	if ( (gSavedSettings.getWarning(RLV_SETTING_FIRSTUSE_GIVETORLV)) && (RlvSettings::getForbidGiveToRLV()) )
+		LLNotifications::instance().add(RLV_SETTING_FIRSTUSE_GIVETORLV, LLSD(), LLSD(), &RlvNotifications::onGiveToRLVConfirmation);
+}
+*/
+
+// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b
+/*
+void RlvNotifications::onGiveToRLVConfirmation(const LLSD& notification, const LLSD& response)
+{
+	gSavedSettings.setWarning(RLV_SETTING_FIRSTUSE_GIVETORLV, FALSE);
+
+	S32 idxOption = LLNotification::getSelectedOption(notification, response);
+	if ( (0 == idxOption) || (1 == idxOption) )
+		gSavedSettings.setBOOL(RLV_SETTING_FORBIDGIVETORLV, (idxOption == 1));
+}
+*/
+
+// =========================================================================
+// RlvSettings
+//
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+bool RlvSettings::s_fCompositeFolders = false;
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+bool RlvSettings::s_fCanOOC = true;
+bool RlvSettings::s_fLegacyNaming = true;
+bool RlvSettings::s_fNoSetEnv = false;
+bool RlvSettings::s_fTempAttach = true;
+std::list<LLUUID> RlvSettings::s_CompatItemCreators;
+std::list<std::string> RlvSettings::s_CompatItemNames;
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0i
+void RlvSettings::initClass()
+{
+	static bool fInitialized = false;
+	if (!fInitialized)
+	{
+		initCompatibilityMode(LLStringUtil::null);
+
+		s_fTempAttach = rlvGetSetting<bool>(RLV_SETTING_ENABLETEMPATTACH, true);
+		if (gSavedSettings.controlExists(RLV_SETTING_ENABLETEMPATTACH))
+			gSavedSettings.getControl(RLV_SETTING_ENABLETEMPATTACH)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fTempAttach));
+
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		s_fCompositeFolders = rlvGetSetting<bool>(RLV_SETTING_ENABLECOMPOSITES, false);
+		if (gSavedSettings.controlExists(RLV_SETTING_ENABLECOMPOSITES))
+			gSavedSettings.getControl(RLV_SETTING_ENABLECOMPOSITES)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fCompositeFolders));
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+		s_fLegacyNaming = rlvGetSetting<bool>(RLV_SETTING_ENABLELEGACYNAMING, true);
+		if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING))
+			gSavedSettings.getControl(RLV_SETTING_ENABLELEGACYNAMING)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fLegacyNaming));
+
+		s_fCanOOC = rlvGetSetting<bool>(RLV_SETTING_CANOOC, true);
+		s_fNoSetEnv = rlvGetSetting<bool>(RLV_SETTING_NOSETENV, false);
+
+		// Don't allow toggling RLVaLoginLastLocation from the debug settings floater
+		if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION))
+			gSavedPerAccountSettings.getControl(RLV_SETTING_LOGINLASTLOCATION)->setHiddenFromSettingsEditor(true);
+
+		if (gSavedSettings.controlExists(RLV_SETTING_TOPLEVELMENU))
+			gSavedSettings.getControl(RLV_SETTING_TOPLEVELMENU)->getSignal()->connect(boost::bind(&onChangedMenuLevel));
+
+		fInitialized = true;
+	}
+}
+
+// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d
+void RlvSettings::updateLoginLastLocation()
+{
+	if ( (!LLApp::isQuitting()) && (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) )
+	{
+		BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!RlvActions::canStand());
+		if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue)
+		{
+			gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue);
+			gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
+		}
+	}
+}
+
+// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b
+bool RlvSettings::onChangedMenuLevel()
+{
+	rlvMenuToggleVisible();
+	return true;
+}
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0i
+bool RlvSettings::onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting)
+{
+	if (pfSetting)
+		*pfSetting = sdValue.asBoolean();
+	return true;
+}
+
+// Checked: 2015-05-25 (RLVa-1.5.0)
+void RlvSettings::onChangedSettingMain(const LLSD& sdValue)
+{
+	if (sdValue.asBoolean() != (bool)rlv_handler_t::isEnabled())
+	{
+		LLNotificationsUtil::add(
+			"GenericAlert",
+			LLSD().with("MESSAGE", llformat(LLTrans::getString("RLVaToggleMessage").c_str(), 
+				(sdValue.asBoolean()) ? LLTrans::getString("RLVaToggleEnabled").c_str()
+				                      : LLTrans::getString("RLVaToggleDisabled").c_str())));
+	}
+}
+
+void RlvSettings::initCompatibilityMode(std::string strCompatList)
+{
+	// NOTE: this function can be called more than once
+	s_CompatItemCreators.clear();
+	s_CompatItemNames.clear();
+
+	strCompatList.append(";").append(rlvGetSetting<std::string>("RLVaCompatibilityModeList", ""));
+
+	boost_tokenizer tokCompatList(strCompatList, boost::char_separator<char>(";", "", boost::drop_empty_tokens));
+	for (const std::string& strCompatEntry : tokCompatList)
+	{
+		if (boost::starts_with(strCompatEntry, "creator:"))
+		{
+			LLUUID idCreator;
+			if ( (44 == strCompatEntry.size()) && (LLUUID::parseUUID(strCompatEntry.substr(8), &idCreator)) &&
+			     (s_CompatItemCreators.end() == std::find(s_CompatItemCreators.begin(), s_CompatItemCreators.end(), idCreator)) )
+			{
+				s_CompatItemCreators.push_back(idCreator);
+			}
+		}
+		else if (boost::starts_with(strCompatEntry, "name:"))
+		{
+			if (strCompatEntry.size() > 5)
+				s_CompatItemNames.push_back(strCompatEntry.substr(5));
+		}
+	}
+}
+
+bool RlvSettings::isCompatibilityModeObject(const LLUUID& idRlvObject)
+{
+	bool fCompatMode = false;
+	if (idRlvObject.notNull())
+	{
+		const LLViewerObject* pObj = gObjectList.findObject(idRlvObject);
+		if ( (pObj) && (pObj->isAttachment()) )
+		{
+			const LLViewerInventoryItem* pItem = gInventory.getItem(pObj->getAttachmentItemID());
+			if (pItem)
+			{
+				fCompatMode = s_CompatItemCreators.end() != std::find(s_CompatItemCreators.begin(), s_CompatItemCreators.end(), pItem->getCreatorUUID());
+				if (!fCompatMode)
+				{
+					const std::string& strAttachName = pItem->getName();
+					for (const std::string& strCompatName : s_CompatItemNames)
+					{
+					    boost::regex regexp(strCompatName, boost::regex::perl | boost::regex::icase);
+						if (boost::regex_match(strAttachName, regexp))
+						{
+							fCompatMode = true;
+							break;
+						}
+					}
+				}
+			}
+		}
+	}
+	return fCompatMode;
+}
+
+// ============================================================================
+// RlvStrings
+//
+
+std::vector<std::string> RlvStrings::m_Anonyms;
+RlvStrings::string_map_t RlvStrings::m_StringMap;
+std::string RlvStrings::m_StringMapPath;
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvStrings::initClass()
+{
+	static bool fInitialized = false;
+	if (!fInitialized)
+	{
+		// Load the default string values
+		std::vector<std::string> files = gDirUtilp->findSkinnedFilenames(LLDir::XUI, RLV_STRINGS_FILE, LLDir::ALL_SKINS);
+		m_StringMapPath = (!files.empty()) ? files.front() : LLStringUtil::null;
+		for (std::vector<std::string>::const_iterator itFile = files.begin(); itFile != files.end(); ++itFile)
+		{
+			loadFromFile(*itFile, false);
+		}
+
+		// Load the custom string overrides
+		loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE), true);
+
+		// Sanity check
+		if ( (m_StringMap.empty()) || (m_Anonyms.empty()) )
+		{
+			RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL;
+			return;
+		}
+
+		fInitialized = true;
+	}
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvStrings::loadFromFile(const std::string& strFilePath, bool fUserOverride)
+{
+	llifstream fileStream(strFilePath.c_str(), std::ios::binary); LLSD sdFileData;
+	if ( (!fileStream.is_open()) || (!LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) )
+		return;
+	fileStream.close();
+
+	if (sdFileData.has("strings"))
+	{
+		const LLSD& sdStrings = sdFileData["strings"];
+		for (LLSD::map_const_iterator itString = sdStrings.beginMap(); itString != sdStrings.endMap(); ++itString)
+		{
+			if ( (!itString->second.has("value")) || ((fUserOverride) && (!hasString(itString->first))) )
+				continue;
+
+			std::list<std::string>& listValues = m_StringMap[itString->first];
+			if (!fUserOverride)
+			{
+				if (listValues.size() > 0)
+					listValues.pop_front();
+				listValues.push_front(itString->second["value"].asString());
+			}
+			else
+			{
+				while (listValues.size() > 1)
+					listValues.pop_back();
+				listValues.push_back(itString->second["value"].asString());
+			}
+		}
+	}
+	if (sdFileData.has("anonyms"))
+	{
+		const LLSD& sdAnonyms = sdFileData["anonyms"];
+		for (LLSD::array_const_iterator itAnonym = sdAnonyms.beginArray(); itAnonym != sdAnonyms.endArray(); ++itAnonym)
+		{
+			m_Anonyms.push_back((*itAnonym).asString());
+		}
+	}
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvStrings::saveToFile(const std::string& strFilePath)
+{
+	LLSD sdFileData;
+
+	LLSD& sdStrings = sdFileData["strings"];
+	for (string_map_t::const_iterator itString = m_StringMap.begin(); itString != m_StringMap.end(); ++itString)
+	{
+		const std::list<std::string>& listValues = itString->second;
+		if (listValues.size() > 1)
+			sdStrings[itString->first]["value"] = listValues.back();
+	}
+
+	llofstream fileStream(strFilePath.c_str());
+	if (!fileStream.good())
+		return;
+
+	LLSDSerialize::toPrettyXML(sdFileData, fileStream);
+	fileStream.close();
+}
+
+// Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a
+const std::string& RlvStrings::getAnonym(const std::string& strName)
+{
+	const char* pszName = strName.c_str(); U32 nHash = 0;
+	
+	// Test with 11,264 SL names showed a 3.33% - 3.82% occurance for each so we *should* get a very even spread
+	for (int idx = 0, cnt = strName.length(); idx < cnt; idx++)
+		nHash += pszName[idx];
+
+	return m_Anonyms[nHash % m_Anonyms.size()];
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+const std::string& RlvStrings::getString(const std::string& strStringName)
+{
+	static const std::string strMissing = "(Missing RLVa string)";
+	string_map_t::const_iterator itString = m_StringMap.find(strStringName);
+	return (itString != m_StringMap.end()) ? itString->second.back() : strMissing;
+}
+
+// Checked: 2009-11-25 (RLVa-1.1.0f) | Added: RLVa-1.1.0f
+const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet)
+{
+	// TODO-RLVa: [2009-11-25] clean this up along with the calling code in process_chat_from_simulator() once we're happy with the output
+	switch (eRet)
+	{
+		case RLV_RET_SUCCESS_UNSET:
+			return "unset";
+		case RLV_RET_SUCCESS_DUPLICATE:
+			return "duplicate";
+		case RLV_RET_SUCCESS_DELAYED:
+			return "delayed";
+		case RLV_RET_SUCCESS_DEPRECATED:
+			return "deprecated";
+		case RLV_RET_FAILED_SYNTAX:
+			return "thingy error";
+		case RLV_RET_FAILED_OPTION:
+			return "invalid option";
+		case RLV_RET_FAILED_PARAM:
+			return "invalid param";
+		case RLV_RET_FAILED_LOCK:
+			return "locked command";
+		case RLV_RET_FAILED_DISABLED:
+			return "disabled command";
+		case RLV_RET_FAILED_UNKNOWN:
+			return "unknown command";
+		case RLV_RET_FAILED_NOSHAREDROOT:
+			return "missing #RLV";
+		case RLV_RET_FAILED_DEPRECATED:
+			return "deprecated and disabled";
+		// The following are identified by the chat verb
+		case RLV_RET_RETAINED:
+		case RLV_RET_SUCCESS:
+		case RLV_RET_FAILED:
+			break;
+		// The following shouldn't occur
+		case RLV_RET_UNKNOWN:
+		default:
+			RLV_ASSERT(false);
+			break;
+	};
+	return NULL;
+}
+
+std::string RlvStrings::getVersion(const LLUUID& idRlvObject, bool fLegacy)
+{
+	bool fCompatMode = RlvSettings::isCompatibilityModeObject(idRlvObject);
+	return llformat("%s viewer v%d.%d.%d (RLVa %d.%d.%d)",
+		( (!fLegacy) ? "RestrainedLove" : "RestrainedLife" ),
+		(!fCompatMode) ? RLV_VERSION_MAJOR : RLV_VERSION_MAJOR_COMPAT, (!fCompatMode) ? RLV_VERSION_MINOR : RLV_VERSION_MINOR_COMPAT, (!fCompatMode) ? RLV_VERSION_PATCH : RLV_VERSION_PATCH_COMPAT,
+		RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH);
+}
+
+std::string RlvStrings::getVersionAbout()
+{
+	return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, LLVersionInfo::getBuild());
+}
+
+std::string RlvStrings::getVersionNum(const LLUUID& idRlvObject)
+{
+	bool fCompatMode = RlvSettings::isCompatibilityModeObject(idRlvObject);
+	return llformat("%d%02d%02d%02d",
+		(!fCompatMode) ? RLV_VERSION_MAJOR : RLV_VERSION_MAJOR_COMPAT, (!fCompatMode) ? RLV_VERSION_MINOR : RLV_VERSION_MINOR_COMPAT,
+		(!fCompatMode) ? RLV_VERSION_PATCH : RLV_VERSION_PATCH_COMPAT, (!fCompatMode) ? RLV_VERSION_BUILD : RLV_VERSION_BUILD_COMPAT);
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+bool RlvStrings::hasString(const std::string& strStringName, bool fCheckCustom)
+{
+	string_map_t::const_iterator itString = m_StringMap.find(strStringName);
+	return (itString != m_StringMap.end()) && ((!fCheckCustom) || (itString->second.size() > 0));
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvStrings::setCustomString(const std::string& strStringName, const std::string& strStringValue)
+{
+	if (!hasString(strStringName))
+		return;
+
+	std::list<std::string>& listValues = m_StringMap[strStringName];
+	while (listValues.size() > 1)
+		listValues.pop_back();
+	if (!strStringValue.empty())
+		listValues.push_back(strStringValue);
+}
+
+// ============================================================================
+// RlvUtil
+//
+
+bool RlvUtil::m_fForceTp = false;
+
+// Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a
+void RlvUtil::filterLocation(std::string& strUTF8Text)
+{
+	// Filter any mention of the surrounding region names
+	LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList();
+	const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+	for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion)
+		boost::ireplace_all(strUTF8Text, (*itRegion)->getName(), strHiddenRegion);
+
+	// Filter any mention of the parcel name
+	LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance();
+	if (pParcelMgr)
+		boost::ireplace_all(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL));
+}
+
+// Checked: 2010-12-08 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c
+void RlvUtil::filterNames(std::string& strUTF8Text, bool fFilterLegacy, bool fClearMatches)
+{
+	uuid_vec_t idAgents;
+	LLWorld::getInstance()->getAvatars(&idAgents, NULL);
+	for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++)
+	{
+		LLAvatarName avName;
+		// NOTE: if we're agressively culling nearby names then ignore exceptions
+		if ( (LLAvatarNameCache::get(idAgents[idxAgent], &avName)) && ((fClearMatches) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgents[idxAgent]))) )
+		{
+			const std::string& strDisplayName = avName.getDisplayName();
+			bool fFilterDisplay = (strDisplayName.length() > 2);
+			const std::string& strLegacyName = avName.getLegacyName();
+			fFilterLegacy &= (strLegacyName.length() > 2);
+			const std::string& strAnonym = (!fClearMatches) ? RlvStrings::getAnonym(avName) : LLStringUtil::null;
+
+			// If the display name is a subset of the legacy name we need to filter that first, otherwise it's the other way around
+			if (boost::icontains(strLegacyName, strDisplayName))
+			{
+				if (fFilterLegacy)
+					boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym);
+				if (fFilterDisplay)
+					boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym);
+			}
+			else
+			{
+				if (fFilterDisplay)
+					boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym);
+				if (fFilterLegacy)
+					boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym);
+			}
+		}
+	}
+}
+
+// Checked: 2012-08-19 (RLVa-1.4.7)
+void RlvUtil::filterScriptQuestions(S32& nQuestions, LLSD& sdPayload)
+{
+	// Check SCRIPT_PERMISSION_ATTACH
+	if ((!gRlvAttachmentLocks.canAttach()) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit & nQuestions))
+	{
+		// Notify the user that we blocked it since they're not allowed to wear any new attachments
+		sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMATTACH;
+		nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit;
+	}
+
+	// Check SCRIPT_PERMISSION_TELEPORT
+	if ((gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit & nQuestions))
+	{
+		// Notify the user that we blocked it since they're not allowed to teleport
+		sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMTELEPORT;
+		nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit;
+	}
+
+	sdPayload["questions"] = nQuestions;
+}
+
+// Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+void RlvUtil::forceTp(const LLVector3d& posDest)
+{
+	m_fForceTp = true;
+	gAgent.teleportViaLocationLookAt(posDest);
+	m_fForceTp = false;
+}
+
+// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+bool RlvUtil::isNearbyAgent(const LLUUID& idAgent)
+{
+	// Sanity check since we call this with notification payloads as well and those strings tend to change from one release to another
+	RLV_ASSERT(idAgent.notNull());
+	if ( (idAgent.notNull()) && (gAgent.getID() != idAgent) )
+	{
+		std::vector<LLUUID> idAgents;
+		LLWorld::getInstance()->getAvatars(&idAgents, NULL);
+
+		for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++)
+			if (idAgents[idxAgent] == idAgent)
+				return true;
+	}
+	return false;
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+bool RlvUtil::isNearbyRegion(const std::string& strRegion)
+{
+	LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList();
+	for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion)
+		if ((*itRegion)->getName() == strRegion)
+			return true;
+	return false;
+}
+
+// Checked: 2011-04-11 (RLVa-1.3.0h) | Modified: RLVa-1.3.0h
+void RlvUtil::notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs)
+{
+	std::string strMsg = RlvStrings::getString(strNotifcation);
+	LLStringUtil::format(strMsg, sdArgs);
+
+	LLSD sdNotify;
+	sdNotify["MESSAGE"] = strMsg;
+	LLNotificationsUtil::add("SystemMessageTip", sdNotify);
+}
+
+// Checked: 2010-11-11 (RLVa-1.2.1g) | Added: RLVa-1.2.1g
+void RlvUtil::notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine)
+{
+	// Don't show the same assertion over and over, or if the user opted out
+	static std::string strAssertPrev, strFilePrev; static int nLinePrev;
+	if ( ((strAssertPrev == strAssert) && (strFile == strFilePrev) && (nLine == nLinePrev)) ||
+		 (!rlvGetSetting<bool>(RLV_SETTING_SHOWASSERTIONFAIL, true)) )
+	{
+		return;
+	}
+
+	strAssertPrev = strAssert;
+	strFilePrev = strFile;
+	nLinePrev = nLine;
+
+	LLSD argsNotify;
+	argsNotify["MESSAGE"] = llformat("RLVa assertion failure: %s (%s - %d)", strAssert.c_str(), strFile.c_str(), nLine);
+	LLNotificationsUtil::add("SystemMessageTip", argsNotify);
+}
+
+// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+void RlvUtil::sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession)
+{
+	// [See process_improved_im()]
+	std::string strFullName;
+	LLAgentUI::buildFullname(strFullName);
+
+	pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName,
+		strMsg, IM_ONLINE, IM_DO_NOT_DISTURB_AUTO_RESPONSE, idSession);
+	gAgent.sendReliableMessage();
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.0.1e
+bool RlvUtil::sendChatReply(S32 nChannel, const std::string& strUTF8Text)
+{
+	if (!isValidReplyChannel(nChannel))
+		return false;
+
+	// Copy/paste from send_chat_from_viewer()
+	gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer);
+	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	gMessageSystem->nextBlockFast(_PREHASH_ChatData);
+	gMessageSystem->addStringFast(_PREHASH_Message, utf8str_truncate(strUTF8Text, MAX_MSG_STR_LEN));
+	gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT);
+	gMessageSystem->addS32("Channel", nChannel);
+	gAgent.sendReliableMessage();
+	add(LLStatViewer::CHAT_COUNT, 1);
+
+	return true;
+}
+
+void RlvUtil::teleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt)
+{
+	if (hRegion)
+	{
+		const LLVector3d posGlobal = from_region_handle(hRegion) + (LLVector3d)posRegion;
+		if (vecLookAt.isExactlyZero())
+			gAgent.teleportViaLocation(posGlobal);
+		else
+			gAgent.teleportViaLocationLookAt(posGlobal, vecLookAt);
+	}
+}
+
+// ============================================================================
+// Generic menu enablers
+//
+
+// Checked: 2015-05-25 (RLVa-1.5.0)
+bool rlvMenuMainToggleVisible(LLUICtrl* pMenuCtrl)
+{
+	LLMenuItemCheckGL* pMenuItem = dynamic_cast<LLMenuItemCheckGL*>(pMenuCtrl);
+	if (pMenuItem)
+	{
+		static std::string strLabel = pMenuItem->getLabel();
+		if (gSavedSettings.getBOOL(RLV_SETTING_MAIN) == rlv_handler_t::isEnabled())
+			pMenuItem->setLabel(strLabel);
+		else
+			pMenuItem->setLabel(strLabel + " " + LLTrans::getString("RLVaPendingRestart"));
+	}
+	return true;
+}
+
+// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b
+void rlvMenuToggleVisible()
+{
+	bool fTopLevel = rlvGetSetting(RLV_SETTING_TOPLEVELMENU, true);
+	bool fRlvEnabled = rlv_handler_t::isEnabled();
+
+	LLMenuGL* pRLVaMenuMain = gMenuBarView->findChildMenuByName("RLVa Main", FALSE);
+	LLMenuGL* pAdvancedMenu = gMenuBarView->findChildMenuByName("Advanced", FALSE);
+	LLMenuGL* pRLVaMenuEmbed = pAdvancedMenu->findChildMenuByName("RLVa Embedded", FALSE);
+
+	gMenuBarView->setItemVisible("RLVa Main", (fRlvEnabled) && (fTopLevel));
+	pAdvancedMenu->setItemVisible("RLVa Embedded", (fRlvEnabled) && (!fTopLevel));
+
+	if ( (rlv_handler_t::isEnabled()) && (pRLVaMenuMain) && (pRLVaMenuEmbed) && 
+		 ( ((fTopLevel) && (1 == pRLVaMenuMain->getItemCount())) || ((!fTopLevel) && (1 == pRLVaMenuEmbed->getItemCount())) ) )
+	{
+		LLMenuGL* pMenuFrom = (fTopLevel) ? pRLVaMenuEmbed : pRLVaMenuMain;
+		LLMenuGL* pMenuTo = (fTopLevel) ? pRLVaMenuMain : pRLVaMenuEmbed;
+		while (LLMenuItemGL* pItem = pMenuFrom->getItem(1))
+		{
+			pMenuFrom->removeChild(pItem);
+			pMenuTo->addChild(pItem);
+			pItem->updateBranchParent(pMenuTo);
+		}
+	}
+}
+
+bool rlvMenuCanShowName()
+{
+  const LLVOAvatar* pAvatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+  return (pAvatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, pAvatar->getID()));
+}
+
+// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+bool rlvMenuEnableIfNot(const LLSD& sdParam)
+{
+	bool fEnable = true;
+	if (rlv_handler_t::isEnabled())
+	{
+		ERlvBehaviour eBhvr = RlvBehaviourDictionary::instance().getBehaviourFromString(sdParam.asString(), RLV_TYPE_ADDREM);
+		fEnable = (eBhvr != RLV_BHVR_UNKNOWN) ? !gRlvHandler.hasBehaviour(eBhvr) : true;
+	}
+	return fEnable;
+}
+
+// ============================================================================
+// Selection functors
+//
+
+// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0
+bool rlvCanDeleteOrReturn(const LLViewerObject* pObj)
+{
+	// Block if: @rez=n restricted and owned by us or a group *or* @unsit=n restricted and being sat on by us
+	return
+		( (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || ((!pObj->permYouOwner()) && (!pObj->permGroupOwner())) ) &&
+		( (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (!isAgentAvatarValid()) || (!pObj->getRootEdit()->isChild(gAgentAvatarp)) );
+}
+
+// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0
+bool rlvCanDeleteOrReturn()
+{
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) )
+	{
+		struct RlvCanDeleteOrReturn : public LLSelectedObjectFunctor
+		{
+			/*virtual*/ bool apply(LLViewerObject* pObj) { return rlvCanDeleteOrReturn(pObj); }
+		} f;
+		LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+		return (hSel.notNull()) && (0 != hSel->getRootObjectCount()) && (hSel->applyToRootObjects(&f, false));
+	}
+	return true;
+}
+
+// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-0.2.0f
+bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode)
+{
+	return (pNode->getObject()) ? gRlvAttachmentLocks.isLockedAttachment(pNode->getObject()->getRootEdit()) : false;
+}
+
+// Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c
+bool RlvSelectIsEditable::apply(LLSelectNode* pNode)
+{
+	const LLViewerObject* pObj = pNode->getObject();
+	return (pObj) && (!RlvActions::canEdit(pObj));
+}
+
+// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
+bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode)
+{
+	return (pNode->getObject()) && (pNode->getObject()->getRootEdit()->isChild(m_pAvatar));
+}
+
+// ============================================================================
+// Predicates
+//
+
+// Checked: 2010-11-11 (RLVa-1.2.1g) | Modified: RLVa-1.2.1g
+bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask)
+{
+	if ( (pItem) && (RlvForceWear::isWearableItem(pItem)) )
+	{
+		if (RlvForceWear::isWearingItem(pItem))
+			return true; // Special exception for currently worn items
+		switch (pItem->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+				// NOTE: only one body part of each type is allowed so the only way to wear one is if we can replace the current one
+				return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & RLV_WEAR_REPLACE & eWearMask));
+			case LLAssetType::AT_CLOTHING:
+				return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & eWearMask));
+			case LLAssetType::AT_OBJECT:
+				return (RLV_WEAR_LOCKED != (gRlvAttachmentLocks.canAttach(pItem) & eWearMask));
+			case LLAssetType::AT_GESTURE:
+				return true;
+			default:
+				RLV_ASSERT(false);
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask)
+{
+	return !rlvPredCanWearItem(pItem, eWearMask);
+}
+
+// Checked: 2014-11-02 (RLVa-1.4.11)
+bool rlvPredCanRemoveItem(const LLUUID& idItem)
+{
+	// Check the inventory item if it's available
+	const LLViewerInventoryItem* pItem = gInventory.getItem(idItem);
+	if (pItem)
+	{
+		return rlvPredCanRemoveItem(pItem);
+	}
+
+	// Temporary attachments don't have inventory items associated with them so check the attachment itself
+	if (isAgentAvatarValid())
+	{
+		const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(idItem);
+		return (pAttachObj) && (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj));
+	}
+
+	return false;
+}
+
+// Checked: 2010-03-22 (RLVa-1.2.0)
+bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem)
+{
+	if (pItem)
+	{
+		switch (pItem->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+			case LLAssetType::AT_CLOTHING:
+				return gRlvWearableLocks.canRemove(pItem);
+			case LLAssetType::AT_OBJECT:
+				return gRlvAttachmentLocks.canDetach(pItem);
+			case LLAssetType::AT_GESTURE:
+				return true;
+			default:
+				RLV_ASSERT(!RlvForceWear::isWearableItem(pItem));
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem)
+{
+	return !rlvPredCanRemoveItem(pItem);
+}
+
+// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+RlvPredIsEqualOrLinkedItem::RlvPredIsEqualOrLinkedItem(const LLUUID& idItem)
+{
+	m_pItem = gInventory.getItem(idItem);
+}
+
+// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+bool RlvPredIsEqualOrLinkedItem::operator()(const LLViewerInventoryItem* pItem) const
+{
+	return (m_pItem) && (pItem) && (m_pItem->getLinkedUUID() == pItem->getLinkedUUID());
+}
+
+// ============================================================================
+// Various public helper functions
+//
+
+// Checked: 2009-11-15 (RLVa-1.1.0c) | Added: RLVa-1.1.0c
+/*
+BOOL rlvEnableSharedWearEnabler(void* pParam)
+{
+	return false;
+	// Visually disable the "Enable Shared Wear" option when at least one attachment is non-detachable
+	return (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE));
+}
+*/
+
+// Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+const std::string& rlvGetAnonym(const LLAvatarName& avName)
+{
+	return RlvStrings::getAnonym(avName);
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h
new file mode 100644
index 0000000000000000000000000000000000000000..5f3811873455b94047d3f19e048f504b74182cef
--- /dev/null
+++ b/indra/newview/rlvcommon.h
@@ -0,0 +1,330 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_COMMON_H
+#define RLV_COMMON_H
+
+#include "llavatarname.h"
+#include "llselectmgr.h"
+#include "llviewercontrol.h"
+
+#include "rlvdefines.h"
+
+#ifdef LL_WINDOWS
+	#pragma warning (push)
+	#pragma warning (disable : 4702) // warning C4702: unreachable code
+#endif
+#include <boost/variant.hpp>
+#ifdef LL_WINDOWS
+	#pragma warning (pop)
+#endif
+
+// ============================================================================
+// Forward declarations
+//
+
+//
+// General viewer source
+//
+class LLInventoryItem;
+class LLUICtrl;
+class LLViewerInventoryCategory;
+class LLViewerInventoryItem;
+class LLViewerJointAttachment;
+class LLViewerWearable;
+class LLWearable;
+
+//
+// RLVa-specific
+//
+class RlvCommand;
+typedef std::list<RlvCommand> rlv_command_list_t;
+class RlvObject;
+
+struct RlvException;
+typedef boost::variant<std::string, LLUUID, S32, ERlvBehaviour> RlvExceptionOption;
+typedef boost::variant<int, float, LLVector3, LLUUID> RlvBehaviourModifierValue;
+
+class RlvGCTimer;
+
+// ============================================================================
+// RlvSettings
+//
+
+template<typename T> inline T rlvGetSetting(const std::string& strSetting, const T& defaultValue)
+{
+	RLV_ASSERT_DBG(gSavedSettings.controlExists(strSetting));
+	return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.get<T>(strSetting) : defaultValue;
+}
+
+template<typename T> inline T rlvGetPerUserSetting(const std::string& strSetting, const T& defaultValue)
+{
+	RLV_ASSERT_DBG(gSavedPerAccountSettings.controlExists(strSetting));
+	return (gSavedPerAccountSettings.controlExists(strSetting)) ? gSavedPerAccountSettings.get<T>(strSetting) : defaultValue;
+}
+
+class RlvSettings
+{
+public:
+	static bool getDebug()						{ return rlvGetSetting<bool>(RLV_SETTING_DEBUG, false); }
+	static bool getCanOOC()						{ return s_fCanOOC; }
+	static bool getForbidGiveToRLV()			{ return rlvGetSetting<bool>(RLV_SETTING_FORBIDGIVETORLV, true); }
+	static bool getNoSetEnv()					{ return s_fNoSetEnv; }
+
+	static std::string getWearAddPrefix()		{ return rlvGetSetting<std::string>(RLV_SETTING_WEARADDPREFIX, LLStringUtil::null); }
+	static std::string getWearReplacePrefix()	{ return rlvGetSetting<std::string>(RLV_SETTING_WEARREPLACEPREFIX, LLStringUtil::null); }
+
+	static bool getDebugHideUnsetDup()			{ return rlvGetSetting<bool>(RLV_SETTING_DEBUGHIDEUNSETDUP, false); }
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	static BOOL getEnableComposites()			{ return s_fCompositeFolders; }
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	static bool getEnableIMQuery()              { return rlvGetSetting<bool>("RLVaEnableIMQuery", true); }
+	static bool getEnableLegacyNaming()			{ return s_fLegacyNaming; }
+	static bool getEnableSharedWear()			{ return rlvGetSetting<bool>(RLV_SETTING_ENABLESHAREDWEAR, false); }
+	static bool getEnableTemporaryAttachments() { return s_fTempAttach; }
+	static bool getHideLockedLayers()			{ return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDLAYER, false); }
+	static bool getHideLockedAttach()			{ return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDATTACH, false); }
+	static bool getHideLockedInventory()		{ return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDINVENTORY, false); }
+	static bool getSharedInvAutoRename()		{ return rlvGetSetting<bool>(RLV_SETTING_SHAREDINVAUTORENAME, true); }
+
+	static bool getLoginLastLocation()			{ return rlvGetPerUserSetting<bool>(RLV_SETTING_LOGINLASTLOCATION, true); }
+	static void updateLoginLastLocation();
+
+	static void initCompatibilityMode(std::string strCompatList);
+	static bool isCompatibilityModeObject(const LLUUID& idRlvObject);
+
+	static void initClass();
+	static void onChangedSettingMain(const LLSD& sdValue);
+protected:
+	static bool onChangedMenuLevel();
+	static bool onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting);
+
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	static BOOL s_fCompositeFolders;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	/*
+	 * Member variables
+	 */
+protected:
+	static bool s_fCanOOC;
+	static bool s_fLegacyNaming;
+	static bool s_fNoSetEnv;
+	static bool s_fTempAttach;
+	static std::list<LLUUID>      s_CompatItemCreators;
+	static std::list<std::string> s_CompatItemNames;
+};
+
+// ============================================================================
+// RlvStrings
+//
+
+class RlvStrings
+{
+public:
+	static void initClass();
+	static void loadFromFile(const std::string& strFilePath, bool fDefault);
+	static void saveToFile(const std::string& strFilePath);
+
+	static const std::string& getAnonym(const LLAvatarName& avName);		// @shownames
+	static const std::string& getAnonym(const std::string& strName);		// @shownames
+	static const std::string& getString(const std::string& strStringName);
+	static const char*        getStringFromReturnCode(ERlvCmdRet eRet);
+	static const std::string& getStringMapPath() { return m_StringMapPath; }
+	static std::string        getVersion(const LLUUID& idRlvObject, bool fLegacy = false);
+	static std::string        getVersionAbout();
+	static std::string        getVersionNum(const LLUUID& idRlvObject);
+	static bool               hasString(const std::string& strStringName, bool fCheckCustom = false);
+	static void               setCustomString(const std::string& strStringName, const std::string& strStringValue);
+
+protected:
+	static std::vector<std::string> m_Anonyms;
+	typedef std::map<std::string, std::list<std::string> > string_map_t;
+	static string_map_t m_StringMap;
+	static std::string  m_StringMapPath;
+};
+
+// ============================================================================
+// RlvUtil - Collection of (static) helper functions
+//
+
+class RlvUtil
+{
+public:
+	static bool isEmote(const std::string& strUTF8Text);
+	static bool isNearbyAgent(const LLUUID& idAgent);								// @shownames
+	static bool isNearbyRegion(const std::string& strRegion);						// @showloc
+
+	static void filterLocation(std::string& strUTF8Text);							// @showloc
+	static void filterNames(std::string& strUTF8Text, bool fFilterLegacy = true, bool fClearMatches = false);	// @shownames
+	static void filterScriptQuestions(S32& nQuestions, LLSD& sdPayload); 
+
+	static bool isForceTp()	{ return m_fForceTp; }
+	static void forceTp(const LLVector3d& posDest);									// Ignores restrictions that might otherwise prevent tp'ing
+
+	static void notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs = LLSD());
+	static void notifyBlockedGeneric()	{ notifyBlocked(RLV_STRING_BLOCKED_GENERIC); }
+	static void notifyBlockedViewXXX(LLAssetType::EType assetType) { notifyBlocked(RLV_STRING_BLOCKED_VIEWXXX, LLSD().with("[TYPE]", LLAssetType::lookup(assetType))); }
+	static void notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine);
+
+	static void sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession = LLUUID::null);
+	static bool isValidReplyChannel(S32 nChannel, bool fLoopback = false);
+	static bool sendChatReply(S32 nChannel, const std::string& strUTF8Text);
+	static bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text);
+
+	static void teleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt);
+protected:
+	static bool m_fForceTp;															// @standtp
+};
+
+// ============================================================================
+// Extensibility classes
+//
+
+class RlvExtCommandHandler
+{
+public:
+	virtual ~RlvExtCommandHandler() {}
+	virtual bool onAddRemCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; }
+	virtual bool onClearCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)  { return false; }
+	virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)  { return false; }
+	virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)  { return false; }
+};
+typedef bool (RlvExtCommandHandler::*rlvExtCommandHandler)(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet);
+
+// ============================================================================
+// Generic menu enablers
+//
+
+bool rlvMenuMainToggleVisible(LLUICtrl* pMenuItem);
+void rlvMenuToggleVisible();
+bool rlvMenuCanShowName();
+bool rlvMenuEnableIfNot(const LLSD& sdParam);
+
+// ============================================================================
+// Selection functors
+//
+
+bool rlvCanDeleteOrReturn();
+bool rlvCanDeleteOrReturn(const LLViewerObject* pObj);
+
+struct RlvSelectHasLockedAttach : public LLSelectedNodeFunctor
+{
+	RlvSelectHasLockedAttach() {}
+	virtual bool apply(LLSelectNode* pNode);
+};
+
+// Filters out selected objects that can't be editable (i.e. getFirstNode() will return NULL if the selection is fully editable)
+struct RlvSelectIsEditable : public LLSelectedNodeFunctor
+{
+	RlvSelectIsEditable() {}
+	/*virtual*/ bool apply(LLSelectNode* pNode);
+};
+
+struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor
+{
+	RlvSelectIsSittingOn(const LLVOAvatar* pAvatar) : m_pAvatar(pAvatar) {}
+	/*virtual*/ bool apply(LLSelectNode* pNode);
+protected:
+	const LLVOAvatar* m_pAvatar;
+};
+
+// ============================================================================
+// Predicates
+//
+
+bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask);
+bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask);
+bool rlvPredCanRemoveItem(const LLUUID& idItem);
+bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem);
+bool rlvPredCanNotRemoveItem(const LLUUID& idItem);
+bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem);
+
+struct RlvPredCanWearItem
+{
+	RlvPredCanWearItem(ERlvWearMask eWearMask) : m_eWearMask(eWearMask) {}
+	bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanWearItem(pItem, m_eWearMask); }
+protected:
+	ERlvWearMask m_eWearMask;
+};
+
+struct RlvPredCanNotWearItem
+{
+	RlvPredCanNotWearItem(ERlvWearMask eWearMask) : m_eWearMask(eWearMask) {}
+	bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanNotWearItem(pItem, m_eWearMask); }
+protected:
+	ERlvWearMask m_eWearMask;
+};
+
+struct RlvPredCanRemoveItem
+{
+	RlvPredCanRemoveItem() {}
+	bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanRemoveItem(pItem); }
+};
+
+struct RlvPredCanNotRemoveItem
+{
+	RlvPredCanNotRemoveItem() {}
+	bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanNotRemoveItem(pItem); }
+};
+
+struct RlvPredIsEqualOrLinkedItem
+{
+	RlvPredIsEqualOrLinkedItem(const LLViewerInventoryItem* pItem) : m_pItem(pItem) {}
+	RlvPredIsEqualOrLinkedItem(const LLUUID& idItem);
+	bool operator()(const LLViewerInventoryItem* pItem) const;
+protected:
+	const LLViewerInventoryItem* m_pItem;
+};
+
+template<typename T> struct RlvPredValuesEqual
+{
+	bool operator()(const T* pT2) const { return (pT1) && (pT2) && (*pT1 == *pT2); }
+	const T* pT1;
+};
+
+// ============================================================================
+// Inlined class member functions
+//
+
+// Checked: 2010-10-31 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+inline const std::string& RlvStrings::getAnonym(const LLAvatarName& avName)
+{
+	return getAnonym(avName.getDisplayName());
+}
+
+// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.2a
+inline bool RlvUtil::isEmote(const std::string& strUTF8Text)
+{
+	return (strUTF8Text.length() > 4) && ( (strUTF8Text.compare(0, 4, "/me ") == 0) || (strUTF8Text.compare(0, 4, "/me'") == 0) );
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0b) | Added: RLVa-1.0.2a
+inline bool RlvUtil::isValidReplyChannel(S32 nChannel, bool fLoopback /*=false*/)
+{
+	return (nChannel > ((!fLoopback) ? 0 : -1)) && (CHAT_CHANNEL_DEBUG != nChannel);
+}
+
+// Checked: 2009-08-05 (RLVa-1.0.1e) | Added: RLVa-1.0.0e
+inline bool RlvUtil::sendChatReply(const std::string& strChannel, const std::string& strUTF8Text)
+{
+	S32 nChannel;
+	return (LLStringUtil::convertToS32(strChannel, nChannel)) ? sendChatReply(nChannel, strUTF8Text) : false;
+}
+
+// ============================================================================
+
+#endif // RLV_COMMON_H
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c150b9136ffb089b53645697de15caf5847e4a7
--- /dev/null
+++ b/indra/newview/rlvdefines.h
@@ -0,0 +1,392 @@
+/**
+ *
+ * Copyright (c) 2009-2016, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ *
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to
+ * abide by those obligations.
+ *
+ */
+
+#ifndef RLV_DEFINES_H
+#define RLV_DEFINES_H
+
+// ============================================================================
+// Defines
+//
+
+// Version of the specifcation we report
+const S32 RLV_VERSION_MAJOR = 3;
+const S32 RLV_VERSION_MINOR = 1;
+const S32 RLV_VERSION_PATCH = 4;
+const S32 RLV_VERSION_BUILD = 0;
+
+// Version of the specifcation we report (in compatibility mode)
+const S32 RLV_VERSION_MAJOR_COMPAT = 2;
+const S32 RLV_VERSION_MINOR_COMPAT = 8;
+const S32 RLV_VERSION_PATCH_COMPAT = 0;
+const S32 RLV_VERSION_BUILD_COMPAT = 0;
+
+// Implementation version
+const S32 RLVa_VERSION_MAJOR = 2;
+const S32 RLVa_VERSION_MINOR = 0;
+const S32 RLVa_VERSION_PATCH = 3;
+
+// Uncomment before a final release
+//#define RLV_RELEASE
+
+// Defining these makes it easier if we ever need to change our tag
+#define RLV_WARNS		LL_WARNS("RLV")
+#define RLV_INFOS		LL_INFOS("RLV")
+#define RLV_DEBUGS		LL_DEBUGS("RLV")
+#define RLV_ENDL		LL_ENDL
+#define RLV_VERIFY(f)	if (!(f)) { RlvUtil::notifyFailedAssertion(#f, __FILE__, __LINE__); }
+
+#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+	// Turn on extended debugging information
+	#define RLV_DEBUG
+	// Make sure we halt execution on errors
+	#define RLV_ERRS				LL_ERRS("RLV")
+	// Keep our asserts separate from LL's
+	#define RLV_ASSERT(f)			if (!(f)) { RLV_ERRS << "ASSERT (" << #f << ")" << RLV_ENDL; }
+	#define RLV_ASSERT_DBG(f)		RLV_ASSERT(f)
+#else
+	// Don't halt execution on errors in release
+	#define RLV_ERRS				LL_WARNS("RLV")
+	// We don't want to check assertions in release builds
+	#ifndef RLV_RELEASE
+		#define RLV_ASSERT(f)		RLV_VERIFY(f)
+		#define RLV_ASSERT_DBG(f)
+	#else
+		#define RLV_ASSERT(f)
+		#define RLV_ASSERT_DBG(f)
+	#endif // RLV_RELEASE
+#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+
+#define RLV_ROOT_FOLDER					"#RLV"
+#define RLV_CMD_PREFIX					'@'
+#define RLV_MODIFIER_TPLOCAL_DEFAULT    256.f			// Any teleport that's more than a region away is non-local
+#define RLV_MODIFIER_FARTOUCH_DEFAULT   1.5f			// Specifies the default @fartouch distance
+#define RLV_MODIFIER_SITTP_DEFAULT      1.5f			// Specifies the default @sittp distance
+#define RLV_OPTION_SEPARATOR			";"				// Default separator used in command options
+#define RLV_PUTINV_PREFIX				"#RLV/~"
+#define RLV_PUTINV_SEPARATOR			"/"
+#define RLV_PUTINV_MAXDEPTH				4
+#define RLV_SETROT_OFFSET				F_PI_BY_TWO		// @setrot is off by 90 degrees with the rest of SL
+#define RLV_STRINGS_FILE				"rlva_strings.xml"
+
+#define RLV_FOLDER_FLAG_NOSTRIP			"nostrip"
+#define RLV_FOLDER_PREFIX_HIDDEN		'.'
+#define RLV_FOLDER_PREFIX_PUTINV    	'~'
+
+// ============================================================================
+// Enumeration declarations
+//
+
+// NOTE: any changes to this enumeration should be reflected in the RlvBehaviourDictionary constructor
+enum ERlvBehaviour {
+	RLV_BHVR_DETACH = 0,			// "detach"
+	RLV_BHVR_ADDATTACH,				// "addattach"
+	RLV_BHVR_REMATTACH,				// "remattach"
+	RLV_BHVR_ADDOUTFIT,				// "addoutfit"
+	RLV_BHVR_REMOUTFIT,				// "remoutfit"
+	RLV_BHVR_SHAREDWEAR,			// "sharedwear"
+	RLV_BHVR_SHAREDUNWEAR,			// "sharedunwear"
+	RLV_BHVR_UNSHAREDWEAR,			// "unsharedwear"
+	RLV_BHVR_UNSHAREDUNWEAR,		// "unsharedunwear"
+	RLV_BHVR_EMOTE,					// "emote"
+	RLV_BHVR_SENDCHAT,				// "sendchat"
+	RLV_BHVR_RECVCHAT,				// "recvchat"
+	RLV_BHVR_RECVCHATFROM,			// "recvchatfrom"
+	RLV_BHVR_RECVEMOTE,				// "recvemote"
+	RLV_BHVR_RECVEMOTEFROM,			// "recvemotefrom"
+	RLV_BHVR_REDIRCHAT,				// "redirchat"
+	RLV_BHVR_REDIREMOTE,			// "rediremote"
+	RLV_BHVR_CHATWHISPER,			// "chatwhisper"
+	RLV_BHVR_CHATNORMAL,			// "chatnormal"
+	RLV_BHVR_CHATSHOUT,				// "chatshout"
+	RLV_BHVR_SENDCHANNEL,
+	RLV_BHVR_SENDCHANNELEXCEPT,
+	RLV_BHVR_SENDIM,				// "sendim"
+	RLV_BHVR_SENDIMTO,				// "sendimto"
+	RLV_BHVR_RECVIM,				// "recvim"
+	RLV_BHVR_RECVIMFROM,			// "recvimfrom"
+	RLV_BHVR_STARTIM,				// "startim"
+	RLV_BHVR_STARTIMTO,				// "startimto"
+	RLV_BHVR_SENDGESTURE,
+	RLV_BHVR_PERMISSIVE,			// "permissive"
+	RLV_BHVR_NOTIFY,				// "notify"
+	RLV_BHVR_SHOWINV,				// "showinv"
+	RLV_BHVR_SHOWMINIMAP,			// "showminimap"
+	RLV_BHVR_SHOWWORLDMAP,			// "showworldmap"
+	RLV_BHVR_SHOWLOC,				// "showloc"
+	RLV_BHVR_SHOWNAMES,				// "shownames"
+	RLV_BHVR_SHOWNAMETAGS,			// "shownametags"
+	RLV_BHVR_SHOWNEARBY,
+	RLV_BHVR_SHOWHOVERTEXT,			// "showhovertext"
+	RLV_BHVR_SHOWHOVERTEXTHUD,		// "showhovertexthud"
+	RLV_BHVR_SHOWHOVERTEXTWORLD,	// "showhovertextworld"
+	RLV_BHVR_SHOWHOVERTEXTALL,		// "showhovertextall"
+	RLV_BHVR_SHOWSELF,
+	RLV_BHVR_SHOWSELFHEAD,
+	RLV_BHVR_TPLM,					// "tplm"
+	RLV_BHVR_TPLOC,					// "tploc"
+	RLV_BHVR_TPLOCAL,
+	RLV_BHVR_TPLURE,				// "tplure"
+	RLV_BHVR_TPREQUEST,				// "tprequest"
+	RLV_BHVR_VIEWNOTE,				// "viewnote"
+	RLV_BHVR_VIEWSCRIPT,			// "viewscript"
+	RLV_BHVR_VIEWTEXTURE,			// "viewtexture"
+	RLV_BHVR_ACCEPTPERMISSION,		// "acceptpermission"
+	RLV_BHVR_ACCEPTTP,				// "accepttp"
+	RLV_BHVR_ACCEPTTPREQUEST,		// "accepttprequest"
+	RLV_BHVR_ALLOWIDLE,				// "allowidle"
+	RLV_BHVR_EDIT,					// "edit"
+	RLV_BHVR_EDITOBJ,				// "editobj"
+	RLV_BHVR_REZ,					// "rez"
+	RLV_BHVR_FARTOUCH,				// "fartouch"
+	RLV_BHVR_INTERACT,				// "interact"
+	RLV_BHVR_TOUCHTHIS,				// "touchthis"
+	RLV_BHVR_TOUCHATTACH,			// "touchattach"
+	RLV_BHVR_TOUCHATTACHSELF,		// "touchattachself"
+	RLV_BHVR_TOUCHATTACHOTHER,		// "touchattachother"
+	RLV_BHVR_TOUCHHUD,				// "touchhud"
+	RLV_BHVR_TOUCHWORLD,			// "touchworld"
+	RLV_BHVR_TOUCHALL,				// "touchall"
+	RLV_BHVR_TOUCHME,				// "touchme"
+	RLV_BHVR_FLY,					// "fly"
+	RLV_BHVR_SETGROUP,				// "setgroup"
+	RLV_BHVR_UNSIT,					// "unsit"
+	RLV_BHVR_SIT,					// "sit"
+	RLV_BHVR_SITTP,					// "sittp"
+	RLV_BHVR_STANDTP,				// "standtp"
+	RLV_BHVR_SETDEBUG,				// "setdebug"
+	RLV_BHVR_SETENV,				// "setenv"
+	RLV_BHVR_ALWAYSRUN,				// "alwaysrun"
+	RLV_BHVR_TEMPRUN,				// "temprun"
+	RLV_BHVR_DETACHME,				// "detachme"
+	RLV_BHVR_ATTACHTHIS,			// "attachthis"
+	RLV_BHVR_ATTACHTHISEXCEPT,		// "attachthis_except"
+	RLV_BHVR_DETACHTHIS,			// "detachthis"
+	RLV_BHVR_DETACHTHISEXCEPT,		// "detachthis_except"
+	RLV_BHVR_ADJUSTHEIGHT,			// "adjustheight"
+	RLV_BHVR_TPTO,					// "tpto"
+	RLV_BHVR_VERSION,				// "version"
+	RLV_BHVR_VERSIONNEW,			// "versionnew"
+	RLV_BHVR_VERSIONNUM,			// "versionnum"
+	RLV_BHVR_GETATTACH,				// "getattach"
+	RLV_BHVR_GETATTACHNAMES,		// "getattachnames"
+	RLV_BHVR_GETADDATTACHNAMES,		// "getaddattachnames"
+	RLV_BHVR_GETREMATTACHNAMES,		// "getremattachnames"
+	RLV_BHVR_GETOUTFIT,				// "getoutfit"
+	RLV_BHVR_GETOUTFITNAMES,		// "getoutfitnames"
+	RLV_BHVR_GETADDOUTFITNAMES,		// "getaddoutfitnames"
+	RLV_BHVR_GETREMOUTFITNAMES,		// "getremoutfitnames"
+	RLV_BHVR_FINDFOLDER,			// "findfolder"
+	RLV_BHVR_FINDFOLDERS,			// "findfolders"
+	RLV_BHVR_GETPATH,				// "getpath"
+	RLV_BHVR_GETPATHNEW,			// "getpathnew"
+	RLV_BHVR_GETINV,				// "getinv"
+	RLV_BHVR_GETINVWORN,			// "getinvworn"
+	RLV_BHVR_GETGROUP,				// "getgroup"
+	RLV_BHVR_GETSITID,				// "getsitid"
+	RLV_BHVR_GETCOMMAND,			// "getcommand"
+	RLV_BHVR_GETSTATUS,				// "getstatus"
+	RLV_BHVR_GETSTATUSALL,			// "getstatusall"
+	RLV_CMD_FORCEWEAR,				// Internal representation of all force wear commands
+
+	// Camera (behaviours)
+	RLV_BHVR_SETCAM,                // Gives an object exclusive control of the user's camera
+	RLV_BHVR_SETCAM_AVDISTMIN,		// Enforces a minimum distance from the avatar (in m)
+	RLV_BHVR_SETCAM_AVDISTMAX,		// Enforces a maximum distance from the avatar (in m)
+	RLV_BHVR_SETCAM_ORIGINDISTMIN,	// Enforces a minimum distance from the camera origin (in m)
+	RLV_BHVR_SETCAM_ORIGINDISTMAX,	// Enforces a maximum distance from the camera origin (in m)
+	RLV_BHVR_SETCAM_EYEOFFSET,      // Changes the default camera offset
+	RLV_BHVR_SETCAM_FOCUSOFFSET,    // Changes the default camera focus offset
+	RLV_BHVR_SETCAM_FOCUS,			// Forces the camera focus and/or position to a specific object, avatar or position
+	RLV_BHVR_SETCAM_FOV,			// Changes the current - vertical - field of view
+	RLV_BHVR_SETCAM_FOVMIN,			// Enforces a minimum - vertical - FOV (in degrees)
+	RLV_BHVR_SETCAM_FOVMAX,			// Enforces a maximum - vertical - FOV (in degrees)
+	RLV_BHVR_SETCAM_MOUSELOOK,		// Prevent the user from going into mouselook
+	RLV_BHVR_SETCAM_TEXTURES,		// Replaces all textures with the specified texture (or the default unrezzed one)
+	RLV_BHVR_SETCAM_UNLOCK,			// Forces the camera focus to the user's avatar
+	// Camera (behaviours - deprecated)
+	RLV_BHVR_CAMZOOMMIN,			// Enforces a minimum - vertical - FOV angle of 60° / multiplier
+	RLV_BHVR_CAMZOOMMAX,			// Enforces a maximum - vertical - FOV angle of 60° / multiplier
+	// Camera (reply)
+	RLV_BHVR_GETCAM_AVDIST,			// Returns the current minimum distance between the camera and the user's avatar
+	RLV_BHVR_GETCAM_AVDISTMIN,		// Returns the active (if any) minimum distance between the camera and the user's avatar
+	RLV_BHVR_GETCAM_AVDISTMAX,		// Returns the active (if any) maxmimum distance between the camera and the user's avatar
+	RLV_BHVR_GETCAM_FOV,			// Returns the current field of view angle (in radians)
+	RLV_BHVR_GETCAM_FOVMIN,			// Returns the active (if any) minimum field of view angle (in radians)
+	RLV_BHVR_GETCAM_FOVMAX,			// Enforces a maximum (if any) maximum field of view angle (in radians)
+	RLV_BHVR_GETCAM_TEXTURES,		// Returns the active (if any) replace texture UUID
+	// Camera (force)
+	RLV_BHVR_SETCAM_MODE,			// Switch the user's camera into the specified mode (e.g. mouselook or thirdview)
+
+	RLV_BHVR_COUNT,
+	RLV_BHVR_UNKNOWN
+};
+
+enum ERlvBehaviourModifier
+{
+	RLV_MODIFIER_FARTOUCHDIST,			// Radius of a sphere around the user in which they can interact with the world
+	RLV_MODIFIER_RECVIMDISTMIN,			// Minimum distance to receive an IM from an otherwise restricted sender (squared value)
+	RLV_MODIFIER_RECVIMDISTMAX,			// Maximum distance to receive an IM from an otherwise restricted sender (squared value)
+	RLV_MODIFIER_SENDIMDISTMIN,			// Minimum distance to send an IM to an otherwise restricted recipient (squared value)
+	RLV_MODIFIER_SENDIMDISTMAX,			// Maximum distance to send an IM to an otherwise restricted recipient (squared value)
+	RLV_MODIFIER_STARTIMDISTMIN,		// Minimum distance to start an IM to an otherwise restricted recipient (squared value)
+	RLV_MODIFIER_STARTIMDISTMAX,		// Maximum distance to start an IM to an otherwise restricted recipient (squared value)
+	RLV_MODIFIER_SETCAM_AVDISTMIN,		// Minimum distance between the camera position and the user's avatar (normal value)
+	RLV_MODIFIER_SETCAM_AVDISTMAX,		// Maximum distance between the camera position and the user's avatar (normal value)
+	RLV_MODIFIER_SETCAM_ORIGINDISTMIN,	// Minimum distance between the camera position and the origin point (normal value)
+	RLV_MODIFIER_SETCAM_ORIGINDISTMAX,	// Maximum distance between the camera position and the origin point (normal value)
+	RLV_MODIFIER_SETCAM_EYEOFFSET,		// Specifies the default camera's offset from the camera (vector)
+	RLV_MODIFIER_SETCAM_FOCUSOFFSET,	// Specifies the default camera's focus (vector)
+	RLV_MODIFIER_SETCAM_FOVMIN,			// Minimum value for the camera's field of view (angle in radians)
+	RLV_MODIFIER_SETCAM_FOVMAX,			// Maximum value for the camera's field of view (angle in radians)
+	RLV_MODIFIER_SETCAM_TEXTURE,		// Specifies the UUID of the texture used to texture the world view
+	RLV_MODIFIER_SITTPDIST,
+	RLV_MODIFIER_TPLOCALDIST,
+
+	RLV_MODIFIER_COUNT,
+	RLV_MODIFIER_UNKNOWN
+};
+
+enum ERlvBehaviourOptionType
+{
+	RLV_OPTION_NONE,				// Behaviour takes no parameters
+	RLV_OPTION_EXCEPTION,			// Behaviour requires an exception as a parameter
+	RLV_OPTION_NONE_OR_EXCEPTION,	// Behaviour takes either no parameters or an exception
+	RLV_OPTION_MODIFIER,			// Behaviour requires a modifier as a parameter
+	RLV_OPTION_NONE_OR_MODIFIER		// Behaviour takes either no parameters or a modifier
+};
+
+enum ERlvParamType {
+	RLV_TYPE_UNKNOWN = 0x00,
+	RLV_TYPE_ADD     = 0x01,		// <param> == "n"|"add"
+	RLV_TYPE_REMOVE  = 0x02,		// <param> == "y"|"rem"
+	RLV_TYPE_FORCE   = 0x04,		// <param> == "force"
+	RLV_TYPE_REPLY   = 0x08,		// <param> == <number>
+	RLV_TYPE_CLEAR   = 0x10,
+	RLV_TYPE_ADDREM  = RLV_TYPE_ADD | RLV_TYPE_REMOVE
+};
+
+enum ERlvCmdRet {
+	RLV_RET_UNKNOWN		= 0x0000,	// Unknown error (should only be used internally)
+	RLV_RET_RETAINED,				// Command was retained
+	RLV_RET_SUCCESS		= 0x0100,	// Command executed succesfully
+	RLV_RET_SUCCESS_UNSET,			// Command executed succesfully (RLV_TYPE_REMOVE for an unrestricted behaviour)
+	RLV_RET_SUCCESS_DUPLICATE,		// Command executed succesfully (RLV_TYPE_ADD for an already restricted behaviour)
+	RLV_RET_SUCCESS_DEPRECATED,		// Command executed succesfully but has been marked as deprecated
+	RLV_RET_SUCCESS_DELAYED,		// Command parsed valid but will execute at a later time
+	RLV_RET_FAILED		= 0x0200,	// Command failed (general failure)
+	RLV_RET_FAILED_SYNTAX,			// Command failed (syntax error)
+	RLV_RET_FAILED_OPTION,			// Command failed (invalid option)
+	RLV_RET_FAILED_PARAM,			// Command failed (invalid param)
+	RLV_RET_FAILED_LOCK,			// Command failed (command is locked by another object)
+	RLV_RET_FAILED_DISABLED,		// Command failed (command disabled by user)
+	RLV_RET_FAILED_UNKNOWN,			// Command failed (unknown command)
+	RLV_RET_FAILED_NOSHAREDROOT,	// Command failed (missing #RLV)
+	RLV_RET_FAILED_DEPRECATED,		// Command failed (deprecated and no longer supported)
+	RLV_RET_NO_PROCESSOR			// Command doesn't have a template processor define (legacy code)
+};
+#define RLV_RET_SUCCEEDED(eCmdRet)  (((eCmdRet) & RLV_RET_SUCCESS) == RLV_RET_SUCCESS)
+
+enum ERlvExceptionCheck
+{
+	RLV_CHECK_PERMISSIVE,			// Exception can be set by any object
+	RLV_CHECK_STRICT,				// Exception must be set by all objects holding the restriction
+	RLV_CHECK_DEFAULT				// Permissive or strict will be determined by currently enforced restrictions
+};
+
+enum ERlvLockMask
+{
+	RLV_LOCK_NONE   = 0x00,
+	RLV_LOCK_ADD    = 0x01,
+	RLV_LOCK_REMOVE = 0x02,
+	RLV_LOCK_ANY    = RLV_LOCK_ADD | RLV_LOCK_REMOVE
+};
+
+enum ERlvWearMask
+{
+	RLV_WEAR_LOCKED	 = 0x00,		// User can not wear the item at all
+	RLV_WEAR_ADD	 = 0x01,		// User can wear the item in addition to what's already worn
+	RLV_WEAR_REPLACE = 0x02,		// User can wear the item and replace what's currently worn
+	RLV_WEAR		 = 0x03			// Convenience: combines RLV_WEAR_ADD and RLV_WEAR_REPLACE
+};
+
+enum ERlvAttachGroupType
+{
+	RLV_ATTACHGROUP_HEAD = 0,
+	RLV_ATTACHGROUP_TORSO,
+	RLV_ATTACHGROUP_ARMS,
+	RLV_ATTACHGROUP_LEGS,
+	RLV_ATTACHGROUP_HUD,
+	RLV_ATTACHGROUP_COUNT,
+	RLV_ATTACHGROUP_INVALID
+};
+
+// ============================================================================
+// Settings
+//
+
+#define RLV_SETTING_MAIN				"RestrainedLove"
+#define RLV_SETTING_DEBUG				"RestrainedLoveDebug"
+#define RLV_SETTING_CANOOC				"RestrainedLoveCanOOC"
+#define RLV_SETTING_FORBIDGIVETORLV		"RestrainedLoveForbidGiveToRLV"
+#define RLV_SETTING_NOSETENV			"RestrainedLoveNoSetEnv"
+#define RLV_SETTING_SHOWELLIPSIS		"RestrainedLoveShowEllipsis"
+#define RLV_SETTING_WEARADDPREFIX       "RestrainedLoveStackWhenFolderBeginsWith"
+#define RLV_SETTING_WEARREPLACEPREFIX   "RestrainedLoveReplaceWhenFolderBeginsWith"
+
+#define RLV_SETTING_DEBUGHIDEUNSETDUP   "RLVaDebugHideUnsetDuplicate"
+#define RLV_SETTING_ENABLECOMPOSITES	"RLVaEnableCompositeFolders"
+#define RLV_SETTING_ENABLELEGACYNAMING	"RLVaEnableLegacyNaming"
+#define RLV_SETTING_ENABLESHAREDWEAR	"RLVaEnableSharedWear"
+#define RLV_SETTING_ENABLETEMPATTACH    "RLVaEnableTemporaryAttachments"
+#define RLV_SETTING_HIDELOCKEDLAYER		"RLVaHideLockedLayers"
+#define RLV_SETTING_HIDELOCKEDATTACH	"RLVaHideLockedAttachments"
+#define RLV_SETTING_HIDELOCKEDINVENTORY	"RLVaHideLockedInventory"
+#define RLV_SETTING_LOGINLASTLOCATION	"RLVaLoginLastLocation"
+#define RLV_SETTING_SHAREDINVAUTORENAME	"RLVaSharedInvAutoRename"
+#define RLV_SETTING_SHOWASSERTIONFAIL	"RLVaShowAssertionFailures"
+#define RLV_SETTING_TOPLEVELMENU		"RLVaTopLevelMenu"
+#define RLV_SETTING_WEARREPLACEUNLOCKED	"RLVaWearReplaceUnlocked"
+
+#define RLV_SETTING_FIRSTUSE_PREFIX		"FirstRLV"
+#define RLV_SETTING_FIRSTUSE_GIVETORLV	RLV_SETTING_FIRSTUSE_PREFIX"GiveToRLV"
+
+// ============================================================================
+// Strings (see rlva_strings.xml)
+//
+
+#define RLV_STRING_HIDDEN					"hidden_generic"
+#define RLV_STRING_HIDDEN_PARCEL			"hidden_parcel"
+#define RLV_STRING_HIDDEN_REGION			"hidden_region"
+
+#define RLV_STRING_BLOCKED_AUTOPILOT		"blocked_autopilot"
+#define RLV_STRING_BLOCKED_GENERIC			"blocked_generic"
+#define RLV_STRING_BLOCKED_GROUPCHANGE		"blocked_groupchange"
+#define RLV_STRING_BLOCKED_PERMATTACH		"blocked_permattach"
+#define RLV_STRING_BLOCKED_PERMTELEPORT		"blocked_permteleport"
+#define RLV_STRING_BLOCKED_RECVIM			"blocked_recvim"
+#define RLV_STRING_BLOCKED_RECVIM_REMOTE	"blocked_recvim_remote"
+#define RLV_STRING_BLOCKED_SENDIM			"blocked_sendim"
+#define RLV_STRING_BLOCKED_STARTCONF		"blocked_startconf"
+#define RLV_STRING_BLOCKED_STARTIM			"blocked_startim"
+#define RLV_STRING_BLOCKED_TELEPORT			"blocked_teleport"
+#define RLV_STRING_BLOCKED_TELEPORT_OFFER   "blocked_teleport_offer"
+#define RLV_STRING_BLOCKED_TPLUREREQ_REMOTE	"blocked_tplurerequest_remote"
+#define RLV_STRING_BLOCKED_VIEWXXX			"blocked_viewxxx"
+#define RLV_STRING_BLOCKED_WIREFRAME		"blocked_wireframe"
+
+// ============================================================================
+
+#endif // RLV_DEFINES_H
diff --git a/indra/newview/rlvextensions.cpp b/indra/newview/rlvextensions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..43a5f61f506efa23d95a27f03ac24f3b2463e2dc
--- /dev/null
+++ b/indra/newview/rlvextensions.cpp
@@ -0,0 +1,640 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "lldaycyclemanager.h"
+#include "llvoavatarself.h"
+#include "llwlparammanager.h"
+
+#include "rlvextensions.h"
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+
+// ============================================================================
+
+class RlvWindLightControl
+{
+public:
+	enum EType			 { TYPE_COLOR, TYPE_COLOR_R, TYPE_FLOAT, TYPE_UNKNOWN };
+	enum EColorComponent { COMPONENT_R, COMPONENT_G, COMPONENT_B, COMPONENT_I, COMPONENT_NONE };
+public:
+	RlvWindLightControl(WLColorControl* pCtrl, bool fColorR) : m_eType((!fColorR) ? TYPE_COLOR: TYPE_COLOR_R), m_pColourCtrl(pCtrl), m_pFloatCtrl(NULL) {}
+	RlvWindLightControl(WLFloatControl* pCtrl) : m_eType(TYPE_FLOAT), m_pColourCtrl(NULL), m_pFloatCtrl(pCtrl) {}
+
+	EType		getControlType() const	{ return m_eType; }
+	bool		isColorType() const		{ return (TYPE_COLOR == m_eType) || (TYPE_COLOR_R == m_eType); }
+	bool		isFloatType() const		{ return (TYPE_FLOAT == m_eType); }
+	// TYPE_COLOR and TYPE_COLOR_R
+	F32			getColorComponent(EColorComponent eComponent, bool& fError) const;
+	LLVector4	getColorVector(bool& fError) const;
+	bool		setColorComponent(EColorComponent eComponent, F32 nValue);
+	// TYPE_FLOAT
+	F32			getFloat(bool& fError) const;
+	bool		setFloat(F32 nValue);
+
+	static EColorComponent getComponentFromCharacter(char ch);
+protected:
+	EType			m_eType;			// Type of the WindLight control
+	WLColorControl*	m_pColourCtrl;
+	WLFloatControl*	m_pFloatCtrl;
+};
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+static F32 get_intensity_from_color(const LLVector4& v)
+{
+	return llmax(v.mV[0], v.mV[1], v.mV[2]);
+}
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+F32 RlvWindLightControl::getColorComponent(EColorComponent eComponent, bool& fError) const
+{
+	switch (eComponent)
+	{
+		case COMPONENT_R: return getColorVector(fError).mV[0];
+		case COMPONENT_G: return getColorVector(fError).mV[1];
+		case COMPONENT_B: return getColorVector(fError).mV[2];
+		case COMPONENT_I: return get_intensity_from_color(getColorVector(fError));	// SL-2.8: Always seems to be 1.0 so get it manually
+		default         : RLV_ASSERT(false); fError = true; return 0.0;
+	}
+}
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+RlvWindLightControl::EColorComponent RlvWindLightControl::getComponentFromCharacter(char ch)
+{
+	if (('r' == ch) || ('x' == ch))
+		return COMPONENT_R;
+	else if (('g' == ch) || ('y' == ch))
+		return COMPONENT_G;
+	else if (('b' == ch) || ('d' == ch))
+		return COMPONENT_B;
+	else if ('i' == ch)
+		return COMPONENT_I;
+	return COMPONENT_NONE;
+}
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+LLVector4 RlvWindLightControl::getColorVector(bool& fError) const
+{
+	if ((fError = !isColorType()))
+		return LLVector4(0, 0, 0, 0);
+	F32 nMult = (m_pColourCtrl->isSunOrAmbientColor) ? 3.0f : ((m_pColourCtrl->isBlueHorizonOrDensity) ? 2.0f : 1.0f);
+	return LLWLParamManager::getInstance()->mCurParams.getVector(m_pColourCtrl->mName, fError) / nMult;
+}
+
+// Checked: 2011-08-28 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+bool RlvWindLightControl::setColorComponent(EColorComponent eComponent, F32 nValue)
+{
+	if (isColorType())
+	{
+		nValue *= (m_pColourCtrl->isSunOrAmbientColor) ? 3.0f : ((m_pColourCtrl->isBlueHorizonOrDensity) ? 2.0f : 1.0f);
+		if (COMPONENT_I == eComponent)								// (See: LLFloaterWindLight::onColorControlIMoved)
+		{
+			if (m_pColourCtrl->hasSliderName)
+			{
+				F32 curMax = llmax(m_pColourCtrl->r, m_pColourCtrl->g, m_pColourCtrl->b);
+				if ( (0.0f == nValue) || (0.0f == curMax) )
+				{
+					m_pColourCtrl->r = m_pColourCtrl->g = m_pColourCtrl->b = m_pColourCtrl->i = nValue;
+				}
+				else
+				{
+					F32 nDelta = (nValue - curMax) / curMax;
+					m_pColourCtrl->r *= (1.0f + nDelta);
+					m_pColourCtrl->g *= (1.0f + nDelta);
+					m_pColourCtrl->b *= (1.0f + nDelta);
+					m_pColourCtrl->i = nValue;
+				}
+			}
+		}
+		else														// (See: LLFloaterWindLight::onColorControlRMoved)
+		{
+			F32* pnValue = (COMPONENT_R == eComponent) ? &m_pColourCtrl->r : (COMPONENT_G == eComponent) ? &m_pColourCtrl->g : (COMPONENT_B == eComponent) ? &m_pColourCtrl->b : NULL;
+			if (pnValue)
+				*pnValue = nValue;
+			if (m_pColourCtrl->hasSliderName)
+				m_pColourCtrl->i = llmax(m_pColourCtrl->r, m_pColourCtrl->g, m_pColourCtrl->b);
+		}
+		m_pColourCtrl->update(LLWLParamManager::getInstance()->mCurParams);
+		LLWLParamManager::getInstance()->propagateParameters();
+	}
+	return isColorType();
+}
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+F32 RlvWindLightControl::getFloat(bool& fError) const
+{
+	return (!(fError = (TYPE_FLOAT != m_eType))) ? LLWLParamManager::getInstance()->mCurParams.getVector(m_pFloatCtrl->mName, fError).mV[0] * m_pFloatCtrl->mult : 0.0;
+}
+
+// Checked: 2011-08-28 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+bool RlvWindLightControl::setFloat(F32 nValue)
+{
+	if (TYPE_FLOAT == m_eType)
+	{
+		m_pFloatCtrl->x = nValue / m_pFloatCtrl->mult;
+		m_pFloatCtrl->update(LLWLParamManager::getInstance()->mCurParams);
+		LLWLParamManager::getInstance()->propagateParameters();
+	}
+	return (TYPE_FLOAT == m_eType);
+}
+
+// ============================================================================
+
+class RlvWindLight : public LLSingleton<RlvWindLight>
+{
+	friend class LLSingleton<RlvWindLight>;
+public:
+	RlvWindLight();
+
+	std::string	getValue(const std::string& strSetting, bool& fError);
+	bool		setValue(const std::string& strRlvName, const std::string& strValue);
+
+protected:
+	std::map<std::string, RlvWindLightControl> m_ControlLookupMap;
+};
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+RlvWindLight::RlvWindLight()
+{
+	LLWLParamManager* pWLParamMgr = LLWLParamManager::getInstance();
+
+	// TYPE_FLOAT
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudcoverage",	RlvWindLightControl(&pWLParamMgr->mCloudCoverage)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudscale",		RlvWindLightControl(&pWLParamMgr->mCloudScale)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("densitymultiplier", RlvWindLightControl(&pWLParamMgr->mDensityMult)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("distancemultiplier", RlvWindLightControl(&pWLParamMgr->mDistanceMult)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("maxaltitude",	RlvWindLightControl(&pWLParamMgr->mMaxAlt)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("scenegamma",		RlvWindLightControl(&pWLParamMgr->mWLGamma)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("hazedensity",	RlvWindLightControl(&pWLParamMgr->mHazeDensity)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("hazehorizon",	RlvWindLightControl(&pWLParamMgr->mHazeHorizon)));
+	// TYPE_COLOR
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("ambient",		RlvWindLightControl(&pWLParamMgr->mAmbient, false)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("bluedensity",	RlvWindLightControl(&pWLParamMgr->mBlueDensity, false)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("bluehorizon",	RlvWindLightControl(&pWLParamMgr->mBlueHorizon, false)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloud",			RlvWindLightControl(&pWLParamMgr->mCloudMain, false)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudcolor",		RlvWindLightControl(&pWLParamMgr->mCloudColor, false)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("clouddetail",	RlvWindLightControl(&pWLParamMgr->mCloudDetail, false)));
+	m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("sunmooncolor",	RlvWindLightControl(&pWLParamMgr->mSunlight, false)));
+}
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+std::string RlvWindLight::getValue(const std::string& strSetting, bool& fError)
+{
+	LLWLParamManager* pWLParams = LLWLParamManager::getInstance(); 
+	LLEnvManagerNew* pEnvMgr = LLEnvManagerNew::getInstance();
+
+	fError = false;							// Assume we won't fail
+	if ("preset" == strSetting)
+		return (pEnvMgr->getUseFixedSky()) ? pEnvMgr->getSkyPresetName() : std::string();
+	else if ("daycycle" == strSetting)
+		return (pEnvMgr->getUseDayCycle()) ? pEnvMgr->getDayCycleName() : std::string();
+
+	F32 nValue = 0.0f;
+	if ("daytime" == strSetting)
+	{
+		nValue = (pEnvMgr->getUseFixedSky()) ? pWLParams->mCurParams.getFloat("sun_angle", fError) / F_TWO_PI : -1.0f;
+	}
+	else if (("sunglowfocus" == strSetting) || ("sunglowsize" == strSetting))
+	{
+		pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fError);
+		RLV_ASSERT_DBG(!fError);
+
+		if ("sunglowfocus" == strSetting) 
+			nValue = -pWLParams->mGlow.b / 5.0f;
+		else
+			nValue = 2 - pWLParams->mGlow.r / 20.0f;
+	}
+	else if ("starbrightness" == strSetting)		nValue = pWLParams->mCurParams.getStarBrightness();
+	else if ("eastangle" == strSetting)				nValue = pWLParams->mCurParams.getEastAngle() / F_TWO_PI;
+	else if ("sunmoonposition" == strSetting)		nValue = pWLParams->mCurParams.getSunAngle() / F_TWO_PI;
+	else if ("cloudscrollx" == strSetting)			nValue = pWLParams->mCurParams.getCloudScrollX() - 10.0f;
+	else if ("cloudscrolly" == strSetting)			nValue = pWLParams->mCurParams.getCloudScrollY() - 10.0f;
+	else
+	{
+		std::map<std::string, RlvWindLightControl>::const_iterator itControl = m_ControlLookupMap.find(strSetting);
+		if (m_ControlLookupMap.end() != itControl)
+		{
+			switch (itControl->second.getControlType())
+			{
+				case RlvWindLightControl::TYPE_FLOAT:
+					nValue = itControl->second.getFloat(fError);
+					break;
+				case RlvWindLightControl::TYPE_COLOR_R:
+					nValue = itControl->second.getColorComponent(RlvWindLightControl::COMPONENT_R, fError);
+					break;
+				default:
+					fError = true;
+					break;
+			}
+		}
+		else
+		{
+			// Couldn't find the exact name, check for a color control name
+			RlvWindLightControl::EColorComponent eComponent = RlvWindLightControl::getComponentFromCharacter(strSetting[strSetting.length() - 1]);
+			if (RlvWindLightControl::COMPONENT_NONE != eComponent)
+				itControl = m_ControlLookupMap.find(strSetting.substr(0, strSetting.length() - 1));
+			if ( (m_ControlLookupMap.end() != itControl) && (itControl->second.isColorType()) )
+				nValue = itControl->second.getColorComponent(eComponent, fError);
+			else
+				fError = true;
+		}
+	}
+	return llformat("%f", nValue);
+}
+
+// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a
+bool RlvWindLight::setValue(const std::string& strRlvName, const std::string& strValue)
+{
+	F32 nValue = 0.0f;
+	// Sanity check - make sure strValue specifies a number for all settings except "preset" and "daycycle"
+	if ( (RlvSettings::getNoSetEnv()) || 
+		 ( (!LLStringUtil::convertToF32(strValue, nValue)) && (("preset" != strRlvName) && ("daycycle" != strRlvName)) ) )
+ 	{
+		return false;
+	}
+
+	LLWLParamManager* pWLParams = LLWLParamManager::getInstance(); 
+	LLEnvManagerNew* pEnvMgr = LLEnvManagerNew::getInstance();
+
+	if ("daytime" == strRlvName)
+	{
+		if (0.0f <= nValue)
+		{
+			pWLParams->mAnimator.deactivate();
+			pWLParams->mAnimator.setDayTime(nValue);
+			pWLParams->mAnimator.update(pWLParams->mCurParams);
+		}
+		else
+		{
+			pEnvMgr->setUserPrefs(pEnvMgr->getWaterPresetName(), pEnvMgr->getSkyPresetName(), pEnvMgr->getDayCycleName(), false, true);
+		}
+		return true;
+	}
+	else if ("preset" == strRlvName)
+	{
+		std::string strPresetName = pWLParams->findPreset(strValue, LLEnvKey::SCOPE_LOCAL);
+		if (!strPresetName.empty())
+			pEnvMgr->useSkyPreset(strPresetName);
+		return !strPresetName.empty();
+	}
+	else if ("daycycle" == strRlvName)
+	{
+		std::string strPresetName = LLDayCycleManager::instance().findPreset(strValue);
+		if (!strPresetName.empty())
+			pEnvMgr->useDayCycle(strValue, LLEnvKey::SCOPE_LOCAL);
+		return !strPresetName.empty();
+	}
+
+	bool fError = false;
+	pWLParams->mAnimator.deactivate();
+	if (("sunglowfocus" == strRlvName) || ("sunglowsize" == strRlvName))
+	{
+		pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fError);
+		RLV_ASSERT_DBG(!fError);
+
+		if ("sunglowfocus" == strRlvName)
+			pWLParams->mGlow.b = -nValue * 5;
+		else
+			pWLParams->mGlow.r = (2 - nValue) * 20;
+
+		pWLParams->mGlow.update(pWLParams->mCurParams);
+		pWLParams->propagateParameters();
+		return true;
+	}
+	else if ("starbrightness" == strRlvName)
+	{
+		pWLParams->mCurParams.setStarBrightness(nValue);
+		return true;
+	}
+	else if (("eastangle" == strRlvName) || ("sunmoonposition" == strRlvName))
+	{
+		if ("eastangle" == strRlvName)
+			pWLParams->mCurParams.setEastAngle(F_TWO_PI * nValue);
+		else
+			pWLParams->mCurParams.setSunAngle(F_TWO_PI * nValue);
+
+		// Set the sun vector
+		pWLParams->mLightnorm.r = -sin(pWLParams->mCurParams.getEastAngle()) * cos(pWLParams->mCurParams.getSunAngle());
+		pWLParams->mLightnorm.g = sin(pWLParams->mCurParams.getSunAngle());
+		pWLParams->mLightnorm.b = cos(pWLParams->mCurParams.getEastAngle()) * cos(pWLParams->mCurParams.getSunAngle());
+		pWLParams->mLightnorm.i = 1.f;
+
+		pWLParams->propagateParameters();
+		return true;
+	}
+	else if ("cloudscrollx" == strRlvName)
+	{
+		pWLParams->mCurParams.setCloudScrollX(nValue + 10.0f);
+		return true;
+	}
+	else if ("cloudscrolly" == strRlvName)
+	{
+		pWLParams->mCurParams.setCloudScrollY(nValue + 10.0f);
+		return true;
+	}
+
+	std::map<std::string, RlvWindLightControl>::iterator itControl = m_ControlLookupMap.find(strRlvName);
+	if (m_ControlLookupMap.end() != itControl)
+	{
+		switch (itControl->second.getControlType())
+		{
+			case RlvWindLightControl::TYPE_FLOAT:
+				return itControl->second.setFloat(nValue);
+			case RlvWindLightControl::TYPE_COLOR_R:
+				return itControl->second.setColorComponent(RlvWindLightControl::COMPONENT_R, nValue);
+			default:
+				RLV_ASSERT(false);
+		}
+	}
+	else
+	{
+		// Couldn't find the exact name, check for a color control name
+		RlvWindLightControl::EColorComponent eComponent = RlvWindLightControl::getComponentFromCharacter(strRlvName[strRlvName.length() - 1]);
+		if (RlvWindLightControl::COMPONENT_NONE != eComponent)
+			itControl = m_ControlLookupMap.find(strRlvName.substr(0, strRlvName.length() - 1));
+		if ( (m_ControlLookupMap.end() != itControl) && (itControl->second.isColorType()) )
+			return itControl->second.setColorComponent(eComponent, nValue);
+	}
+	return false;
+}
+
+// ============================================================================
+
+std::map<std::string, S16> RlvExtGetSet::m_DbgAllowed;
+std::map<std::string, std::string> RlvExtGetSet::m_PseudoDebug;
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h
+RlvExtGetSet::RlvExtGetSet()
+{
+	if (!m_DbgAllowed.size())	// m_DbgAllowed is static and should only be initialized once
+	{
+		m_DbgAllowed.insert(std::pair<std::string, S16>("AvatarSex", DBG_READ | DBG_WRITE | DBG_PSEUDO));
+		m_DbgAllowed.insert(std::pair<std::string, S16>("RenderResolutionDivisor", DBG_READ | DBG_WRITE));
+		m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_FORBIDGIVETORLV, DBG_READ));
+		m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_NOSETENV, DBG_READ));
+		m_DbgAllowed.insert(std::pair<std::string, S16>("WindLightUseAtmosShaders", DBG_READ));
+
+		// Cache persistance of every setting
+		LLControlVariable* pSetting;
+		for (std::map<std::string, S16>::iterator itDbg = m_DbgAllowed.begin(); itDbg != m_DbgAllowed.end(); ++itDbg)
+		{
+			if ( ((pSetting = gSavedSettings.getControl(itDbg->first)) != NULL) && (pSetting->isPersisted()) )
+				itDbg->second |= DBG_PERSIST;
+		}
+	}
+}
+
+// Checked: 2009-05-17 (RLVa-0.2.0a)
+bool RlvExtGetSet::onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)
+{
+	return processCommand(rlvCmd, cmdRet);
+}
+
+// Checked: 2009-05-17 (RLVa-0.2.0a)
+bool RlvExtGetSet::onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)
+{
+	return processCommand(rlvCmd, cmdRet);
+}
+
+// Checked: 2009-12-23 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k
+bool RlvExtGetSet::processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet)
+{
+	std::string strBehaviour = rlvCmd.getBehaviour(), strGetSet, strSetting;
+	int idxSetting = strBehaviour.find('_');
+	if ( (strBehaviour.length() >= 6) && (-1 != idxSetting) && ((int)strBehaviour.length() > idxSetting + 1) )
+	{
+		strSetting = strBehaviour.substr(idxSetting + 1);
+		strBehaviour.erase(idxSetting);	// Get rid of "_<setting>"
+
+		strGetSet = strBehaviour.substr(0, 3);
+		strBehaviour.erase(0, 3);		// Get rid of get/set
+
+		if ("debug" == strBehaviour)
+		{
+			if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) )
+			{
+				RlvUtil::sendChatReply(rlvCmd.getParam(), onGetDebug(strSetting));
+				eRet = RLV_RET_SUCCESS;
+				return true;
+			}
+			else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) )
+			{
+				if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETDEBUG, rlvCmd.getObjectID()))
+					eRet = onSetDebug(strSetting, rlvCmd.getOption());
+				else
+					eRet = RLV_RET_FAILED_LOCK;
+				return true;
+			}
+		}
+		else if ("env" == strBehaviour)
+		{
+			bool fError = false;
+			if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) )
+			{
+				RlvUtil::sendChatReply(rlvCmd.getParam(), RlvWindLight::instance().getValue(strSetting, fError));
+				eRet = (!fError) ? RLV_RET_SUCCESS : RLV_RET_FAILED_UNKNOWN;
+				return true;
+			}
+			else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) )
+			{
+				if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETENV, rlvCmd.getObjectID()))
+					eRet = (RlvWindLight::instance().setValue(strSetting, rlvCmd.getOption())) ? RLV_RET_SUCCESS : RLV_RET_FAILED_UNKNOWN;
+				else
+					eRet = RLV_RET_FAILED_LOCK;
+				return true;
+			}
+		}
+	}
+	else if ("setrot" == rlvCmd.getBehaviour())
+	{
+		// NOTE: if <option> is invalid (or missing) altogether then RLV-1.17 will rotate to 0.0 (which is actually PI / 4)
+		F32 nAngle = 0.0f;
+		if (LLStringUtil::convertToF32(rlvCmd.getOption(), nAngle))
+		{
+			nAngle = RLV_SETROT_OFFSET - nAngle;
+
+			gAgentCamera.startCameraAnimation();
+
+			LLVector3 at(LLVector3::x_axis);
+			at.rotVec(nAngle, LLVector3::z_axis);
+			at.normalize();
+			gAgent.resetAxes(at);
+
+			eRet = RLV_RET_SUCCESS;
+		}
+		else
+		{
+			eRet = RLV_RET_FAILED_OPTION;
+		}
+		return true;
+	}
+	return false;
+}
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h
+bool RlvExtGetSet::findDebugSetting(std::string& strSetting, S16& flags)
+{
+	LLStringUtil::toLower(strSetting);	// Convenience for non-RLV calls
+
+	std::string strTemp;
+	for (std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.begin(); itSetting != m_DbgAllowed.end(); ++itSetting)
+	{
+		strTemp = itSetting->first;
+		LLStringUtil::toLower(strTemp);
+		
+		if (strSetting == strTemp)
+		{
+			strSetting = itSetting->first;
+			flags = itSetting->second;
+			return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h
+S16 RlvExtGetSet::getDebugSettingFlags(const std::string& strSetting)
+{
+	std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.find(strSetting);
+	return (itSetting != m_DbgAllowed.end()) ? itSetting->second : 0;
+}
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h
+std::string RlvExtGetSet::onGetDebug(std::string strSetting)
+{
+	S16 dbgFlags;
+	if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_READ) == DBG_READ) )
+	{
+		if ((dbgFlags & DBG_PSEUDO) == 0)
+		{
+			LLControlVariable* pSetting = gSavedSettings.getControl(strSetting);
+			if (pSetting)
+			{
+				switch (pSetting->type())
+				{
+					case TYPE_U32:
+						return llformat("%u", gSavedSettings.getU32(strSetting));
+					case TYPE_S32:
+						return llformat("%d", gSavedSettings.getS32(strSetting));
+					case TYPE_BOOLEAN:
+						return llformat("%d", gSavedSettings.getBOOL(strSetting));
+					default:
+						RLV_ERRS << "Unexpected debug setting type" << LL_ENDL;
+						break;
+				}
+			}
+		}
+		else
+		{
+			return onGetPseudoDebug(strSetting);
+		}
+	}
+	return std::string();
+}
+
+// Checked: 2009-10-03 (RLVa-1.0.4e) | Added: RLVa-1.0.4e
+std::string RlvExtGetSet::onGetPseudoDebug(const std::string& strSetting)
+{
+	// Skip sanity checking because it's all done in RlvExtGetSet::onGetDebug() already
+	if ("AvatarSex" == strSetting)
+	{
+		std::map<std::string, std::string>::const_iterator itPseudo = m_PseudoDebug.find(strSetting);
+		if (itPseudo != m_PseudoDebug.end())
+		{
+			return itPseudo->second;
+		}
+		else
+		{
+			if (isAgentAvatarValid())
+				return llformat("%d", (gAgentAvatarp->getSex() == SEX_MALE)); // [See LLFloaterCustomize::LLFloaterCustomize()]
+		}
+	}
+	return std::string();
+}
+
+// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e
+ERlvCmdRet RlvExtGetSet::onSetDebug(std::string strSetting, const std::string& strValue)
+{
+	S16 dbgFlags; ERlvCmdRet eRet = RLV_RET_FAILED_UNKNOWN;
+	if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_WRITE) == DBG_WRITE) )
+	{
+		eRet = RLV_RET_FAILED_OPTION;
+		if ((dbgFlags & DBG_PSEUDO) == 0)
+		{
+			LLControlVariable* pSetting = gSavedSettings.getControl(strSetting);
+			if (pSetting)
+			{
+				U32 u32Value; S32 s32Value; BOOL fValue;
+				switch (pSetting->type())
+				{
+					case TYPE_U32:
+						if (LLStringUtil::convertToU32(strValue, u32Value))
+						{
+							gSavedSettings.setU32(strSetting, u32Value);
+							eRet = RLV_RET_SUCCESS;
+						}
+						break;
+					case TYPE_S32:
+						if (LLStringUtil::convertToS32(strValue, s32Value))
+						{
+							gSavedSettings.setS32(strSetting, s32Value);
+							eRet = RLV_RET_SUCCESS;
+						}
+						break;
+					case TYPE_BOOLEAN:
+						if (LLStringUtil::convertToBOOL(strValue, fValue))
+						{
+							gSavedSettings.setBOOL(strSetting, fValue);
+							eRet = RLV_RET_SUCCESS;
+						}
+						break;
+					default:
+						RLV_ERRS << "Unexpected debug setting type" << LL_ENDL;
+						eRet = RLV_RET_FAILED;
+						break;
+				}
+
+				// Default settings should persist if they were marked that way, but non-default settings should never persist
+				pSetting->setPersist( ((pSetting->isDefault()) && ((dbgFlags & DBG_PERSIST) == DBG_PERSIST)) ? LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO );
+			}
+		}
+		else
+		{
+			eRet = onSetPseudoDebug(strSetting, strValue);
+		}
+	}
+	return eRet;
+}
+
+// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e
+ERlvCmdRet RlvExtGetSet::onSetPseudoDebug(const std::string& strSetting, const std::string& strValue)
+{
+	ERlvCmdRet eRet = RLV_RET_FAILED_OPTION;
+	if ("AvatarSex" == strSetting)
+	{
+		BOOL fValue;
+		if (LLStringUtil::convertToBOOL(strValue, fValue))
+		{
+			m_PseudoDebug[strSetting] = strValue;
+			eRet = RLV_RET_SUCCESS;
+		}
+	}
+	return eRet;
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvextensions.h b/indra/newview/rlvextensions.h
new file mode 100644
index 0000000000000000000000000000000000000000..08a6d1fca7b1022e53d1fbb3b9ab2ccd642eeeea
--- /dev/null
+++ b/indra/newview/rlvextensions.h
@@ -0,0 +1,57 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_EXTENSIONS_H
+#define RLV_EXTENSIONS_H
+
+#include "rlvcommon.h"
+
+// ============================================================================
+/*
+ * RlvExtGetSet
+ * ============
+ * Implements @get_XXX:<option>=<channel> and @set_XXX:<option>=force
+ *
+ */
+
+class RlvExtGetSet : public RlvExtCommandHandler
+{
+public:
+	RlvExtGetSet();
+	virtual ~RlvExtGetSet() {}
+
+	virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet);
+	virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet);
+protected:
+	std::string onGetDebug(std::string strSetting);
+	std::string onGetPseudoDebug(const std::string& strSetting);
+	ERlvCmdRet  onSetDebug(std::string strSetting, const std::string& strValue);
+	ERlvCmdRet  onSetPseudoDebug(const std::string& strSetting, const std::string& strValue);
+
+	bool processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet);
+
+public:
+	enum { DBG_READ = 0x01, DBG_WRITE = 0x02, DBG_PERSIST = 0x04, DBG_PSEUDO = 0x08 };
+	static std::map<std::string, S16> m_DbgAllowed;
+	static std::map<std::string, std::string> m_PseudoDebug;
+
+	static bool findDebugSetting(/*[in,out]*/ std::string& strSetting, /*[out]*/ S16& flags);
+	static S16  getDebugSettingFlags(const std::string& strSetting);
+};
+
+// ============================================================================
+
+#endif // RLV_EXTENSIONS_H
diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4b4303cf2789423ac4c4ed1a8e307c6abc105b1c
--- /dev/null
+++ b/indra/newview/rlvfloaters.cpp
@@ -0,0 +1,818 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llavatarnamecache.h"
+#include "llclipboard.h"
+#include "llcombobox.h"
+#include "llinventoryfunctions.h"
+#include "llnotificationsutil.h"
+#include "llscrolllistctrl.h"
+#include "llsdserialize.h"
+#include "lltexteditor.h"
+#include "llviewerjointattachment.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatarself.h"
+
+#include "rlvfloaters.h"
+#include "rlvhelper.h"
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+
+// ============================================================================
+// Helper functions
+//
+
+// Checked: 2012-07-14 (RLVa-1.4.7)
+std::string rlvGetItemName(const LLViewerInventoryItem* pItem)
+{
+	if ( (pItem) && ((LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType())) )
+	{
+		return llformat("%s (%s)", pItem->getName().c_str(), LLWearableType::getTypeName(pItem->getWearableType()).c_str());
+	}
+	else if ( (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (isAgentAvatarValid()) )
+	{
+		std::string strAttachPtName;
+		gAgentAvatarp->getAttachedPointName(pItem->getUUID(), strAttachPtName);
+		return llformat("%s (%s)", pItem->getName().c_str(), strAttachPtName.c_str());
+	}
+	return (pItem) ? pItem->getName() : LLStringUtil::null;
+}
+
+// Checked: 2012-07-14 (RLVa-1.4.7)
+std::string rlvGetItemType(const LLViewerInventoryItem* pItem)
+{
+	if (pItem)
+	{
+		switch (pItem->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+			case LLAssetType::AT_CLOTHING:
+				return "Wearable";
+			case LLAssetType::AT_OBJECT:
+				return "Attachment";
+			default:
+				break;
+		}
+	}
+	return "Unknown";
+}
+
+std::string rlvGetItemNameFromObjID(const LLUUID& idObj, bool fIncludeAttachPt = true)
+{
+	const LLViewerObject* pObj = gObjectList.findObject(idObj);
+	if ( (pObj) && (pObj->isAvatar()) )
+	{
+		LLAvatarName avName;
+		if (LLAvatarNameCache::get(pObj->getID(), &avName))
+			return avName.getCompleteName();
+		return ((LLVOAvatar*)pObj)->getFullname();
+	}
+
+	const LLViewerObject* pObjRoot = (pObj) ? pObj->getRootEdit() : NULL;
+	const LLViewerInventoryItem* pItem = ((pObjRoot) && (pObjRoot->isAttachment())) ? gInventory.getItem(pObjRoot->getAttachmentItemID()) : NULL;
+
+	const std::string strItemName = (pItem) ? pItem->getName() : idObj.asString();
+	if ( (!fIncludeAttachPt) || (!pObj) || (!pObj->isAttachment()) || (!isAgentAvatarValid()) )
+		return strItemName;
+
+	const LLViewerJointAttachment* pAttachPt = get_if_there(gAgentAvatarp->mAttachmentPoints, RlvAttachPtLookup::getAttachPointIndex(pObjRoot), (LLViewerJointAttachment*)NULL);
+	const std::string strAttachPtName = (pAttachPt) ? pAttachPt->getName() : std::string("Unknown");
+	return llformat("%s (%s%s)", strItemName.c_str(), strAttachPtName.c_str(), (pObj == pObjRoot) ? "" : ", child");
+}
+
+// Checked: 2011-05-23 (RLVa-1.3.0c) | Added: RLVa-1.3.0c
+bool rlvGetShowException(ERlvBehaviour eBhvr)
+{
+	switch (eBhvr)
+	{
+		case RLV_BHVR_RECVCHAT:
+		case RLV_BHVR_RECVEMOTE:
+		case RLV_BHVR_SENDIM:
+		case RLV_BHVR_RECVIM:
+		case RLV_BHVR_STARTIM:
+		case RLV_BHVR_TPLURE:
+		case RLV_BHVR_TPREQUEST:
+		case RLV_BHVR_ACCEPTTP:
+		case RLV_BHVR_ACCEPTTPREQUEST:
+		case RLV_BHVR_SHOWNAMES:
+		case RLV_BHVR_SHOWNAMETAGS:
+			return true;
+		default:
+			return false;
+	}
+}
+
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvLockMaskToString(ERlvLockMask eLockType)
+{
+	switch (eLockType)
+	{
+		case RLV_LOCK_ADD:
+			return "add";
+		case RLV_LOCK_REMOVE:
+			return "rem";
+		default:
+			return "unknown";
+	}
+}
+
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvFolderLockPermissionToString(RlvFolderLocks::ELockPermission eLockPermission)
+{
+	switch (eLockPermission)
+	{
+		case RlvFolderLocks::PERM_ALLOW:
+			return "allow";
+		case RlvFolderLocks::PERM_DENY:
+			return "deny";
+		default:
+			return "unknown";
+	}
+}
+
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvFolderLockScopeToString(RlvFolderLocks::ELockScope eLockScope)
+{
+	switch (eLockScope)
+	{
+		case RlvFolderLocks::SCOPE_NODE:
+			return "node";
+		case RlvFolderLocks::SCOPE_SUBTREE:
+			return "subtree";
+		default:
+			return "unknown";
+	}
+}
+
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvFolderLockSourceToTarget(RlvFolderLocks::folderlock_source_t lockSource)
+{
+	switch (lockSource.first)
+	{
+		case RlvFolderLocks::ST_ATTACHMENT:
+			{
+				std::string strAttachName = rlvGetItemNameFromObjID(boost::get<LLUUID>(lockSource.second));
+				return llformat("Attachment (%s)", strAttachName.c_str());
+			}
+		case RlvFolderLocks::ST_ATTACHMENTPOINT:
+			{
+				const LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(boost::get<S32>(lockSource.second));
+				return llformat("Attachment point (%s)", (pAttachPt) ? pAttachPt->getName().c_str() : "Unknown");
+			}
+		case RlvFolderLocks::ST_FOLDER:
+			{
+				return "Folder: <todo>";
+			}
+		case RlvFolderLocks::ST_ROOTFOLDER:
+			{
+				return "Root folder";
+			}
+		case RlvFolderLocks::ST_SHAREDPATH:
+			{
+				const std::string& strPath = boost::get<std::string>(lockSource.second);
+				return llformat("Shared path (#RLV%s%s)", (!strPath.empty()) ? "/" : "", strPath.c_str());
+			}
+		case RlvFolderLocks::ST_WEARABLETYPE:
+			{
+				const std::string& strTypeName = LLWearableType::getTypeName(boost::get<LLWearableType::EType>(lockSource.second));
+				return llformat("Wearable type (%s)", strTypeName.c_str());
+			}
+		default:
+			{
+				return "(Unknown)";
+			}
+	}
+}
+
+// ============================================================================
+// RlvFloaterBehaviours member functions
+//
+
+// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::onOpen(const LLSD& sdKey)
+{
+	m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterBehaviours::onCommand, this, _1, _2));
+
+	refreshAll();
+}
+
+// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::onClose(bool fQuitting)
+{
+	m_ConnRlvCommand.disconnect();
+}
+
+// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::onAvatarNameLookup(const LLUUID& idAgent, const LLAvatarName& avName)
+{
+	uuid_vec_t::iterator itLookup = std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idAgent);
+	if (itLookup != m_PendingLookup.end())
+		m_PendingLookup.erase(itLookup);
+	if (getVisible())
+		refreshAll();
+}
+
+// Checked: 2011-05-26 (RLVa-1.3.1c) | Added: RLVa-1.3.1c
+void RlvFloaterBehaviours::onBtnCopyToClipboard()
+{
+	std::ostringstream strRestrictions;
+
+	strRestrictions << RlvStrings::getVersion(LLUUID::null) << "\n";
+
+	const RlvHandler::rlv_object_map_t* pObjects = gRlvHandler.getObjectMap();
+	for (RlvHandler::rlv_object_map_t::const_iterator itObj = pObjects->begin(), endObj = pObjects->end(); itObj != endObj; ++itObj)
+	{
+		strRestrictions << "\n" << rlvGetItemNameFromObjID(itObj->first) << ":\n";
+
+		const rlv_command_list_t* pCommands = itObj->second.getCommandList();
+		for (rlv_command_list_t::const_iterator itCmd = pCommands->begin(), endCmd = pCommands->end(); itCmd != endCmd; ++itCmd)
+		{
+			std::string strOption; LLUUID idOption;
+			if ( (itCmd->hasOption()) && (idOption.set(itCmd->getOption(), FALSE)) && (idOption.notNull()) )
+			{
+				LLAvatarName avName;
+				if (gObjectList.findObject(idOption))
+					strOption = rlvGetItemNameFromObjID(idOption, true);
+				else if (LLAvatarNameCache::get(idOption, &avName))
+					strOption = (!avName.getAccountName().empty()) ? avName.getAccountName() : avName.getDisplayName();
+				else if (!gCacheName->getGroupName(idOption, strOption))
+					strOption = itCmd->getOption();
+			}
+
+			strRestrictions << "  -> " << itCmd->asString();
+			if ( (!strOption.empty()) && (strOption != itCmd->getOption()) )
+				strRestrictions << "  [" << strOption << "]";
+			strRestrictions << "\n";
+		}
+	}
+
+	LLWString wstrRestrictions = utf8str_to_wstring(strRestrictions.str());
+	LLClipboard::instance().copyToClipboard(wstrRestrictions, 0, wstrRestrictions.length());
+}
+
+// Checked: 2011-05-23 (RLVa-1.3.1c) | Modified: RLVa-1.3.1c
+void RlvFloaterBehaviours::onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet)
+{
+	if ( (RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType()) )
+		refreshAll();
+}
+
+// Checked: 2011-05-23 (RLVa-1.3.1c) | Added: RLVa-1.3.1c
+BOOL RlvFloaterBehaviours::postBuild()
+{
+	getChild<LLUICtrl>("copy_btn")->setCommitCallback(boost::bind(&RlvFloaterBehaviours::onBtnCopyToClipboard, this));
+	return TRUE;
+}
+
+void RlvFloaterBehaviours::refreshAll()
+{
+	LLCtrlListInterface* pBhvrList = childGetListInterface("behaviour_list");
+	LLCtrlListInterface* pExceptList = childGetListInterface("exception_list");
+	LLCtrlListInterface* pModifierList = childGetListInterface("modifier_list");
+	if ( (!pBhvrList) || (!pExceptList) || (!pModifierList) )
+		return;
+	pBhvrList->operateOnAll(LLCtrlListInterface::OP_DELETE);
+	pExceptList->operateOnAll(LLCtrlListInterface::OP_DELETE);
+	pModifierList->operateOnAll(LLCtrlListInterface::OP_DELETE);
+
+	if (!isAgentAvatarValid())
+		return;
+
+	//
+	// Set-up a row we can just reuse
+	//
+	LLSD sdBhvrRow; LLSD& sdBhvrColumns = sdBhvrRow["columns"];
+	sdBhvrColumns[0] = LLSD().with("column", "behaviour").with("type", "text");
+	sdBhvrColumns[1] = LLSD().with("column", "issuer").with("type", "text");
+
+	LLSD sdExceptRow; LLSD& sdExceptColumns = sdExceptRow["columns"];
+	sdExceptColumns[0] = LLSD().with("column", "behaviour").with("type", "text");
+	sdExceptColumns[1] = LLSD().with("column", "option").with("type", "text");
+	sdExceptColumns[2] = LLSD().with("column", "issuer").with("type", "text");
+
+	LLSD sdModifierRow; LLSD& sdModifierColumns = sdModifierRow["columns"];
+	sdModifierColumns[0] = LLSD().with("column", "modifier").with("type", "text");
+	sdModifierColumns[1] = LLSD().with("column", "value").with("type", "text");
+	sdModifierColumns[2] = LLSD().with("column", "primary").with("type", "text");
+
+	//
+	// List behaviours
+	//
+	const RlvHandler::rlv_object_map_t* pObjects = gRlvHandler.getObjectMap();
+	for (RlvHandler::rlv_object_map_t::const_iterator itObj = pObjects->begin(), endObj = pObjects->end(); itObj != endObj; ++itObj)
+	{
+		const std::string strIssuer = rlvGetItemNameFromObjID(itObj->first);
+
+		const rlv_command_list_t* pCommands = itObj->second.getCommandList();
+		for (rlv_command_list_t::const_iterator itCmd = pCommands->begin(), endCmd = pCommands->end(); itCmd != endCmd; ++itCmd)
+		{
+			std::string strOption; LLUUID idOption;
+			if ( (itCmd->hasOption()) && (idOption.set(itCmd->getOption(), FALSE)) && (idOption.notNull()) )
+			{
+				LLAvatarName avName;
+				if (gObjectList.findObject(idOption))
+				{
+					strOption = rlvGetItemNameFromObjID(idOption, true);
+				}
+				else if (LLAvatarNameCache::get(idOption, &avName))
+				{
+					strOption = (!avName.getAccountName().empty()) ? avName.getAccountName() : avName.getDisplayName();
+				}
+				else if (!gCacheName->getGroupName(idOption, strOption))
+				{
+					if (m_PendingLookup.end() == std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idOption))
+					{
+						LLAvatarNameCache::get(idOption, boost::bind(&RlvFloaterBehaviours::onAvatarNameLookup, this, _1, _2));
+						m_PendingLookup.push_back(idOption);
+					}
+					strOption = itCmd->getOption();
+				}
+			}
+
+			if ( (itCmd->hasOption()) && (rlvGetShowException(itCmd->getBehaviourType())) )
+			{
+				// List under the "Exception" tab
+				sdExceptRow["enabled"] = gRlvHandler.isException(itCmd->getBehaviourType(), idOption);
+				sdExceptColumns[0]["value"] = itCmd->getBehaviour();
+				sdExceptColumns[1]["value"] = strOption;
+				sdExceptColumns[2]["value"] = strIssuer;
+				pExceptList->addElement(sdExceptRow, ADD_BOTTOM);
+			}
+			else
+			{
+				// List under the "Restrictions" tab
+				sdBhvrColumns[0]["value"] = (strOption.empty()) ? itCmd->asString() : itCmd->getBehaviour() + ":" + strOption;
+				sdBhvrColumns[1]["value"] = strIssuer;
+				pBhvrList->addElement(sdBhvrRow, ADD_BOTTOM);
+			}
+		}
+	}
+
+	//
+	// List modifiers
+	//
+	for (int idxModifier = 0; idxModifier < RLV_MODIFIER_COUNT; idxModifier++)
+	{
+		const RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().m_BehaviourModifiers[idxModifier];
+		if (pBhvrModifier)
+		{
+			sdModifierRow["enabled"] = (pBhvrModifier->hasValue());
+			sdModifierColumns[0]["value"] = pBhvrModifier->getName();
+
+			if (pBhvrModifier->hasValue())
+			{
+				const RlvBehaviourModifierValue& modValue = pBhvrModifier->getValue();
+				if (typeid(float) == modValue.type())
+					sdModifierColumns[1]["value"] = llformat("%f", boost::get<float>(modValue));
+				else if (typeid(int) == modValue.type())
+					sdModifierColumns[1]["value"] = llformat("%d", boost::get<int>(modValue));
+			}
+			else
+			{
+				sdModifierColumns[1]["value"] = "(default)";
+			}
+
+			sdModifierColumns[2]["value"] = (pBhvrModifier->getPrimaryObject().notNull()) ? rlvGetItemNameFromObjID(pBhvrModifier->getPrimaryObject()) : LLStringUtil::null;
+			pModifierList->addElement(sdModifierRow, ADD_BOTTOM);
+		}
+	}
+}
+
+// ============================================================================
+// RlvFloaterLocks member functions
+//
+
+// Checked: 2010-03-11 (RLVa-1.2.0)
+void RlvFloaterLocks::onOpen(const LLSD& sdKey)
+{
+	m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterLocks::onRlvCommand, this, _1, _2));
+
+	refreshAll();
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0)
+void RlvFloaterLocks::onClose(bool fQuitting)
+{
+	m_ConnRlvCommand.disconnect();
+}
+
+// Checked: 2012-07-14 (RLVa-1.4.7)
+BOOL RlvFloaterLocks::postBuild()
+{
+	getChild<LLUICtrl>("refresh_btn")->setCommitCallback(boost::bind(&RlvFloaterLocks::refreshAll, this));
+
+	return TRUE;
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvFloaterLocks::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet)
+{
+	// Refresh on any successful @XXX=y|n command where XXX is any of the attachment or wearable locking behaviours
+	if ( (RLV_RET_SUCCESS == eRet) && ((RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType())) )
+	{
+		switch (rlvCmd.getBehaviourType())
+		{
+			case RLV_BHVR_DETACH:
+			case RLV_BHVR_ADDATTACH:
+			case RLV_BHVR_REMATTACH:
+			case RLV_BHVR_ADDOUTFIT:
+			case RLV_BHVR_REMOUTFIT:
+				refreshAll();
+				break;
+			default:
+				break;
+		}
+	}
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0)
+void RlvFloaterLocks::refreshAll()
+{
+	LLScrollListCtrl* pLockList = getChild<LLScrollListCtrl>("lock_list");
+	pLockList->operateOnAll(LLCtrlListInterface::OP_DELETE);
+
+	if (!isAgentAvatarValid())
+		return;
+
+	//
+	// Set-up a row we can just reuse
+	//
+	LLSD sdRow;
+	LLSD& sdColumns = sdRow["columns"];
+	sdColumns[0]["column"] = "lock_type";   sdColumns[0]["type"] = "text";
+	sdColumns[1]["column"] = "lock_addrem"; sdColumns[1]["type"] = "text";
+	sdColumns[2]["column"] = "lock_target"; sdColumns[2]["type"] = "text";
+	sdColumns[3]["column"] = "lock_origin"; sdColumns[3]["type"] = "text";
+
+	//
+	// List attachment locks
+	//
+	sdColumns[0]["value"] = "Attachment";
+	sdColumns[1]["value"] = "rem";
+
+	const RlvAttachmentLocks::rlv_attachobjlock_map_t& attachObjRem = gRlvAttachmentLocks.getAttachObjLocks();
+	for (RlvAttachmentLocks::rlv_attachobjlock_map_t::const_iterator itAttachObj = attachObjRem.begin(); 
+			itAttachObj != attachObjRem.end(); ++itAttachObj)
+	{
+		sdColumns[2]["value"] = rlvGetItemNameFromObjID(itAttachObj->first);
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachObj->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	//
+	// List attachment point locks
+	//
+	sdColumns[0]["value"] = "Attachment Point";
+
+	sdColumns[1]["value"] = "add";
+	const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtAdd = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_ADD);
+	for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtAdd.begin(); 
+			itAttachPt != attachPtAdd.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = 
+			get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL);
+		sdColumns[2]["value"] = pAttachPt->getName();
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	sdColumns[1]["value"] = "rem";
+	const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtRem = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_REMOVE);
+	for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtRem.begin(); 
+			itAttachPt != attachPtRem.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = 
+			get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL);
+		sdColumns[2]["value"] = pAttachPt->getName();
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	//
+	// List wearable type locks
+	//
+	sdColumns[0]["value"] = "Wearable Type";
+
+	sdColumns[1]["value"] = "add";
+	const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeAdd = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_ADD);
+	for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeAdd.begin(); 
+			itWearableType != wearableTypeAdd.end(); ++itWearableType)
+	{
+		sdColumns[2]["value"] = LLWearableType::getTypeLabel(itWearableType->first);
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	sdColumns[1]["value"] = "rem";
+	const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeRem = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_REMOVE);
+	for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeRem.begin(); 
+			itWearableType != wearableTypeRem.end(); ++itWearableType)
+	{
+		sdColumns[2]["value"] = LLWearableType::getTypeName(itWearableType->first);
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	//
+	// List "nostrip" (soft) locks
+	//
+	sdColumns[1]["value"] = "nostrip";
+	sdColumns[3]["value"] = "(Agent)";
+
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	LLFindWearablesEx f(true, true);
+	gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, FALSE, f);
+
+	for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
+	{
+		const LLViewerInventoryItem* pItem = *itItem;
+		if (!RlvForceWear::instance().isStrippable(pItem->getUUID()))
+		{
+			sdColumns[0]["value"] = rlvGetItemType(pItem);
+			sdColumns[2]["value"] = rlvGetItemName(pItem);
+
+			pLockList->addElement(sdRow, ADD_BOTTOM);
+		}
+	}
+
+	//
+	// List folder locks
+	//
+	{
+		// Folder lock descriptors
+		const RlvFolderLocks::folderlock_list_t& folderLocks = RlvFolderLocks::instance().getFolderLocks();
+		for (RlvFolderLocks::folderlock_list_t::const_iterator itFolderLock = folderLocks.begin(); 
+				itFolderLock != folderLocks.end(); ++itFolderLock)
+		{
+			const RlvFolderLocks::folderlock_descr_t* pLockDescr = *itFolderLock;
+			if (pLockDescr)
+			{
+				sdColumns[0]["value"] = "Folder Descriptor";
+				sdColumns[1]["value"] =
+					rlvLockMaskToString(pLockDescr->eLockType) + "/" +
+					rlvFolderLockPermissionToString(pLockDescr->eLockPermission) + "/" +
+					rlvFolderLockScopeToString(pLockDescr->eLockScope);
+				sdColumns[2]["value"] = rlvFolderLockSourceToTarget(pLockDescr->lockSource);
+				sdColumns[3]["value"] = rlvGetItemNameFromObjID(pLockDescr->idRlvObj);
+
+				pLockList->addElement(sdRow, ADD_BOTTOM);
+			}
+		}
+	}
+
+	{
+		// Folder locked attachments and wearables
+		uuid_vec_t idItems;
+		const uuid_vec_t& folderLockAttachmentsIds = RlvFolderLocks::instance().getAttachmentLookups();
+		idItems.insert(idItems.end(), folderLockAttachmentsIds.begin(), folderLockAttachmentsIds.end());
+		const uuid_vec_t& folderLockWearabels = RlvFolderLocks::instance().getWearableLookups();
+		idItems.insert(idItems.end(), folderLockWearabels.begin(), folderLockWearabels.end());
+
+		for (uuid_vec_t::const_iterator itItemId = idItems.begin(); itItemId != idItems.end(); ++itItemId)
+		{
+			const LLViewerInventoryItem* pItem = gInventory.getItem(*itItemId);
+			if (pItem)
+			{
+				sdColumns[0]["value"] = rlvGetItemType(pItem);
+				sdColumns[1]["value"] = rlvLockMaskToString(RLV_LOCK_REMOVE);
+				sdColumns[2]["value"] = rlvGetItemName(pItem);
+				sdColumns[3]["value"] = "<Folder Lock>";
+
+				pLockList->addElement(sdRow, ADD_BOTTOM);
+			}
+		}
+	}
+}
+
+// ============================================================================
+// RlvFloaterStrings member functions
+//
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+RlvFloaterStrings::RlvFloaterStrings(const LLSD& sdKey)
+	: LLFloater(sdKey)
+	, m_fDirty(false)
+	, m_pStringList(NULL)
+{
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+BOOL RlvFloaterStrings::postBuild()
+{
+	// Set up the UI controls
+	m_pStringList = findChild<LLComboBox>("string_list");
+	m_pStringList->setCommitCallback(boost::bind(&RlvFloaterStrings::checkDirty, this, true));
+
+	LLUICtrl* pDefaultBtn = findChild<LLUICtrl>("default_btn");
+	pDefaultBtn->setCommitCallback(boost::bind(&RlvFloaterStrings::onStringRevertDefault, this));
+
+	// Read all string metadata from the default strings file
+	llifstream fileStream(RlvStrings::getStringMapPath().c_str(), std::ios::binary); LLSD sdFileData;
+	if ( (fileStream.is_open()) && (LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) )
+	{
+		m_sdStringsInfo = sdFileData["strings"];
+		fileStream.close();
+	}
+
+	// Populate the combo box
+	for (LLSD::map_const_iterator itString = m_sdStringsInfo.beginMap(); itString != m_sdStringsInfo.endMap(); ++itString)
+	{
+		const LLSD& sdStringInfo = itString->second;
+		if ( (!sdStringInfo.has("customizable")) || (!sdStringInfo["customizable"].asBoolean()) )
+			continue;
+		m_pStringList->add( (sdStringInfo.has("label")) ? sdStringInfo["label"].asString() : itString->first, itString->first);
+	}
+	
+	refresh();
+
+	return TRUE;
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvFloaterStrings::onClose(bool fQuitting)
+{
+	checkDirty(false);
+	if (m_fDirty)
+	{
+		// Save the custom string overrides
+		RlvStrings::saveToFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE));
+
+		// Remind the user their changes require a relog to take effect
+		LLNotificationsUtil::add("RLVChangeStrings");
+	}
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvFloaterStrings::onStringRevertDefault()
+{
+	if (!m_strStringCurrent.empty())
+	{
+		RlvStrings::setCustomString(m_strStringCurrent, LLStringUtil::null);
+		m_fDirty = true;
+	}
+	refresh();
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvFloaterStrings::checkDirty(bool fRefresh)
+{
+	LLTextEditor* pStringValue = findChild<LLTextEditor>("string_value");
+	if (!pStringValue->isPristine())
+	{
+		RlvStrings::setCustomString(m_strStringCurrent, pStringValue->getText());
+		m_fDirty = true;
+	}
+
+	if (fRefresh)
+	{
+		refresh();
+	}
+}
+
+// Checked: 2011-11-08 (RLVa-1.5.0)
+void RlvFloaterStrings::refresh()
+{
+	m_strStringCurrent = (-1 != m_pStringList->getCurrentIndex()) ? m_pStringList->getSelectedValue().asString() : LLStringUtil::null;
+
+	LLTextEditor* pStringDescr = findChild<LLTextEditor>("string_descr");
+	pStringDescr->clear();
+	LLTextEditor* pStringValue = findChild<LLTextEditor>("string_value");
+	pStringValue->setEnabled(!m_strStringCurrent.empty());
+	pStringValue->clear();
+	if (!m_strStringCurrent.empty())
+	{
+		if (m_sdStringsInfo[m_strStringCurrent].has("description"))
+			pStringDescr->setText(m_sdStringsInfo[m_strStringCurrent]["description"].asString());
+		pStringValue->setText(RlvStrings::getString(m_strStringCurrent));
+		pStringValue->makePristine();
+	}
+
+	findChild<LLUICtrl>("default_btn")->setEnabled(!m_strStringCurrent.empty());
+}
+
+// ============================================================================
+// RlvFloaterConsole
+//
+
+static const char s_strRlvConsolePrompt[] = "> ";
+static const char s_strRlvConsoleDisabled[] = "RLVa is disabled";
+static const char s_strRlvConsoleInvalid[] = "Invalid command";
+
+RlvFloaterConsole::RlvFloaterConsole(const LLSD& sdKey)
+	: LLFloater(sdKey), m_pOutputText(nullptr)
+{
+}
+
+RlvFloaterConsole::~RlvFloaterConsole()
+{
+}
+
+BOOL RlvFloaterConsole::postBuild()
+{
+	LLLineEditor* pInputEdit = getChild<LLLineEditor>("console_input");
+	pInputEdit->setEnableLineHistory(true);
+	pInputEdit->setCommitCallback(boost::bind(&RlvFloaterConsole::onInput, this, _1, _2));
+	pInputEdit->setFocus(true);
+	pInputEdit->setCommitOnFocusLost(false);
+
+	m_pOutputText = getChild<LLTextEditor>("console_output");
+	m_pOutputText->appendText(s_strRlvConsolePrompt, false);
+
+	return TRUE;
+}
+
+void RlvFloaterConsole::onClose(bool fQuitting)
+{
+	gRlvHandler.processCommand(gAgent.getID(), "clear", true);
+}
+
+void RlvFloaterConsole::addCommandReply(const std::string& strCommand, const std::string& strReply)
+{
+	m_pOutputText->appendText(llformat("%s: ", strCommand.c_str()), true);
+	m_pOutputText->appendText(strReply, false);
+}
+
+void RlvFloaterConsole::onInput(LLUICtrl* pCtrl, const LLSD& sdParam)
+{
+	LLLineEditor* pInputEdit = static_cast<LLLineEditor*>(pCtrl);
+	std::string strInput = pInputEdit->getText();
+	LLStringUtil::trim(strInput);
+
+	m_pOutputText->appendText(strInput, false);
+	pInputEdit->clear();
+
+	if (!rlv_handler_t::isEnabled())
+	{
+		m_pOutputText->appendText(s_strRlvConsoleDisabled, true);
+	}
+	else if ( (strInput.length() <= 3) || (RLV_CMD_PREFIX != strInput[0]) )
+	{
+		m_pOutputText->appendText(s_strRlvConsoleInvalid, true);
+	}
+	else
+	{
+		strInput.erase(0, 1);
+		LLStringUtil::toLower(strInput);
+
+		std::string strExecuted, strFailed, strRetained, *pstr;
+
+		boost_tokenizer tokens(strInput, boost::char_separator<char>(",", "", boost::drop_empty_tokens));
+		for (std::string strCmd : tokens)
+		{
+			ERlvCmdRet eRet = gRlvHandler.processCommand(gAgent.getID(), strCmd, true);
+			if ( RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS) )	
+				pstr = &strExecuted;
+			else if ( RLV_RET_FAILED == (eRet & RLV_RET_FAILED) )
+				pstr = &strFailed;
+			else if (RLV_RET_RETAINED == eRet)
+				pstr = &strRetained;
+			else
+			{
+				RLV_ASSERT(false);
+				pstr = &strFailed;
+			}
+
+			if (const char* pstrSuffix = RlvStrings::getStringFromReturnCode(eRet))
+				strCmd.append(" (").append(pstrSuffix).append(")");
+			else if (RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS))
+				strCmd.clear(); // Only show feedback on successful commands when there's an informational notice
+
+			if (!pstr->empty())
+				pstr->push_back(',');
+			pstr->append(strCmd);
+		}
+
+		if (!strExecuted.empty())
+			m_pOutputText->appendText("INFO: @" + strExecuted, true);
+		if (!strFailed.empty())
+			m_pOutputText->appendText("ERR: @" + strFailed, true);
+		if (!strRetained.empty())
+			m_pOutputText->appendText("RET: @" + strRetained, true);
+	}
+
+	m_pOutputText->appendText(s_strRlvConsolePrompt, true);
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h
new file mode 100644
index 0000000000000000000000000000000000000000..8238aa68885e6d1b5308c10564a8acfbd9cd44ef
--- /dev/null
+++ b/indra/newview/rlvfloaters.h
@@ -0,0 +1,163 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_FLOATERS_H
+#define RLV_FLOATERS_H
+
+#include "llfloater.h"
+
+#include "rlvdefines.h"
+#include "rlvcommon.h"
+
+// ============================================================================
+// Foward declarations
+//
+class LLComboBox;
+class LLTextEditor;
+
+// ============================================================================
+// RlvFloaterLocks class declaration
+//
+
+class RlvFloaterBehaviours : public LLFloater
+{
+	friend class LLFloaterReg;
+private:
+	RlvFloaterBehaviours(const LLSD& sdKey) : LLFloater(sdKey) {}
+
+	/*
+	 * LLFloater overrides
+	 */
+public:
+	/*virtual*/ void onOpen(const LLSD& sdKey);
+	/*virtual*/ void onClose(bool fQuitting);
+	/*virtual*/ BOOL postBuild();
+
+	/*
+	 * Member functions
+	 */
+protected:
+	void onAvatarNameLookup(const LLUUID& idAgent, const LLAvatarName& avName);
+	void onBtnCopyToClipboard();
+	void onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet);
+	void refreshAll();
+
+	/*
+	 * Member variables
+	 */
+protected:
+	boost::signals2::connection	m_ConnRlvCommand;
+	uuid_vec_t 					m_PendingLookup;
+};
+
+// ============================================================================
+// RlvFloaterLocks class declaration
+//
+
+class RlvFloaterLocks : public LLFloater
+{
+	friend class LLFloaterReg;
+private:
+	RlvFloaterLocks(const LLSD& sdKey) : LLFloater(sdKey) {}
+
+	/*
+	 * LLFloater overrides
+	 */
+public:
+	/*virtual*/ void onOpen(const LLSD& sdKey);
+	/*virtual*/ void onClose(bool fQuitting);
+	/*virtual*/ BOOL postBuild();
+
+	/*
+	 * Member functions
+	 */
+protected:
+	void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet);
+	void refreshAll();
+
+	/*
+	 * Member variables
+	 */
+protected:
+	boost::signals2::connection m_ConnRlvCommand;
+};
+
+// ============================================================================
+// RlvFloaterStrings class declaration
+//
+
+class RlvFloaterStrings : public LLFloater
+{
+	friend class LLFloaterReg;
+private:
+	RlvFloaterStrings(const LLSD& sdKey);
+
+	// LLFloater overrides
+public:
+	/*virtual*/ void onClose(bool fQuitting);
+	/*virtual*/ BOOL postBuild();
+
+	// Member functions
+protected:
+	void onStringRevertDefault();
+	void checkDirty(bool fRefresh);
+	void refresh();
+
+	// Member variables
+protected:
+	bool		m_fDirty;
+	std::string m_strStringCurrent;
+	LLComboBox*	m_pStringList;
+	LLSD		m_sdStringsInfo;
+};
+
+// ============================================================================
+// RlvFloaterConsole - debug console to allow command execution without the need for a script
+//
+
+class RlvFloaterConsole : public LLFloater
+{
+	friend class LLFloaterReg;
+	template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl;
+	friend class RlvHandler;
+private:
+	RlvFloaterConsole(const LLSD& sdKey);
+	~RlvFloaterConsole() override;
+
+	/*
+	 * LLFloater overrides
+	 */
+public:
+	BOOL postBuild() override;
+	void onClose(bool fQuitting) override;
+	
+	/*
+	 * Member functions
+	 */
+protected:
+	void addCommandReply(const std::string& strCommand, const std::string& strReply);
+	void onInput(LLUICtrl* ctrl, const LLSD& param);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	LLTextEditor* m_pOutputText;
+};
+
+// ============================================================================
+
+#endif // RLV_FLOATERS_H
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3500252033bffcc9bcfc58eaf6dbbd30902960b8
--- /dev/null
+++ b/indra/newview/rlvhandler.cpp
@@ -0,0 +1,3162 @@
+/** 
+ *
+ * Copyright (c) 2009-2016, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+// Generic includes
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llappviewer.h"
+#include "llgroupactions.h"
+#include "llhudtext.h"
+#include "llmoveview.h"
+#include "llstartup.h"
+#include "llviewermessage.h"
+#include "llviewermenu.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+
+// Command specific includes
+#include "llagentcamera.h"				// @setcam and related
+#include "llavatarnamecache.h"			// @shownames
+#include "llavatarlist.h"				// @shownames
+#include "llenvmanager.h"				// @setenv
+#include "llfloatersidepanelcontainer.h"// @shownames
+#include "lloutfitslist.h"				// @showinv - "Appearance / My Outfits" panel
+#include "llpaneloutfitsinventory.h"	// @showinv - "Appearance" floater
+#include "llpanelpeople.h"				// @shownames
+#include "llpanelwearing.h"				// @showinv - "Appearance / Current Outfit" panel
+#include "llsidepanelappearance.h"		// @showinv - "Appearance / Edit appearance" panel
+#include "lltabcontainer.h"				// @showinv - Tab container control for inventory tabs
+#include "lltoolmgr.h"					// @edit
+#include "llviewercamera.h"				// @setcam and related
+#include "llworldmapmessage.h"			// @tpto
+#include "llviewertexturelist.h"		// @setcam_texture
+
+// RLVa includes
+#include "rlvactions.h"
+#include "rlvfloaters.h"
+#include "rlvactions.h"
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+#include "rlvinventory.h"
+#include "rlvlocks.h"
+#include "rlvui.h"
+#include "rlvextensions.h"
+
+// Boost includes
+#include <boost/algorithm/string.hpp>
+
+// ============================================================================
+// Static variable initialization
+//
+
+BOOL RlvHandler::m_fEnabled = FALSE;
+
+rlv_handler_t gRlvHandler;
+
+// ============================================================================
+// Command specific helper functions
+//
+
+// Checked: 2009-08-04 (RLVa-1.0.1d) | Added: RLVa-1.0.1d
+static bool rlvParseNotifyOption(const std::string& strOption, S32& nChannel, std::string& strFilter)
+{
+	boost_tokenizer tokens(strOption, boost::char_separator<char>(";", "", boost::keep_empty_tokens));
+	boost_tokenizer::const_iterator itTok = tokens.begin();
+
+	// Extract and sanity check the first token (required) which is the channel
+	if ( (itTok == tokens.end()) || (!LLStringUtil::convertToS32(*itTok, nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel)) )
+		return false;
+
+	// Second token (optional) is the filter
+	strFilter.clear();
+	if (++itTok != tokens.end())
+	{
+		strFilter = *itTok;
+		++itTok;
+	}
+
+	return (itTok == tokens.end());
+}
+
+// Checked: 2014-02-26 (RLVa-1.4.10)
+static bool rlvParseGetStatusOption(const std::string& strOption, std::string& strFilter, std::string& strSeparator)
+{
+	// @getstatus:[<option>][;<separator>]
+	//   * Parameters: first and second parameters are both optional
+	//   * Examples  : @getstatus=123 ; @getstatus:tp=123 ; @getstatus:tp;|=123 ; @getstatus:;|=123
+
+	boost_tokenizer tokens(strOption, boost::char_separator<char>(";", "", boost::keep_empty_tokens));
+	boost_tokenizer::const_iterator itTok = tokens.begin();
+
+	strSeparator = "/";
+	strFilter.clear();
+
+	// <option> optional parameter (defaults to empty string if unspecified)
+	if (itTok != tokens.end())
+		strFilter = *itTok++;
+	else
+		strFilter.clear();
+
+	// <separator> optional paramter (defaults to '/' if unspecified)
+	if ( (itTok != tokens.end()) && (!(*itTok).empty()) )
+		strSeparator = *itTok++;
+	else
+		strSeparator = "/";
+
+	return true;
+}
+
+// ============================================================================
+// Constructor/destructor
+//
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d
+RlvHandler::RlvHandler() : m_fCanCancelTp(true), m_posSitSource(), m_pGCTimer(NULL)
+{
+	gAgent.addListener(this, "new group");
+
+	// Array auto-initialization to 0 is still not supported in VS2013
+	memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT);
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d
+RlvHandler::~RlvHandler()
+{
+	gAgent.removeListener(this);
+
+	//delete m_pGCTimer;	// <- deletes itself
+}
+
+// ============================================================================
+// Behaviour related functions
+//
+
+bool RlvHandler::findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& lObjects) const
+{
+	lObjects.clear();
+	for (const auto& objEntry : m_Objects)
+		if (objEntry.second.hasBehaviour(eBhvr, false))
+			lObjects.push_back(&objEntry.second);
+	return !lObjects.empty();
+}
+
+bool RlvHandler::hasBehaviour(const LLUUID& idRlvObj, ERlvBehaviour eBhvr, const std::string& strOption) const
+{
+	rlv_object_map_t::const_iterator itObj = m_Objects.find(idRlvObj);
+	if (m_Objects.end() != itObj)
+		return itObj->second.hasBehaviour(eBhvr, strOption, false);
+	return false;
+}
+
+bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBhvr, const std::string& strOption, const LLUUID& idObj) const
+{
+	for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+		if ( (idObj != itObj->second.getObjectID()) && (itObj->second.hasBehaviour(eBhvr, strOption, false)) )
+			return true;
+	return false;
+}
+
+// Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
+bool RlvHandler::hasBehaviourRoot(const LLUUID& idObjRoot, ERlvBehaviour eBhvr, const std::string& strOption) const
+{
+	for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+		if ( (idObjRoot == itObj->second.getRootID()) && (itObj->second.hasBehaviour(eBhvr, strOption, false)) )
+			return true;
+	return false;
+}
+
+// ============================================================================
+// Behaviour exception handling
+//
+
+// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
+void RlvHandler::addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption)
+{
+	m_Exceptions.insert(std::pair<ERlvBehaviour, RlvException>(eBhvr, RlvException(idObj, eBhvr, varOption)));
+}
+
+// Checked: 2009-10-04 (RLVa-1.0.4c) | Modified: RLVa-1.0.4c
+bool RlvHandler::isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck) const
+{
+	// We need to "strict check" exceptions only if: the restriction is actually in place *and* (isPermissive(eBhvr) == FALSE)
+	if (RLV_CHECK_DEFAULT == typeCheck)
+		typeCheck = ( (hasBehaviour(eBhvr)) && (!isPermissive(eBhvr)) ) ? RLV_CHECK_STRICT : RLV_CHECK_PERMISSIVE;
+
+	uuid_vec_t objList;
+	if (RLV_CHECK_STRICT == typeCheck)
+	{
+		// If we're "strict checking" then we need the UUID of every object that currently has 'eBhvr' restricted
+		for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+			if (itObj->second.hasBehaviour(eBhvr, !hasBehaviour(RLV_BHVR_PERMISSIVE)))
+				objList.push_back(itObj->first);
+	}
+
+	for (rlv_exception_map_t::const_iterator itException = m_Exceptions.lower_bound(eBhvr), 
+			endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
+	{
+		if (itException->second.varOption == varOption)
+		{
+			// For permissive checks we just return on the very first match
+			if (RLV_CHECK_PERMISSIVE == typeCheck)
+				return true;
+
+			// For strict checks we don't return until the list is empty (every object with 'eBhvr' restricted also contains the exception)
+			uuid_vec_t::iterator itList = std::find(objList.begin(), objList.end(), itException->second.idObject);
+			if (itList != objList.end())
+				objList.erase(itList);
+			if (objList.empty())
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
+bool RlvHandler::isPermissive(ERlvBehaviour eBhvr) const
+{
+	return (RlvBehaviourDictionary::instance().getHasStrict(eBhvr)) 
+		? !((hasBehaviour(RLV_BHVR_PERMISSIVE)) || (isException(RLV_BHVR_PERMISSIVE, eBhvr, RLV_CHECK_PERMISSIVE)))
+		: true;
+}
+
+// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
+void RlvHandler::removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption)
+{
+	for (rlv_exception_map_t::iterator itException = m_Exceptions.lower_bound(eBhvr), 
+			endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
+	{
+		if ( (itException->second.idObject == idObj) && (itException->second.varOption == varOption) )
+		{
+			m_Exceptions.erase(itException);
+			break;
+		}
+	}
+}
+
+// ============================================================================
+// Command processing functions
+//
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+void RlvHandler::addCommandHandler(RlvExtCommandHandler* pCmdHandler)
+{
+	if ( (pCmdHandler) && (std::find(m_CommandHandlers.begin(), m_CommandHandlers.end(), pCmdHandler) == m_CommandHandlers.end()) )
+		m_CommandHandlers.push_back(pCmdHandler);
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+void RlvHandler::removeCommandHandler(RlvExtCommandHandler* pCmdHandler)
+{
+	if (pCmdHandler)
+		m_CommandHandlers.remove(pCmdHandler);
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0a
+void RlvHandler::clearCommandHandlers()
+{
+	std::list<RlvExtCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin();
+	while (itHandler != m_CommandHandlers.end())
+	{
+		delete *itHandler;
+		++itHandler;
+	}
+	m_CommandHandlers.clear();
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+bool RlvHandler::notifyCommandHandlers(rlvExtCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const
+{
+	std::list<RlvExtCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin(); bool fContinue = true; eRet = RLV_RET_UNKNOWN;
+	while ( (itHandler != m_CommandHandlers.end()) && ((fContinue) || (fNotifyAll)) )
+	{
+		ERlvCmdRet eCmdRet = RLV_RET_UNKNOWN;
+		if ((fContinue = !((*itHandler)->*f)(rlvCmd, eCmdRet)) == false)
+			eRet = eCmdRet;
+		++itHandler;
+	}
+	RLV_ASSERT( (fContinue) || (eRet != RLV_RET_UNKNOWN) );
+	return !fContinue;
+}
+
+// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::processCommand(const RlvCommand& rlvCmd, bool fFromObj)
+{
+	RLV_DEBUGS << "[" << rlvCmd.getObjectID() << "]: " << rlvCmd.asString() << RLV_ENDL;
+
+	if (!rlvCmd.isValid())
+	{
+		RLV_DEBUGS << "\t-> invalid syntax" << RLV_ENDL;
+		return RLV_RET_FAILED_SYNTAX;
+	}
+	if (rlvCmd.isBlocked())
+	{
+		RLV_DEBUGS << "\t-> blocked command" << RLV_ENDL;
+		return RLV_RET_FAILED_DISABLED;
+	}
+
+	// Using a stack for executing commands solves a few problems:
+	//   - if we passed RlvObject::m_idObj for idObj somewhere and process a @clear then idObj points to invalid/cleared memory at the end
+	//   - if command X triggers command Y along the way then getCurrentCommand()/getCurrentObject() still return Y even when finished
+	m_CurCommandStack.push(&rlvCmd); m_CurObjectStack.push(rlvCmd.getObjectID());
+	const LLUUID& idCurObj = m_CurObjectStack.top();
+
+	ERlvCmdRet eRet = RLV_RET_UNKNOWN;
+	switch (rlvCmd.getParamType())
+	{
+		case RLV_TYPE_ADD:		// Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			{
+				if ( (m_Behaviours[rlvCmd.getBehaviourType()]) && 
+					 ( (RLV_BHVR_SETCAM == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETDEBUG == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETENV == rlvCmd.getBehaviourType()) ) )
+				{
+					// Some restrictions can only be held by one single object to avoid deadlocks
+					RLV_DEBUGS << "\t- " << rlvCmd.getBehaviour() << " is already set by another object => discarding" << RLV_ENDL;
+					eRet = RLV_RET_FAILED_LOCK;
+					break;
+				}
+
+				rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fAdded = false;
+				if (itObj != m_Objects.end())
+				{
+					RlvObject& rlvObj = itObj->second;
+					fAdded = rlvObj.addCommand(rlvCmd);
+				}
+				else
+				{
+					RlvObject rlvObj(idCurObj);
+					fAdded = rlvObj.addCommand(rlvCmd);
+					itObj = m_Objects.insert(std::pair<LLUUID, RlvObject>(idCurObj, rlvObj)).first;
+				}
+
+				RLV_DEBUGS << "\t- " << ( (fAdded) ? "adding behaviour" : "skipping duplicate" ) << RLV_ENDL;
+
+				if (fAdded) {	// If FALSE then this was a duplicate, there's no need to handle those
+					if (!m_pGCTimer)
+						m_pGCTimer = new RlvGCTimer();
+					eRet = processAddRemCommand(rlvCmd);
+					if (!RLV_RET_SUCCEEDED(eRet))
+					{
+						RlvCommand rlvCmdRem(rlvCmd, RLV_TYPE_REMOVE);
+						itObj->second.removeCommand(rlvCmdRem);
+					}
+//					notifyBehaviourObservers(rlvCmd, !fFromObj);
+				}
+				else
+				{
+					eRet = RLV_RET_SUCCESS_DUPLICATE;
+				}
+			}
+			break;
+		case RLV_TYPE_REMOVE:		// Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			{
+				rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fRemoved = false;
+				if (itObj != m_Objects.end())
+					fRemoved = itObj->second.removeCommand(rlvCmd);
+
+				RLV_DEBUGS << "\t- " << ( (fRemoved) ? "removing behaviour"
+													 : "skipping remove (unset behaviour or unknown object)") << RLV_ENDL;
+
+				if (fRemoved) {	// Don't handle non-sensical removes
+					eRet = processAddRemCommand(rlvCmd);
+//					notifyBehaviourObservers(rlvCmd, !fFromObj);
+
+					if (0 == itObj->second.m_Commands.size())
+					{
+						RLV_DEBUGS << "\t- command list empty => removing " << idCurObj << RLV_ENDL;
+						m_Objects.erase(itObj);
+					}
+				}
+				else
+				{
+					eRet = RLV_RET_SUCCESS_UNSET;
+				}
+			}
+			break;
+		case RLV_TYPE_CLEAR:		// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			eRet = processClearCommand(rlvCmd);
+			break;
+		case RLV_TYPE_FORCE:		// Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			eRet = processForceCommand(rlvCmd);
+			break;
+		case RLV_TYPE_REPLY:		// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			eRet = processReplyCommand(rlvCmd);
+			break;
+		case RLV_TYPE_UNKNOWN:		// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+		default:
+			eRet = RLV_RET_FAILED_PARAM;
+			break;
+	}
+	RLV_ASSERT(RLV_RET_UNKNOWN != eRet);
+
+	m_OnCommand(rlvCmd, eRet, !fFromObj);
+
+	RLV_DEBUGS << "\t--> command " << ((eRet & RLV_RET_SUCCESS) ? "succeeded" : "failed") << RLV_ENDL;
+
+	m_CurCommandStack.pop(); m_CurObjectStack.pop();
+	return eRet;
+}
+
+// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj)
+{
+	if (STATE_STARTED != LLStartUp::getStartupState())
+	{
+		m_Retained.push_back(RlvCommand(idObj, strCommand));
+		return RLV_RET_RETAINED;
+	}
+	return processCommand(RlvCommand(idObj, strCommand), fFromObj);
+}
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f
+void RlvHandler::processRetainedCommands(ERlvBehaviour eBhvrFilter /*=RLV_BHVR_UNKNOWN*/, ERlvParamType eTypeFilter /*=RLV_TYPE_UNKNOWN*/)
+{
+	rlv_command_list_t::iterator itCmd = m_Retained.begin(), itCurCmd;
+	while (itCmd != m_Retained.end())
+	{
+		itCurCmd = itCmd++;  // Point the loop iterator ahead
+
+		const RlvCommand& rlvCmd = *itCurCmd;
+		if ( ((RLV_BHVR_UNKNOWN == eBhvrFilter) || (rlvCmd.getBehaviourType() == eBhvrFilter)) && 
+			 ((RLV_TYPE_UNKNOWN == eTypeFilter) || (rlvCmd.getParamType() == eTypeFilter)) )
+		{
+			processCommand(rlvCmd, true);
+			m_Retained.erase(itCurCmd);
+		}
+	}
+}
+
+ERlvCmdRet RlvHandler::processClearCommand(const RlvCommand& rlvCmd)
+{
+	const std::string& strFilter = rlvCmd.getParam(); std::string strCmdRem;
+
+	rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID());
+	if (itObj != m_Objects.end())	// No sense in clearing if we don't have any commands for this object
+	{
+		const RlvObject& rlvObj = itObj->second; bool fContinue = true;
+		for (rlv_command_list_t::const_iterator itCmd = rlvObj.m_Commands.begin(), itCurCmd; 
+				((fContinue) && (itCmd != rlvObj.m_Commands.end())); )
+		{
+			itCurCmd = itCmd++;		// Point itCmd ahead so it won't get invalidated if/when we erase a command
+
+			const RlvCommand& rlvCmdRem = *itCurCmd; strCmdRem = rlvCmdRem.asString();
+			if ( (strFilter.empty()) || (std::string::npos != strCmdRem.find(strFilter)) )
+			{
+				fContinue = (rlvObj.m_Commands.size() > 1); // rlvObj will become invalid once we remove the last command
+				processCommand(rlvCmd.getObjectID(), strCmdRem.append("=y"), false);
+			}
+		}
+	}
+
+	// Let our observers know about clear commands
+	ERlvCmdRet eRet = RLV_RET_SUCCESS;
+	notifyCommandHandlers(&RlvExtCommandHandler::onClearCommand, rlvCmd, eRet, true);
+
+	return RLV_RET_SUCCESS; // Don't fail clear commands even if the object didn't exist since it confuses people
+}
+
+// ============================================================================
+// Externally invoked event handlers
+//
+
+bool RlvHandler::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata)
+{
+	// NOTE: we'll fire once for every group the user belongs to so we need to manually keep track of pending changes
+	static LLUUID s_idLastAgentGroup = LLUUID::null;
+	static bool s_fGroupChanging = false;
+
+	if (s_idLastAgentGroup != gAgent.getGroupID())
+	{
+		s_idLastAgentGroup = gAgent.getGroupID();
+		s_fGroupChanging = false;
+	}
+
+	// If the user managed to change their active group (= newly joined or created group) we need to reactivate the previous one
+	if ( (!RlvActions::canChangeActiveGroup()) && ("new group" == event->desc()) && (m_idAgentGroup != gAgent.getGroupID()) )
+	{
+		// Make sure they still belong to the group
+		if ( (m_idAgentGroup.notNull()) && (!gAgent.isInGroup(m_idAgentGroup)) )
+		{
+			m_idAgentGroup.setNull();
+			s_fGroupChanging = false;
+		}
+
+		if (!s_fGroupChanging)
+		{
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_GROUPCHANGE, LLSD().with("GROUP_SLURL", (m_idAgentGroup.notNull()) ? llformat("secondlife:///app/group/%s/about", m_idAgentGroup.asString()) : "(none)"));
+
+			// [Copy/paste from LLGroupActions::activate()]
+			LLMessageSystem* msg = gMessageSystem;
+			msg->newMessageFast(_PREHASH_ActivateGroup);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+			msg->addUUIDFast(_PREHASH_GroupID, m_idAgentGroup);
+			gAgent.sendReliableMessage();
+			s_fGroupChanging = true;
+			return true;
+		}
+	}
+	else
+	{
+		m_idAgentGroup = gAgent.getGroupID();
+	}
+	return false;
+}
+
+// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvHandler::onSitOrStand(bool fSitting)
+{
+	if (rlv_handler_t::isEnabled())
+	{
+		RlvSettings::updateLoginLastLocation();
+	}
+
+	if ( (hasBehaviour(RLV_BHVR_STANDTP)) && (!fSitting) && (!m_posSitSource.isExactlyZero()) )
+	{
+		// NOTE: we need to do this due to the way @standtp triggers a forced teleport:
+		//   - when standing we're called from LLVOAvatar::sitDown() which is called from LLVOAvatar::getOffObject()
+		//   -> at the time sitDown() is called the avatar's parent is still the linkset it was sitting on so "isRoot()" on the avatar will
+		//      return FALSE and we will crash in LLVOAvatar::getRenderPosition() when trying to teleport
+		//   -> postponing the teleport until the next idle tick will ensure that everything has all been properly cleaned up
+		doOnIdleOneTime(boost::bind(RlvUtil::forceTp, m_posSitSource));
+		m_posSitSource.setZero();
+	}
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvHandler::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	// Assertion - pAttachObj is never NULL always specifies the root
+	RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) );
+	// Sanity check - we need to be called *after* LLViewerJointAttachment::addObject()
+	RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) );
+	if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) )
+		return;
+
+	// Check if we already have an RlvObject instance for this object or one of its child prims
+	for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+	{
+		// Only if we haven't been able to find this object (= attachment that rezzed in) or if it's a rezzed prim attached from in-world
+		if ( (!itObj->second.m_fLookup) || (!itObj->second.m_idxAttachPt) )
+		{
+			const LLViewerObject* pObj = gObjectList.findObject(itObj->first);
+			if ( (pObj) && (pObj->getRootEdit()->getID() == pAttachObj->getID()) )
+			{
+				// Reset any lookup information we might have for this object
+				itObj->second.m_fLookup = true;
+				itObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj);
+				itObj->second.m_idRoot = pAttachObj->getID();
+
+				// We need to check this object for an active "@detach=n" and actually lock it down now that it's been attached somewhere
+				if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false))
+					gRlvAttachmentLocks.addAttachmentLock(pAttachObj->getID(), itObj->second.getObjectID());
+			}
+		}
+	}
+
+	// Fetch the inventory item if it isn't already (we need it in case of a reattach-on-detach) and rename it if appropriate
+	if ( (STATE_STARTED == LLStartUp::getStartupState()) && (gInventory.isInventoryUsable()) )
+	{
+		RlvRenameOnWearObserver* pFetcher = new RlvRenameOnWearObserver(pAttachObj->getAttachmentItemID());
+		pFetcher->startFetch();
+		if (pFetcher->isFinished())
+			pFetcher->done();
+		else
+			gInventory.addObserver(pFetcher);
+	}
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvHandler::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	// Assertion - pAttachObj is never NULL always specifies the root
+	RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) );
+	// Sanity check - we need to be called *before* LLViewerJointAttachment::removeObject()
+	RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) );
+	if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) )
+		return;
+
+	// If the attachment is no longer attached then then the user "Drop"'ed this attachment somehow
+	if (!pAttachObj->isAttachment())
+	{
+		// Check if we have any RlvObject instances for this object (or any of its child prims)
+		for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+		{
+			if ( (itObj->second.m_fLookup) && (itObj->second.m_idRoot == pAttachObj->getID()) )
+			{
+				// Clear the attachment point lookup since it's now an in-world prim
+				itObj->second.m_idxAttachPt = false;
+
+				// If this object has an active "@detach=n" then we need to release the attachment lock since it's no longer attached
+				if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false))
+					gRlvAttachmentLocks.removeAttachmentLock(pAttachObj->getID(), itObj->second.getObjectID());
+			}
+		}
+	}
+	else
+	{
+		// If it's still attached then we need to clean up any restrictions this object (or one of its child prims) may still have set
+		rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj;
+		while (itObj != m_Objects.end())
+		{
+			itCurObj = itObj++;	// @clear will invalidate our iterator so point it ahead now
+#ifdef RLV_DEBUG
+			bool itObj = true;
+			RLV_ASSERT(itObj);	// Little hack to push itObj out of scope and prevent it from being accidentally used below
+#endif // RLV_DEBUG
+
+			// NOTE: ObjectKill seems to happen in reverse (child prims are killed before the root is) so we can't use gObjectList here
+			if (itCurObj->second.m_idRoot == pAttachObj->getID())
+			{
+				RLV_INFOS << "Clearing " << itCurObj->first.asString() << ":" << RLV_ENDL;
+				processCommand(itCurObj->second.getObjectID(), "clear", true);
+				RLV_INFOS << "\t-> done" << RLV_ENDL;
+			}
+		}
+	}
+}
+
+// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvHandler::onGC()
+{
+	rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj;
+	while (itObj != m_Objects.end())
+	{
+		itCurObj = itObj++;	// @clear will invalidate our iterator so point it ahead now
+#ifdef RLV_DEBUG
+		bool itObj = true;
+		RLV_ASSERT(itObj);
+#endif // RLV_DEBUG
+
+		// Temporary sanity check
+		RLV_ASSERT(itCurObj->first == itCurObj->second.getObjectID());
+
+		const LLViewerObject* pObj = gObjectList.findObject(itCurObj->second.getObjectID());
+		if (!pObj)
+		{
+			// If the RlvObject once existed in gObjectList and now doesn't then expire it right away
+			// If the RlvObject never existed in gObjectList and still doesn't then increase its "lookup misses" counter
+			// but if that reaches 20 (we run every 30 seconds so that's about 10 minutes) then we'll expire it too
+			if ( (itCurObj->second.m_fLookup) || (++itCurObj->second.m_nLookupMisses > 20) )
+			{
+				RLV_INFOS << "Garbage collecting " << itCurObj->first.asString() << ":" << RLV_ENDL;
+				processCommand(itCurObj->first, "clear", true);
+				RLV_INFOS << "\t-> done" << RLV_ENDL;
+			}
+		}
+		else
+		{
+			// Assertion: if the GC encounters an RlvObject instance that hasn't existed in gObjectList up until now then
+			//            it has to be a rezzed prim (if it was an attachment then RlvHandler::onAttach() should have caught it)
+			RLV_ASSERT( (itCurObj->second.m_fLookup) || (!pObj->isAttachment()) );
+			if (!itCurObj->second.m_fLookup)
+			{
+				RLV_INFOS << "Resolved missing object " << itCurObj->first.asString() << RLV_ENDL;
+				itCurObj->second.m_fLookup = true;
+				itCurObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pObj);
+				itCurObj->second.m_idRoot = pObj->getRootEdit()->getID();
+
+				// NOTE: the following code should NEVER run (see assertion above), but just to be double-triple safety sure
+				//	-> if it does run it likely means that there's a @detach=n in a *child* prim that we couldn't look up in onAttach()
+				//  -> since RLV doesn't currently support @detach=n from child prims it's actually not such a big deal right now but still
+				if ( (pObj->isAttachment()) && (itCurObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) )
+					gRlvAttachmentLocks.addAttachmentLock(pObj->getID(), itCurObj->second.getObjectID());
+			}
+		}
+	}
+
+	RLV_ASSERT(gRlvAttachmentLocks.verifyAttachmentLocks()); // Verify that we haven't leaked any attachment locks somehow
+
+	return (0 != m_Objects.size());	// GC will kill itself if it has nothing to do
+}
+
+// Checked: 2009-11-26 (RLVa-1.1.0f) | Added: RLVa-1.1.0f
+void RlvHandler::onIdleStartup(void* pParam)
+{
+	LLTimer* pTimer = (LLTimer*)pParam;
+	if (LLStartUp::getStartupState() < STATE_STARTED)
+	{
+		// We don't want to run this *too* often
+		if ( (LLStartUp::getStartupState() >= STATE_MISC) && (pTimer->getElapsedTimeF32() >= 2.0) )
+		{
+			gRlvHandler.processRetainedCommands(RLV_BHVR_VERSION, RLV_TYPE_REPLY);
+			gRlvHandler.processRetainedCommands(RLV_BHVR_VERSIONNEW, RLV_TYPE_REPLY);
+			gRlvHandler.processRetainedCommands(RLV_BHVR_VERSIONNUM, RLV_TYPE_REPLY);
+			pTimer->reset();
+		}
+	}
+	else
+	{
+		// Clean-up
+		gIdleCallbacks.deleteFunction(onIdleStartup, pParam);
+		delete pTimer;
+	}
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvHandler::onLoginComplete()
+{
+	RlvInventory::instance().fetchWornItems();
+	RlvInventory::instance().fetchSharedInventory();
+	RlvSettings::updateLoginLastLocation();
+
+	LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&RlvHandler::onTeleportFailed, this));
+	LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&RlvHandler::onTeleportFinished, this, _1));
+
+	processRetainedCommands();
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+void RlvHandler::onTeleportFailed()
+{
+	setCanCancelTp(true);
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+void RlvHandler::onTeleportFinished(const LLVector3d& posArrival)
+{
+	setCanCancelTp(true);
+}
+
+// ============================================================================
+// String/chat censoring functions
+//
+
+// Checked: 2010-04-11 (RLVa-1.3.0h) | Modified: RLVa-1.3.0h
+bool RlvHandler::canTouch(const LLViewerObject* pObj, const LLVector3& posOffset /*=LLVector3::zero*/) const
+{
+	const LLUUID& idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null;
+	bool fCanTouch = (idRoot.notNull()) && ((pObj->isHUDAttachment()) || (!hasBehaviour(RLV_BHVR_TOUCHALL))) &&
+		((!hasBehaviour(RLV_BHVR_TOUCHTHIS)) || (!isException(RLV_BHVR_TOUCHTHIS, idRoot, RLV_CHECK_PERMISSIVE)));
+
+	static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST);
+	if (fCanTouch)
+	{
+		if ( (!pObj->isAttachment()) || (!pObj->permYouOwner()) )
+		{
+			// User can touch an object (that's isn't one of their own attachments) if:
+			//   - it's an in-world object and they're not prevented from touching it (or the object is an exception)
+			//   - it's an attachment and they're not prevented from touching (another avatar's) attachments (or the attachment is an exception)
+			//   - not fartouch restricted (or the object is within the currently enforced fartouch distance)
+			fCanTouch =
+				( (!pObj->isAttachment()) ? (!hasBehaviour(RLV_BHVR_TOUCHWORLD)) || (isException(RLV_BHVR_TOUCHWORLD, idRoot, RLV_CHECK_PERMISSIVE))
+				                          : ((!hasBehaviour(RLV_BHVR_TOUCHATTACH)) && (!hasBehaviour(RLV_BHVR_TOUCHATTACHOTHER))) || (isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE)) ) &&
+				( (!hasBehaviour(RLV_BHVR_FARTOUCH)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= s_nFartouchDist * s_nFartouchDist) );
+		}
+		else if (!pObj->isHUDAttachment())
+		{
+			// Regular attachment worn by this avie
+			fCanTouch =
+				((!hasBehaviour(RLV_BHVR_TOUCHATTACH)) || (isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE))) &&
+				((!hasBehaviour(RLV_BHVR_TOUCHATTACHSELF)) || (isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE)));
+		}
+		else
+		{
+			// HUD attachment
+			fCanTouch = (!hasBehaviour(RLV_BHVR_TOUCHHUD)) || (isException(RLV_BHVR_TOUCHHUD, idRoot, RLV_CHECK_PERMISSIVE));
+		}
+	}
+	if ( (!fCanTouch) && (hasBehaviour(RLV_BHVR_TOUCHME)) )
+		fCanTouch = hasBehaviourRoot(idRoot, RLV_BHVR_TOUCHME);
+	return fCanTouch;
+}
+
+size_t utf8str_strlen(const std::string& utf8)
+{
+	const char* pUTF8 = utf8.c_str(); size_t length = 0;
+	for (int idx = 0, cnt = utf8.length(); idx < cnt ;idx++)
+	{
+		// We're looking for characters that don't start with 10 as their high bits
+		if ((pUTF8[idx] & 0xC0) != 0x80)
+			length++;
+	}
+	return length;
+}
+
+std::string utf8str_chtruncate(const std::string& utf8, size_t length)
+{
+	if (0 == length)
+		return std::string();
+	if (utf8.length() <= length)
+		return utf8;
+
+	const char* pUTF8 = utf8.c_str(); int idx = 0;
+	while ( (pUTF8[idx]) && (length > 0) )
+	{
+		// We're looking for characters that don't start with 10 as their high bits
+		if ((pUTF8[idx] & 0xC0) != 0x80)
+			length--;
+		idx++;
+	}
+
+	return utf8.substr(0, idx);
+}
+
+// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0f
+bool RlvHandler::filterChat(std::string& strUTF8Text, bool fFilterEmote) const
+{
+	if (strUTF8Text.empty())
+		return false;
+
+	bool fFilter = false;
+	if (RlvUtil::isEmote(strUTF8Text))				// Check if it's an emote
+	{
+		if (fFilterEmote)							// Emote filtering depends on fFilterEmote
+		{
+			if ( (strUTF8Text.find_first_of("\"()*=^_?~") != std::string::npos) || 
+				 (strUTF8Text.find(" -") != std::string::npos) || (strUTF8Text.find("- ") != std::string::npos) || 
+				 (strUTF8Text.find("''") != std::string::npos) )
+			{
+				fFilter = true;						// Emote contains illegal character (or character sequence)
+			}
+			else if (!hasBehaviour(RLV_BHVR_EMOTE))
+			{
+				int idx = strUTF8Text.find('.');	// Truncate at 20 characters or at the dot (whichever is shorter)
+				strUTF8Text = utf8str_chtruncate(strUTF8Text, ( (idx > 0) && (idx < 20) ) ? idx + 1 : 20);
+			}
+		}
+	} 
+	else if (strUTF8Text[0] == '/')					// Not an emote, but starts with a '/'
+	{
+		fFilter = (utf8str_strlen(strUTF8Text) > 7);// Allow as long if it's 6 characters or less
+	}
+	else if ( (!RlvSettings::getCanOOC()) ||
+			  (strUTF8Text.length() < 4) || (strUTF8Text.compare(0, 2, "((")) || (strUTF8Text.compare(strUTF8Text.length() - 2, 2, "))")) )
+	{
+		fFilter = true;								// Regular chat (not OOC)
+	}
+
+	if (fFilter)
+		strUTF8Text = (gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) ? "..." : "";
+	return fFilter;
+}
+
+// Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c
+bool RlvHandler::hasException(ERlvBehaviour eBhvr) const
+{
+	return (m_Exceptions.find(eBhvr) != m_Exceptions.end());
+}
+
+// Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a
+bool RlvHandler::redirectChatOrEmote(const std::string& strUTF8Text) const
+{
+	// Sanity check - @redirchat only for chat and @rediremote only for emotes
+	ERlvBehaviour eBhvr = (!RlvUtil::isEmote(strUTF8Text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE;
+	if ( (strUTF8Text.empty()) || (!hasBehaviour(eBhvr)) )
+		return false;
+
+	if (RLV_BHVR_REDIRCHAT == eBhvr)
+	{
+		std::string strText = strUTF8Text;
+		if (!filterChat(strText, false))
+			return false;	// @sendchat wouldn't filter it so @redirchat won't redirect it either
+	}
+
+	for (rlv_exception_map_t::const_iterator itRedir = m_Exceptions.lower_bound(eBhvr), 
+			endRedir = m_Exceptions.upper_bound(eBhvr); itRedir != endRedir; ++itRedir)
+	{
+		S32 nChannel = boost::get<S32>(itRedir->second.varOption);
+		if (RlvActions::canSendChannel(nChannel))
+			RlvUtil::sendChatReply(nChannel, strUTF8Text);
+	}
+
+	return true;
+}
+
+// ============================================================================
+// Composite folders
+//
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const
+	{
+		if (pFolder)
+		{
+			// Composite folder naming: ^\.?[Folder]
+			const std::string& cstrFolder = pFolder->getName();
+			std::string::size_type idxStart = cstrFolder.find('['), idxEnd = cstrFolder.find(']', idxStart);
+			if ( ((0 == idxStart) || (1 == idxStart)) && (idxEnd - idxStart > 1) )
+			{
+				if (pstrName)
+					pstrName->assign(cstrFolder.substr(idxStart + 1, idxEnd - idxStart - 1));
+				return true;
+			}
+		}
+		return false;
+	}
+
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const
+	{
+/*
+		LLViewerInventoryCategory* pRlvRoot; LLViewerInventoryItem* pItem;
+		if ( (idItem.notNull()) && ((pRlvRoot = getSharedRoot()) != NULL) && 
+			 (gInventory.isObjectDescendentOf(idItem, pRlvRoot->getUUID())) && ((pItem = gInventory.getItem(idItem)) != NULL) )
+		{
+			// We know it's an item in a folder under the shared root (we need its parent if it's a folded folder)
+			LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+			if (isFoldedFolder(pFolder, true, false))	// Don't check if the folder is a composite folder
+				pFolder = gInventory.getCategory(pFolder->getParentUUID());
+
+			if ( (pFolder) && (getCompositeInfo(pFolder, pstrName)) )
+			{
+				if (ppFolder)
+					*ppFolder = pFolder;
+				return true;
+			}
+		}
+*/
+		return false;
+	}
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITE_FOLDING
+	// Checked:
+	inline bool RlvHandler::isHiddenCompositeItem(const LLUUID& idItem, const std::string& cstrItemType) const
+	{
+		// An item that's part of a composite folder will be hidden from @getoutfit and @getattach if:
+		//   (1) the composite name specifies either a wearable layer or an attachment point
+		//   (2) the specified wearable layer or attachment point is worn and resides in the folder
+		//   (3) cstrItemType isn't the specified wearable layer or attach point
+		//
+		// Example: #RLV/Separates/Shoes/ChiChi Pumps/.[shoes] with items: "Shoe Base", "Shoe (left foot)" and "Shoe (right foot)"
+		//   -> as long as "Shoe Base" is worn, @getattach should not reflect "left foot", nor "right foot"
+		std::string strComposite; LLViewerInventoryCategory* pFolder;
+		LLWearableType::EType type; S32 idxAttachPt;
+		if ( (getCompositeInfo(idItem, &strComposite, &pFolder)) && (cstrItemType != strComposite) )
+		{
+			LLUUID idCompositeItem;
+			if ((type = LLWearable::typeNameToType(strComposite)) != WT_INVALID)
+			{
+				idCompositeItem = gAgent.getWearableItem(type);
+			}
+			else if ((idxAttachPt = getAttachPointIndex(strComposite, true)) != 0)
+			{
+				LLVOAvatar* pAvatar; LLViewerJointAttachment* pAttachmentPt;
+				if ( ((pAvatar = gAgent.getAvatarObject()) != NULL) && 
+					 ((pAttachmentPt = get_if_there(pAvatar->mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL)) != NULL) )
+				{
+					idCompositeItem = pAttachmentPt->getItemID();
+				}
+			}
+
+			if ( (idCompositeItem.notNull()) && (gInventory.isObjectDescendentOf(idCompositeItem, pFolder->getUUID())) )
+				return true;
+		}
+		return false;
+	}
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDING
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::canTakeOffComposite(const LLInventoryCategory* pFolder) const
+	{
+		// Sanity check - if there's no folder or no avatar then there is nothing to take off
+		LLVOAvatarSelf* pAvatar = gAgent.getAvatarObject();
+		if ( (!pFolder) || (!pAvatar) )
+			return false;
+		// Sanity check - if nothing is locked then we can definitely take it off
+		if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) || 
+			 (!gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_REMOVE)) )
+		{
+			return true;
+		}
+
+/*
+		LLInventoryModel::cat_array_t folders;
+		LLInventoryModel::item_array_t items;
+		RlvWearableItemCollector functor(pFolder->getUUID(), true, false);
+		gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor);
+
+		for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+		{
+			const LLViewerInventoryItem* pItem = items.get(idxItem);
+			switch (pItem->getType())
+			{
+				case LLAssetType::AT_BODYPART:
+				case LLAssetType::AT_CLOTHING:
+					{
+						LLWearable* pWearable = gAgent.getWearableFromWearableItem(pItem->getUUID());
+						if ( (pWearable) && (!isRemovable(pWearable->getType())) )
+							return false;	// If one wearable in the folder is non-removeable then the entire folder should be
+					}
+					break;
+				case LLAssetType::AT_OBJECT:
+					{
+						LLViewerObject* pObj = pAvatar->getWornAttachment(pItem->getUUID());
+						if ( (pObj != NULL) && (isLockedAttachment(pObj, RLV_LOCK_REMOVE)) )
+							return false;	// If one attachment in the folder is non-detachable then the entire folder should be
+					}
+					break;
+				default:
+					break;
+			}
+		}
+*/
+		return true;
+	}
+
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::canWearComposite(const LLInventoryCategory* pFolder) const
+	{
+		// Sanity check - if there's no folder or no avatar then there is nothing to wear
+		LLVOAvatar* pAvatar = gAgent.getAvatarObject();
+		if ( (!pFolder) || (!pAvatar) )
+			return false;
+		// Sanity check - if nothing is locked then we can definitely wear it
+		if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (!gRlvWearableLocks.hacLockedWearableType(RLV_LOCK_ANY)) )
+			return true;
+
+/*
+		LLInventoryModel::cat_array_t folders;
+		LLInventoryModel::item_array_t items;
+		RlvWearableItemCollector functor(pFolder->getUUID(), true, false);
+		gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor);
+
+		for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+		{
+			LLViewerInventoryItem* pItem = items.get(idxItem);
+
+			if (RlvForceWear::isWearingItem(pItem))
+				continue; // Don't examine any items we're already wearing
+
+			// A wearable layer or attachment point:
+			//   - can't be "add locked"
+			//   - can't be worn and "remove locked"
+			//   - can't be worn and have its item belong to a *different* composite folder that we can't take off
+			switch (pItem->getType())
+			{
+				case LLAssetType::AT_BODYPART:
+				case LLAssetType::AT_CLOTHING:
+					{
+						// NOTE: without its asset we don't know what type the wearable is so we need to look at the item's flags instead
+						LLWearableType::EType wtType = (LLWearableType::EType)(pItem->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK);
+						LLViewerInventoryCategory* pFolder;
+						if ( (!isWearable(wtType)) ||
+							 ( (gAgent.getWearable(wtType)) && (!isRemovable(wtType)) ) || 
+							 ( (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) &&
+							   (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) )
+						{
+							return false;
+						}
+					}
+					break;
+				case LLAssetType::AT_OBJECT:
+					{
+						// If we made it here then *something* is add/remove locked so we absolutely need to know its attachment point
+						LLViewerJointAttachment* pAttachPt = getAttachPoint(pItem, true); 
+						LLViewerInventoryCategory* pFolder;
+						if ( (!pAttachPt) || (isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ||
+							 ( (pAttachPt->getObject()) && (isLockedAttachment(pAttachPt, RLV_LOCK_REMOVE)) ) ||
+							 ( (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) &&
+							   (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) )
+						{
+							return false;
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+*/
+		return true;
+	}
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+// ============================================================================
+// Initialization helper functions
+//
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+BOOL RlvHandler::setEnabled(BOOL fEnable)
+{
+	// TODO-RLVa: [RLVa-1.2.1] Allow toggling at runtime if we haven't seen any llOwnerSay("@....");
+	if (m_fEnabled == fEnable)
+		return fEnable;
+
+	if (fEnable)
+	{
+		RLV_INFOS << "Enabling Restrained Love API support - " << RlvStrings::getVersionAbout() << RLV_ENDL;
+		m_fEnabled = TRUE;
+
+		// Initialize static classes
+		RlvSettings::initClass();
+		RlvStrings::initClass();
+
+		gRlvHandler.addCommandHandler(new RlvExtGetSet());
+
+		// Make sure we get notified when login is successful
+		if (LLStartUp::getStartupState() < STATE_STARTED)
+			LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&RlvHandler::onLoginComplete, &gRlvHandler));
+		else
+			gRlvHandler.onLoginComplete();
+
+		// Set up RlvUIEnabler
+		RlvUIEnabler::getInstance();
+
+		// Reset to show assertions if the viewer version changed
+		if (gSavedSettings.getString("LastRunVersion") != gLastRunVersion)
+			gSavedSettings.setBOOL("RLVaShowAssertionFailures", TRUE);
+	}
+
+	return m_fEnabled;
+}
+
+BOOL RlvHandler::canDisable()
+{
+	return FALSE;
+}
+
+void RlvHandler::clearState()
+{
+/*
+	// TODO-RLVa: should restore all RLV controlled debug variables to their defaults
+
+	// Issue @clear on behalf of every object that has a currently active RLV restriction (even if it's just an exception)
+	LLUUID idObj; LLViewerObject* pObj; bool fDetachable;
+	while (m_Objects.size())
+	{
+		idObj = m_Objects.begin()->first; // Need a copy since after @clear the data it points to will no longer exist
+		fDetachable = ((pObj = gObjectList.findObject(idObj)) != NULL) ? isLockedAttachment(pObj, RLV_LOCK_REMOVE) : true;
+
+		processCommand(idObj, "clear", false);
+		if (!fDetachable)
+			processCommand(idObj, "detachme=force", false);
+	}
+
+	// Sanity check - these should all be empty after we issue @clear on the last object
+	if ( (!m_Objects.empty()) || !(m_Exceptions.empty()) || (!m_AttachAdd.empty()) || (!m_AttachRem.empty()) )
+	{
+		RLV_ERRS << "Object, exception or attachment map not empty after clearing state!" << LL_ENDL;
+		m_Objects.clear();
+		m_Exceptions.clear();
+		m_AttachAdd.clear();
+		m_AttachRem.clear();
+	}
+
+	// These all need manual clearing
+	memset(m_LayersAdd, 0, sizeof(S16) * WT_COUNT);
+	memset(m_LayersRem, 0, sizeof(S16) * WT_COUNT);
+	memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT);
+	m_Retained.clear();
+	clearCommandHandlers(); // <- calls delete on all registered command handlers
+
+	// Clear dynamically allocated memory
+	delete m_pGCTimer;
+	m_pGCTimer = NULL;
+*/
+}
+
+// ============================================================================
+// Command handlers (RLV_TYPE_ADD and RLV_TYPE_REMOVE)
+//
+
+#define VERIFY_OPTION(x)		{ if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } }
+#define VERIFY_OPTION_REF(x)	{ if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } fRefCount = true; }
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+ERlvCmdRet RlvHandler::processAddRemCommand(const RlvCommand& rlvCmd)
+{
+	// NOTE: - at this point the command has already been:
+	//            * added to the RlvObject
+	//            * removed from the RlvObject (which still exists at this point even if this is the last restriction)
+	//       - the object's UUID may or may not exist in gObjectList (see handling of @detach=n|y)
+
+	// Try a command processor first
+	ERlvCmdRet eRet = rlvCmd.processCommand();
+	if (RLV_RET_NO_PROCESSOR != eRet)
+	{
+		return eRet;
+	}
+
+	// Process the command the legacy way
+	ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); ERlvParamType eType = rlvCmd.getParamType();
+	
+	eRet = RLV_RET_SUCCESS; bool fRefCount = false; const std::string& strOption = rlvCmd.getOption();
+	switch (eBhvr)
+	{
+		case RLV_BHVR_ATTACHTHIS:			// @attachthis[:<option>]=n|y
+		case RLV_BHVR_DETACHTHIS:			// @detachthis[:<option>]=n|y
+			eRet = onAddRemFolderLock(rlvCmd, fRefCount);
+			break;
+		case RLV_BHVR_ATTACHTHISEXCEPT:		// @attachthisexcept[:<option>]=n|y
+		case RLV_BHVR_DETACHTHISEXCEPT:		// @detachthisexcept[:<option>]=n|y
+			eRet = onAddRemFolderLockException(rlvCmd, fRefCount);
+			break;
+		case RLV_BHVR_ADDOUTFIT:			// @addoutfit[:<layer>]=n|y			- Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+		case RLV_BHVR_REMOUTFIT:			// @remoutfit[:<layer>]=n|y			- Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+			{
+				// If there's an option it should specify a wearable type name (reference count on no option *and* a valid option)
+				RlvCommandOptionGeneric rlvCmdOption;
+				RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption);
+				VERIFY_OPTION_REF( (rlvCmdOption.isEmpty()) || (rlvCmdOption.isWearableType()) );
+
+				// We need to flush any queued force-wear commands before changing the restrictions
+				if (RlvForceWear::instanceExists())
+					RlvForceWear::instance().done();
+
+				ERlvLockMask eLock = (RLV_BHVR_ADDOUTFIT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE;
+				for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++)
+				{
+					if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType()) )
+					{
+						if (RLV_TYPE_ADD == eType)
+							gRlvWearableLocks.addWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock);
+						else
+							gRlvWearableLocks.removeWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock);
+					}
+				}
+			}
+			break;
+		case RLV_BHVR_SHAREDWEAR:			// @sharedwear=n|y					- Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+		case RLV_BHVR_SHAREDUNWEAR:			// @sharedunwear=n|y				- Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+			{
+				VERIFY_OPTION_REF(strOption.empty());
+
+				RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_SHAREDPATH, LLStringUtil::null);
+				RlvFolderLocks::ELockScope eLockScope = RlvFolderLocks::SCOPE_SUBTREE;
+				ERlvLockMask eLockType = (RLV_BHVR_SHAREDUNWEAR == eBhvr) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD;
+
+				if (RLV_TYPE_ADD == eType)
+					RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType);
+				else
+					RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType);
+			}
+			break;
+		case RLV_BHVR_UNSHAREDWEAR:			// @unsharedwear=n|y				- Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+		case RLV_BHVR_UNSHAREDUNWEAR:		// @unsharedunwear=n|y				- Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+			{
+				VERIFY_OPTION_REF(strOption.empty());
+
+				// Lock down the inventory root
+				RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_ROOTFOLDER, 0);
+				RlvFolderLocks::ELockScope eLockScope = RlvFolderLocks::SCOPE_SUBTREE;
+				ERlvLockMask eLockType = (RLV_BHVR_UNSHAREDUNWEAR == eBhvr) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD;
+
+				if (RLV_TYPE_ADD == eType)
+					RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType);
+				else
+					RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType);
+
+				// Add the #RLV shared folder as an exception
+				lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_SHAREDPATH, LLStringUtil::null);
+				if (RLV_TYPE_ADD == eType)
+					RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_ALLOW, eLockScope, rlvCmd.getObjectID(), eLockType);
+				else
+					RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_ALLOW, eLockScope, rlvCmd.getObjectID(), eLockType);
+			}
+			break;
+		case RLV_BHVR_REDIRCHAT:			// @redirchat:<channel>=n|y			- Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_REDIREMOTE:			// @rediremote:<channel>=n|y		- Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h
+			{
+				// There should be an option which should specify a valid reply channel (if there's an empty option the command is invalid)
+				S32 nChannel = 0;
+				VERIFY_OPTION_REF( (LLStringUtil::convertToS32(strOption, nChannel)) && (RlvUtil::isValidReplyChannel(nChannel)) );
+
+				if (RLV_TYPE_ADD == eType) 
+					addException(rlvCmd.getObjectID(), eBhvr, nChannel);
+				else
+					removeException(rlvCmd.getObjectID(), eBhvr, nChannel);
+			}
+			break;
+		case RLV_BHVR_NOTIFY:				// @notify:<params>=add|rem			- Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+			{
+				// There should be an option that we can successfully parse (if there's an empty option the command is invalid)
+				S32 nChannel; std::string strFilter;
+				VERIFY_OPTION_REF( (!strOption.empty()) && (rlvParseNotifyOption(strOption, nChannel, strFilter)) );
+
+				if (RLV_TYPE_ADD == eType)
+					RlvBehaviourNotifyHandler::getInstance()->addNotify(rlvCmd.getObjectID(), nChannel, strFilter);
+				else
+					RlvBehaviourNotifyHandler::getInstance()->removeNotify(rlvCmd.getObjectID(), nChannel, strFilter);
+			}
+			break;
+		//
+		// Unknown or invalid
+		//
+		case RLV_BHVR_UNKNOWN:
+			// Pass unknown commands on to registered command handlers
+			return (notifyCommandHandlers(&RlvExtCommandHandler::onAddRemCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN;
+		default:
+			// Fail with "Invalid param" if none of the above handled it
+			eRet = RLV_RET_FAILED_PARAM;
+			break;
+	}
+
+	// If this command represents a behaviour restriction that's been added/removed then we need to do some additional processing
+	if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) )
+	{
+		if (RLV_TYPE_ADD == eType)
+		{
+			if (rlvCmd.isStrict())
+				addException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr);
+			m_Behaviours[eBhvr]++;
+			rlvCmd.markRefCounted();
+		}
+		else
+		{
+			if (rlvCmd.isStrict())
+				removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr);
+			m_Behaviours[eBhvr]--;
+		}
+
+		m_OnBehaviour(eBhvr, eType);
+		if ( ((RLV_TYPE_ADD == eType) && (1 == m_Behaviours[eBhvr])) || ((RLV_TYPE_REMOVE == eType) && (0 == m_Behaviours[eBhvr])) )
+			m_OnBehaviourToggle(eBhvr, eType);
+	}
+
+	return eRet;
+}
+
+// Handles reference counting of behaviours and tracks strict exceptions for @permissive (all restriction handlers should call this function)
+ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM>::processCommand(const RlvCommand& rlvCmd, RlvBhvrHandlerFunc* pHandlerFunc, RlvBhvrToggleHandlerFunc* pToggleHandlerFunc)
+{
+	ERlvBehaviour eBhvr = rlvCmd.getBehaviourType();
+	bool fRefCount = false, fHasBhvr = gRlvHandler.hasBehaviour(eBhvr);
+
+	ERlvCmdRet eRet = (*pHandlerFunc)(rlvCmd, fRefCount);
+
+	// If this command represents a restriction that's been added/removed then we need to do some additional processing
+	if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) )
+	{
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		{
+			if (rlvCmd.isStrict())
+				gRlvHandler.addException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr);
+			gRlvHandler.m_Behaviours[eBhvr]++;
+			rlvCmd.markRefCounted();
+		}
+		else
+		{
+			if (rlvCmd.isStrict())
+				gRlvHandler.removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr);
+			gRlvHandler.m_Behaviours[eBhvr]--;
+		}
+
+		if (fHasBhvr != gRlvHandler.hasBehaviour(eBhvr))
+		{
+			if (pToggleHandlerFunc)
+				(*pToggleHandlerFunc)(eBhvr, !fHasBhvr);
+			gRlvHandler.m_OnBehaviourToggle(eBhvr, rlvCmd.getParamType());
+		}
+	}
+
+	return eRet;
+}
+
+// Handles: @bhvr=n|y
+template<>
+ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// There should be no option
+	if (rlvCmd.hasOption())
+		return RLV_RET_FAILED_OPTION;
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @bhvr:<uuid>=n|y
+template<>
+ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_EXCEPTION>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// There should be an option and it should specify a valid UUID
+	LLUUID idException;
+	if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idException))
+		return RLV_RET_FAILED_OPTION;
+
+	if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
+	else
+		gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @bhvr[:<uuid>]=n|y
+template<>
+ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// If there is an option then it should specify a valid UUID (but don't reference count)
+	if (rlvCmd.hasOption())
+	{
+		ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_EXCEPTION>::onCommand(rlvCmd, fRefCount);
+		fRefCount = false;
+		return eRet;
+	}
+	return RlvBehaviourGenericHandler<RLV_OPTION_NONE>::onCommand(rlvCmd, fRefCount);
+}
+
+// Handles: @bhvr:<modifier>=n|y
+template<>
+ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// There should be an option and it should specify a valid modifier (RlvBehaviourModifier performs the appropriate type checks)
+	RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType());
+	RlvBehaviourModifierValue modValue;
+	if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), modValue)) )
+		return RLV_RET_FAILED_OPTION;
+
+	// HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here
+	if (RLV_TYPE_ADD == rlvCmd.getParamType())
+	{
+		gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
+		pBhvrModifier->addValue(modValue, rlvCmd.getObjectID());
+		gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
+	}
+	else
+	{
+		gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
+		pBhvrModifier->removeValue(modValue, rlvCmd.getObjectID());
+		gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
+	}
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @bhvr[:<modifier>]=n|y
+template<>
+ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_MODIFIER>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// If there is an option then it should specify a valid modifier (and reference count)
+	if (rlvCmd.hasOption())
+		return RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(rlvCmd, fRefCount);
+
+	// Add the default option on an empty modifier if needed
+	RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType());
+	if ( (pBhvrModifier) && (pBhvrModifier->getAddDefault()) )
+	{
+		// HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		{
+			gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
+			pBhvrModifier->addValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID());
+			gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
+		}
+		else
+		{
+			gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
+			pBhvrModifier->removeValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID());
+			gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
+		}
+	}
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @addattach[:<attachpt>]=n|y and @remattach[:<attachpt>]=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourAddRemAttachHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// Sanity check - if there's an option it should specify a valid attachment point name
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption());
+	if ( (!idxAttachPt) && (!rlvCmd.getOption().empty())  )
+		return RLV_RET_FAILED_OPTION;
+
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	// We need to flush any queued force-wear commands before changing the restrictions
+	if (RlvForceWear::instanceExists())
+		RlvForceWear::instance().done();
+
+	ERlvLockMask eLock = (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD;
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+	{
+		if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) )
+		{
+			if (RLV_TYPE_ADD == rlvCmd.getParamType())
+				gRlvAttachmentLocks.addAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock);
+			else
+				gRlvAttachmentLocks.removeAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock);
+		}
+	}
+
+	fRefCount = rlvCmd.getOption().empty();	// Only reference count global locks
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @detach[:<attachpt>]=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_DETACH>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// We need to flush any queued force-wear commands before changing the restrictions
+	if (RlvForceWear::instanceExists())
+		RlvForceWear::instance().done();
+
+	if (rlvCmd.getOption().empty())	// @detach=n|y - RLV_LOCK_REMOVE locks an attachment *object*
+	{
+		// The object may or may not exist (it may not have rezzed yet, or it may have already been killed):
+		//   * @detach=n: - if it has rezzed then we'll already have looked up what we need (see next line if it's not an attachment)
+		//                - if it hasn't rezzed yet then it's a @detach=n from a non-attachment and RlvHandler::onAttach() takes care of it
+		//   * @detach=y: - if it ever rezzed as an attachment we'll have cached the UUID of its root
+		//                - if it never rezzed as an attachment there won't be a lock to remove
+		RlvHandler::rlv_object_map_t::const_iterator itObj = gRlvHandler.m_Objects.find(rlvCmd.getObjectID());
+		if ( (itObj != gRlvHandler.m_Objects.end()) && (itObj->second.hasLookup()) && (itObj->second.getAttachPt()) )
+		{
+			if (RLV_TYPE_ADD == rlvCmd.getParamType())
+				gRlvAttachmentLocks.addAttachmentLock(itObj->second.getRootID(), itObj->first);
+			else
+				gRlvAttachmentLocks.removeAttachmentLock(itObj->second.getRootID(), itObj->first);
+		}
+	}
+	else							// @detach:<attachpt>=n|y - RLV_LOCK_ADD and RLV_LOCK_REMOVE locks an attachment *point*
+	{
+		// The attachment point index should always be non-zero for @detach:<attachpt>=n|y
+		S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption());
+		if (0 == idxAttachPt)
+			return RLV_RET_FAILED_OPTION;
+
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+			gRlvAttachmentLocks.addAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE));
+		else
+			gRlvAttachmentLocks.removeAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE));
+	}
+
+	fRefCount = false;	// Don't reference count @detach[:<option>]=n
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0b) | Added: RLVa-1.3.0b
+ERlvCmdRet RlvHandler::onAddRemFolderLock(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	RlvCommandOptionGeneric rlvCmdOption;
+	RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption);
+
+	RlvFolderLocks::folderlock_source_t lockSource;
+	if (rlvCmdOption.isEmpty())
+	{
+		lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_ATTACHMENT, rlvCmd.getObjectID());
+	}
+	else if (rlvCmdOption.isSharedFolder())
+	{
+		lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_SHAREDPATH, rlvCmd.getOption());
+	}
+	else if (rlvCmdOption.isAttachmentPoint())
+	{
+		lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_ATTACHMENTPOINT, RlvAttachPtLookup::getAttachPointIndex(rlvCmdOption.getAttachmentPoint()));
+	}
+	else if (rlvCmdOption.isWearableType())
+	{
+		lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_WEARABLETYPE, rlvCmdOption.getWearableType());
+	}
+	else
+	{
+		fRefCount = false;	// Don't reference count failure
+		return RLV_RET_FAILED_OPTION;
+	}
+
+	// Determine the lock type
+	ERlvLockMask eLockType = (RLV_BHVR_ATTACHTHIS == rlvCmd.getBehaviourType()) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE;
+
+	// Determine the folder lock options from the issued behaviour
+	RlvFolderLocks::ELockPermission eLockPermission = RlvFolderLocks::PERM_DENY;
+	RlvFolderLocks::ELockScope eLockScope = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & rlvCmd.getBehaviourFlags()) ? RlvFolderLocks::SCOPE_SUBTREE : RlvFolderLocks::SCOPE_NODE;
+
+	if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		RlvFolderLocks::instance().addFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType);
+	else
+		RlvFolderLocks::instance().removeFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType);
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+ERlvCmdRet RlvHandler::onAddRemFolderLockException(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// Sanity check - the option should specify a shared folder path
+	RlvCommandOptionGeneric rlvCmdOption;
+	RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption);
+	if (!rlvCmdOption.isSharedFolder())
+		return RLV_RET_FAILED_OPTION;
+
+	ERlvBehaviour eBhvr = rlvCmd.getBehaviourType();
+
+	// Determine the lock type
+	ERlvLockMask eLockType = (RLV_BHVR_ATTACHTHISEXCEPT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE;
+
+	// Determine the folder lock options from the issued behaviour
+	RlvFolderLocks::ELockPermission eLockPermission = RlvFolderLocks::PERM_ALLOW;
+	RlvFolderLocks::ELockScope eLockScope = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & rlvCmd.getBehaviourFlags()) ? RlvFolderLocks::SCOPE_SUBTREE : RlvFolderLocks::SCOPE_NODE;
+
+	RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_SHAREDPATH, rlvCmd.getOption());
+	if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		RlvFolderLocks::instance().addFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType);
+	else
+		RlvFolderLocks::instance().removeFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType);
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @edit=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_EDIT>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if (fHasBhvr)
+	{
+		// Turn off "View / Highlight Transparent"
+		LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
+
+		// Hide the beacons floater if it's currently visible
+		if (LLFloaterReg::instanceVisible("beacons"))
+			LLFloaterReg::hideInstance("beacons");
+
+		// Hide the build floater if it's currently visible
+		if (LLFloaterReg::instanceVisible("build"))
+			LLToolMgr::instance().toggleBuildMode();
+	}
+
+	// Start or stop filtering opening the beacons floater
+	if (fHasBhvr)
+		RlvUIEnabler::instance().addGenericFloaterFilter("beacons");
+	else
+		RlvUIEnabler::instance().removeGenericFloaterFilter("beacons");
+}
+
+// Handles: @sendchannel[:<channel>]=n|y and @sendchannel_except[:<channel>]=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourSendChannelHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// If there's an option then it should be a valid (= positive and non-zero) chat channel
+	if (rlvCmd.hasOption())
+	{
+		S32 nChannel = 0;
+		if ( (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nChannel)) || (nChannel <= 0) )
+			return RLV_RET_FAILED_OPTION;
+
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+			gRlvHandler.addException(rlvCmd.getObjectID(),  rlvCmd.getBehaviourType(), nChannel);
+		else
+			gRlvHandler.removeException(rlvCmd.getObjectID(),  rlvCmd.getBehaviourType(), nChannel);
+	}
+	else
+	{
+		fRefCount = true;
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @recvim[:<uuid|range>]=n|y, @sendim[:<uuid|range>]=n|y and @startim[:<uuid|range>]=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourRecvSendStartIMHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount);
+	if ( (RLV_RET_SUCCESS != eRet) && (rlvCmd.hasOption()) )
+	{
+		// Check for <dist_min>[;<dist_max>] option
+		std::vector<std::string> optionList; float nDistMin = F32_MAX, nDistMax = F32_MAX;
+		if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (optionList.size() > 2) ||
+			 (!RlvCommandOptionHelper::parseOption(optionList[0], nDistMin)) || (nDistMin < 0) ||
+			 ( (optionList.size() >= 2) && (!RlvCommandOptionHelper::parseOption(optionList[1], nDistMax)) ) || (nDistMax < 0) )
+		{
+			return RLV_RET_FAILED_OPTION;
+		}
+
+		// Valid option(s) - figure out which modifier(s) to change
+		ERlvBehaviourModifier eModDistMin, eModDistMax;
+		switch (rlvCmd.getBehaviourType())
+		{
+			case RLV_BHVR_RECVIM:
+				eModDistMin = RLV_MODIFIER_RECVIMDISTMIN; eModDistMax = RLV_MODIFIER_RECVIMDISTMAX;
+				break;
+			case RLV_BHVR_SENDIM:
+				eModDistMin = RLV_MODIFIER_SENDIMDISTMIN; eModDistMax = RLV_MODIFIER_SENDIMDISTMAX;
+				break;
+			case RLV_BHVR_STARTIM:
+				eModDistMin = RLV_MODIFIER_STARTIMDISTMIN; eModDistMax = RLV_MODIFIER_STARTIMDISTMAX;
+				break;
+			default:
+				return RLV_RET_FAILED_OPTION;
+		}
+
+		RlvBehaviourModifier *pBhvrModDistMin = RlvBehaviourDictionary::instance().getModifier(eModDistMin), *pBhvrModDistMax = RlvBehaviourDictionary::instance().getModifier(eModDistMax);
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		{
+			pBhvrModDistMin->addValue(nDistMin * nDistMin, rlvCmd.getObjectID());
+			if (optionList.size() >= 2)
+				pBhvrModDistMax->addValue(nDistMax * nDistMax, rlvCmd.getObjectID());
+		}
+		else
+		{
+			pBhvrModDistMin->removeValue(nDistMin * nDistMin, rlvCmd.getObjectID());
+			if (optionList.size() >= 2)
+				pBhvrModDistMax->removeValue(nDistMax * nDistMax, rlvCmd.getObjectID());
+		}
+
+		fRefCount = true;
+		return RLV_RET_SUCCESS;
+	}
+	return eRet;
+}
+
+// Handles: @sendim=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SENDIM>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	gSavedPerAccountSettings.getControl("DoNotDisturbModeResponse")->setHiddenFromSettingsEditor(fHasBhvr);
+}
+
+// Handles: @setcam_avdistmin:<distance>=n|y changes
+template<>
+void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_AVDISTMIN>::onValueChange() const
+{
+	if ( (gAgentCamera.cameraMouselook()) && (!RlvActions::canChangeToMouselook()) )
+		gAgentCamera.changeCameraToThirdPerson();
+}
+
+// Handles: @setcam_eyeoffset:<vector3>=n|y and @setcam_focusoffset:<vector3>=n|y toggles
+template<> template<>
+void RlvBehaviourCamEyeFocusOffsetHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if (fHasBhvr)
+	{
+		gAgentCamera.switchCameraPreset(CAMERA_RLV_SETCAM_VIEW);
+	}
+	else
+	{
+		const RlvBehaviourModifier* pBhvrEyeModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET);
+		const RlvBehaviourModifier* pBhvrOffsetModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET);
+		if ( (!pBhvrEyeModifier->hasValue()) && (!pBhvrOffsetModifier->hasValue()) )
+			gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
+	}
+}
+
+// Handles: @setcam_eyeoffset:<vector3>=n|y changes
+template<>
+void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_EYEOFFSET>::onValueChange() const
+{
+	if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET))
+	{
+		LLControlVariable* pControl = gSavedSettings.getControl("CameraOffsetRLVaView");
+		if (pBhvrModifier->hasValue())
+			pControl->setValue(pBhvrModifier->getValue<LLVector3>().getValue());
+		else
+			pControl->resetToDefault();
+	}
+}
+
+// Handles: @setcam_focusoffset:<vector3>=n|y changes
+template<>
+void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOCUSOFFSET>::onValueChange() const
+{
+	if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET))
+	{
+		LLControlVariable* pControl = gSavedSettings.getControl("FocusOffsetRLVaView");
+		if (pBhvrModifier->hasValue())
+			pControl->setValue(pBhvrModifier->getValue<LLVector3>().getValue());
+		else
+			pControl->resetToDefault();
+	}
+}
+
+// Handles: @setcam_fovmin:<angle>=n|y and @setcam_fovmax:<angle>=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourSetCamFovHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	static float s_nLastCameraAngle = DEFAULT_FIELD_OF_VIEW;
+
+	S32 nRefMinBhvr = gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_FOVMIN], nRefMaxBhvr = gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_FOVMAX];
+	LLControlVariable* pSetting = gSavedSettings.getControl("CameraAngle");
+
+	// Save the user's current FOV angle if nothing's been restricted (yet)
+	if ( (!nRefMinBhvr) && (!nRefMaxBhvr) && (pSetting) )
+		s_nLastCameraAngle = (pSetting->isPersisted()) ? LLViewerCamera::instance().getDefaultFOV() : DEFAULT_FIELD_OF_VIEW;
+
+	// Perform default handling of the command
+	ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(rlvCmd, fRefCount);
+	if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) && (pSetting) )
+	{
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		{
+			// Don't persist changes from this point
+			pSetting->setPersist(LLControlVariable::PERSIST_NO);
+		}
+		else if ( (RLV_TYPE_REMOVE == rlvCmd.getParamType()) && (1 == nRefMinBhvr + nRefMaxBhvr) )
+		{
+			// Restore the user's last FOV angle (and resume persistance)
+			LLViewerCamera::instance().setDefaultFOV(s_nLastCameraAngle);
+			pSetting->setPersist(LLControlVariable::PERSIST_NONDFT);
+		}
+	}
+	return eRet;
+}
+
+// Handles: @setcam_fovmin:<angle>=n|y changes
+template<>
+void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMIN>::onValueChange() const
+{
+	LLViewerCamera::instance().setDefaultFOV(LLViewerCamera::instance().getDefaultFOV());
+}
+
+// Handles: @setcam_fovmax:<angle>=n|y changes
+template<>
+void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMAX>::onValueChange() const
+{
+	LLViewerCamera::instance().setDefaultFOV(LLViewerCamera::instance().getDefaultFOV());
+}
+
+// Handles: @setcam_mouselook=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_MOUSELOOK>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if ((fHasBhvr) && (gAgentCamera.cameraMouselook()))
+		gAgentCamera.changeCameraToThirdPerson();
+}
+
+// Handles: @setcam_textures[:<uuid>=n|y changes
+template<>
+void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_TEXTURE>::onValueChange() const
+{
+	if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE))
+	{
+		if (pBhvrModifier->hasValue())
+		{
+			RLV_INFOS << "Toggling diffuse textures for @setcam_textures" << RLV_ENDL;
+			LLViewerFetchedTexture::sDefaultDiffuseImagep = LLViewerTextureManager::getFetchedTexture(pBhvrModifier->getValue<LLUUID>(), FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+			gObjectList.setAllObjectDefaultTextures(LLRender::DIFFUSE_MAP, true);
+		}
+		else
+		{
+			RLV_INFOS << "Restoring diffuse textures for @setcam_textures" << RLV_ENDL;
+			gObjectList.setAllObjectDefaultTextures(LLRender::DIFFUSE_MAP, false);
+			LLViewerFetchedTexture::sDefaultDiffuseImagep = nullptr;
+		}
+	}
+}
+
+// Handles: @setcam_unlock=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_UNLOCK>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if (fHasBhvr)
+		handle_reset_view();
+}
+
+// Handles: @setcam=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	// Once an object has exclusive control over the camera only its behaviours should be active. This affects:
+	//   - behaviour modifiers         => it's all handled for us once we set the primary object
+	//   - RLV_BHVR_SETCAM_UNLOCK      => manually (re)set the reference count (and possibly invoke the toggle handler)
+
+	LLUUID idRlvObject; bool fHasCamUnlock = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK);
+	if (fHasBhvr)
+	{
+		// Get the UUID of the primary object
+		std::list<const RlvObject*> lObjects;
+		gRlvHandler.findBehaviour(RLV_BHVR_SETCAM, lObjects);
+		idRlvObject = lObjects.front()->getObjectID();
+		// Reset the @setcam_unlock reference count
+		gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_UNLOCK] = (lObjects.front()->hasBehaviour(RLV_BHVR_SETCAM_UNLOCK, false)) ? 1 : 0;
+	}
+	else
+	{
+		std::list<const RlvObject*> lObjects;
+		// Restore the @setcam_unlock reference count
+		gRlvHandler.findBehaviour(RLV_BHVR_SETCAM_UNLOCK, lObjects);
+		gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_UNLOCK] = lObjects.size();
+	}
+
+	// Manually invoke the @setcam_unlock toggle handler if we toggled it on/off
+	if (fHasCamUnlock != gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK))
+		RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_UNLOCK>::onCommandToggle(RLV_BHVR_SETCAM_UNLOCK, !fHasCamUnlock);
+
+	gAgentCamera.switchCameraPreset( (fHasBhvr) ? CAMERA_RLV_SETCAM_VIEW : CAMERA_PRESET_REAR_VIEW );
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMIN)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMAX)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_ORIGINDISTMIN)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_ORIGINDISTMAX)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOVMIN)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOVMAX)->setPrimaryObject(idRlvObject);
+	RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE)->setPrimaryObject(idRlvObject);
+}
+
+// Handles: @setdebug=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SETDEBUG>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	for (const auto& dbgSetting : RlvExtGetSet::m_DbgAllowed)
+	{
+		if (dbgSetting.second & RlvExtGetSet::DBG_WRITE)
+			gSavedSettings.getControl(dbgSetting.first)->setHiddenFromSettingsEditor(fHasBhvr);
+	}
+}
+
+// Handles: @edit=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SETENV>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	const std::string strEnvFloaters[] = { "env_post_process", "env_settings", "env_delete_preset", "env_edit_sky", "env_edit_water", "env_edit_day_cycle" };
+	for (int idxFloater = 0, cntFloater = sizeof(strEnvFloaters) / sizeof(std::string); idxFloater < cntFloater; idxFloater++)
+	{
+		if (fHasBhvr)
+		{
+			// Hide the floater if it's currently visible
+			LLFloaterReg::const_instance_list_t envFloaters = LLFloaterReg::getFloaterList(strEnvFloaters[idxFloater]);
+			for (LLFloater* pFloater : envFloaters)
+				pFloater->closeFloater();
+			RlvUIEnabler::instance().addGenericFloaterFilter(strEnvFloaters[idxFloater]);
+		}
+		else
+		{
+			RlvUIEnabler::instance().removeGenericFloaterFilter(strEnvFloaters[idxFloater]);
+		}
+	}
+
+	// Don't allow toggling "Basic Shaders" and/or "Atmopsheric Shaders" through the debug settings under @setenv=n
+	gSavedSettings.getControl("VertexShaderEnable")->setHiddenFromSettingsEditor(fHasBhvr);
+	gSavedSettings.getControl("WindLightUseAtmosShaders")->setHiddenFromSettingsEditor(fHasBhvr);
+
+	// Restore the user's WindLight preferences when releasing
+	if (!fHasBhvr)
+		LLEnvManagerNew::instance().usePrefs();
+}
+
+// Handles: @showhovertext:<uuid>=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWHOVERTEXT>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// There should be an option and it should specify a valid UUID
+	LLUUID idException;
+	if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idException))
+		return RLV_RET_FAILED_OPTION;
+
+	if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
+	else
+		gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
+
+	// Clear/restore the object's hover text as needed
+	LLViewerObject* pObj = gObjectList.findObject(idException);
+	if ( (pObj) && (pObj->mText.notNull()) && (!pObj->mText->getObjectText().empty()) )
+		pObj->mText->setString( (RLV_TYPE_ADD == rlvCmd.getParamType()) ? "" : pObj->mText->getObjectText());
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @edit=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SHOWINV>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if (LLApp::isQuitting())
+		return;	// Nothing to do if the viewer is shutting down
+
+	//
+	// When disabling, close any inventory floaters that may be open
+	//
+	if (fHasBhvr)
+	{
+		LLFloaterReg::const_instance_list_t invFloaters = LLFloaterReg::getFloaterList("inventory");
+		for (LLFloater* pFloater : invFloaters)
+			pFloater->closeFloater();
+	}
+
+	//
+	// Enable/disable the "My Outfits" panel on the "My Appearance" sidebar tab
+	//
+	LLPanelOutfitsInventory* pAppearancePanel = LLPanelOutfitsInventory::findInstance();
+	RLV_ASSERT(pAppearancePanel);
+	if (pAppearancePanel)
+	{
+		LLTabContainer* pAppearanceTabs = pAppearancePanel->getAppearanceTabs();
+		LLOutfitsList* pMyOutfitsPanel = pAppearancePanel->getMyOutfitsPanel();
+		if ( (pAppearanceTabs) && (pMyOutfitsPanel) )
+		{
+			S32 idxTab = pAppearanceTabs->getIndexForPanel(pMyOutfitsPanel);
+			RLV_ASSERT(-1 != idxTab);
+			pAppearanceTabs->enableTabButton(idxTab, !fHasBhvr);
+
+			// When disabling, switch to the COF tab if "My Outfits" is currently active
+			if ( (fHasBhvr) && (pAppearanceTabs->getCurrentPanelIndex() == idxTab) )
+				pAppearanceTabs->selectTabPanel(pAppearancePanel->getCurrentOutfitPanel());
+		}
+
+		LLSidepanelAppearance* pCOFPanel = pAppearancePanel->getAppearanceSP();
+		RLV_ASSERT(pCOFPanel);
+		if ( (fHasBhvr) && (pCOFPanel) && (pCOFPanel->isOutfitEditPanelVisible()) )
+		{
+			// TODO-RLVa: we should really just be collapsing the "Add more..." inventory panel (and disable the button)
+			pCOFPanel->showOutfitsInventoryPanel();
+		}
+	}
+
+	//
+	// Filter (or stop filtering) opening new inventory floaters
+	//
+	if (fHasBhvr)
+		RlvUIEnabler::instance().addGenericFloaterFilter("inventory");
+	else
+		RlvUIEnabler::instance().removeGenericFloaterFilter("inventory");
+}
+
+// Handles: @shownames[:<uuid>]=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMES>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if (LLApp::isQuitting())
+		return;	// Nothing to do if the viewer is shutting down
+
+	// Update the shownames context
+	RlvActions::setShowName(RlvActions::SNC_DEFAULT, !fHasBhvr);
+
+	// Refresh the nearby people list
+	LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people");
+	RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) );
+	if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) )
+	{
+		if (pPeoplePanel->getNearbyList()->isInVisibleChain())
+			pPeoplePanel->onCommit();
+		pPeoplePanel->getNearbyList()->updateAvatarNames();
+	}
+
+	// Force the use of the "display name" cache so we can filter both display and legacy names (or return back to the user's preference)
+	if (fHasBhvr)
+	{
+		LLAvatarNameCache::setForceDisplayNames(true);
+	}
+	else
+	{
+		LLAvatarNameCache::setForceDisplayNames(false);
+		LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames"));
+	}
+
+	// Refresh all name tags and HUD text
+	LLVOAvatar::invalidateNameTags();
+	LLHUDText::refreshAllObjectText();
+}
+
+// Handles: @shownames[:<uuid>]=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMES>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount);
+	if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) && (!LLApp::isQuitting()) )
+	{
+		const LLUUID idAgent = RlvCommandOptionHelper::parseOption<LLUUID>(rlvCmd.getOption());
+
+		// Refresh the nearby people list (if necessary)
+		LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people");
+		RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) );
+		if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) && (pPeoplePanel->getNearbyList()->contains(idAgent)) )
+		{
+			if (pPeoplePanel->getNearbyList()->isInVisibleChain())
+				pPeoplePanel->onCommit();
+			pPeoplePanel->getNearbyList()->updateAvatarNames();
+		}
+
+		// Refresh that avatar's name tag and all HUD text
+		LLVOAvatar::invalidateNameTag(idAgent);
+		LLHUDText::refreshAllObjectText();
+	}
+	return eRet;
+}
+
+// Handles: @shownametags[:<uuid>]=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMETAGS>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if (LLApp::isQuitting())
+		return;	// Nothing to do if the viewer is shutting down
+
+	// Update the shownames context
+	RlvActions::setShowName(RlvActions::SNC_NAMETAG, !fHasBhvr);
+
+	// Refresh all name tags
+	LLVOAvatar::invalidateNameTags();
+}
+
+// Handles: @shownametags[:<uuid>]=n|y
+template<> template<>
+ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMETAGS>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount);
+	if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) )
+		LLVOAvatar::invalidateNameTag(RlvCommandOptionHelper::parseOption<LLUUID>(rlvCmd.getOption()));
+	return eRet;
+}
+
+// Handles: @shownearby=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNEARBY>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	if (LLApp::isQuitting())
+		return;	// Nothing to do if the viewer is shutting down
+
+	// Refresh the nearby people list
+	LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people");
+	LLAvatarList* pNearbyList = (pPeoplePanel) ? pPeoplePanel->getNearbyList() : NULL;
+	RLV_ASSERT( (pPeoplePanel) && (pNearbyList) );
+	if (pNearbyList)
+	{
+		static std::string s_strNoItemsMsg = pNearbyList->getNoItemsMsg();
+		pNearbyList->setNoItemsMsg( (fHasBhvr) ? RlvStrings::getString("blocked_nearby") : s_strNoItemsMsg );
+		pNearbyList->clear();
+
+		if (pNearbyList->isInVisibleChain())
+			pPeoplePanel->onCommit();
+		if (!fHasBhvr)
+			pPeoplePanel->updateNearbyList();
+	}
+
+	// Refresh that avatar's name tag and all HUD text
+	LLHUDText::refreshAllObjectText();
+}
+
+// Handles: @showself=n|y and @showselfhead=n|y toggles
+template<> template<>
+void RlvBehaviourShowSelfToggleHandler::onCommandToggle(ERlvBehaviour eBvhr, bool fHasBhvr)
+{
+	if (isAgentAvatarValid())
+		gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
+}
+
+// ============================================================================
+// Command handlers (RLV_TYPE_FORCE)
+//
+
+ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_FORCE>::processCommand(const RlvCommand& rlvCmd, RlvForceHandlerFunc* pHandler)
+{
+	return (*pHandler)(rlvCmd);
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0j
+ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const
+{
+	RLV_ASSERT(RLV_TYPE_FORCE == rlvCmd.getParamType());
+
+	// Try a command processor first
+	ERlvCmdRet eRet = rlvCmd.processCommand();
+	if (RLV_RET_NO_PROCESSOR != eRet)
+	{
+		return eRet;
+	}
+
+	// Process the command the legacy way
+	eRet = RLV_RET_SUCCESS;
+	switch (rlvCmd.getBehaviourType())
+	{
+		case RLV_BHVR_UNSIT:		// @unsit=force							- Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g
+			{
+				VERIFY_OPTION(rlvCmd.getOption().empty());
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (!hasBehaviourExcept(RLV_BHVR_UNSIT, rlvCmd.getObjectID())) )
+				{
+					gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+					send_agent_update(TRUE, TRUE);	// See behaviour notes on why we have to force an agent update here
+				}
+			}
+			break;
+		case RLV_BHVR_ADJUSTHEIGHT:	// @adjustheight:<options>=force		- Checked: 2015-03-30 (RLVa-1.5.0)
+			{
+				RlvCommandOptionAdjustHeight rlvCmdOption(rlvCmd);
+				VERIFY_OPTION(rlvCmdOption.isValid());
+				if (isAgentAvatarValid())
+				{
+					F32 nValue = (rlvCmdOption.m_nPelvisToFoot - gAgentAvatarp->getPelvisToFoot()) * rlvCmdOption.m_nPelvisToFootDeltaMult;
+					nValue += rlvCmdOption.m_nPelvisToFootOffset;
+					if (gAgentAvatarp->getRegion()->avatarHoverHeightEnabled())
+					{
+						LLVector3 avOffset(0.0f, 0.0f, llclamp<F32>(nValue, MIN_HOVER_Z, MAX_HOVER_Z));
+						gSavedPerAccountSettings.setF32("AvatarHoverOffsetZ", avOffset.mV[VZ]);
+						gAgentAvatarp->setHoverOffset(avOffset, true);
+					}
+					else
+					{
+						eRet = RLV_RET_FAILED_DISABLED;
+					}
+				}
+			}
+			break;
+		case RLV_CMD_FORCEWEAR:		// @forcewear[:<options>]=force			- Checked: 2011-09-12 (RLVa-1.5.0)
+			{
+				if (RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE & rlvCmd.getBehaviourFlags())
+				{
+					RlvCommandOptionGeneric rlvCmdOption;
+					RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption);
+					VERIFY_OPTION(rlvCmdOption.isSharedFolder());
+					eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags());
+				}
+				else if (RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT & rlvCmd.getBehaviourFlags())
+				{
+					RlvCommandOptionGetPath rlvGetPathOption(rlvCmd, boost::bind(&RlvHandler::onForceWearCallback, this, _1, rlvCmd.getBehaviourFlags()));
+					VERIFY_OPTION(rlvGetPathOption.isValid());
+					eRet = (!rlvGetPathOption.isCallback()) ? RLV_RET_SUCCESS : RLV_RET_SUCCESS_DELAYED;
+				}
+			}
+			break;
+		case RLV_BHVR_UNKNOWN:
+			// Pass unknown commands on to registered command handlers
+			return (notifyCommandHandlers(&RlvExtCommandHandler::onForceCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN;
+		default:
+			// Fail with "Invalid param" if none of the above handled it
+			eRet = RLV_RET_FAILED_PARAM;
+			break;
+	}
+	return eRet;
+}
+
+// Handles: @detachme=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_DETACHME>::onCommand(const RlvCommand& rlvCmd)
+{
+	if (rlvCmd.hasOption())
+		return RLV_RET_FAILED_OPTION;
+
+	// NOTE: @detachme should respect locks but shouldn't respect things like nostrip
+	const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmd.getObjectID());
+	if ( (pAttachObj) && (pAttachObj->isAttachment()) )
+		LLVOAvatarSelf::detachAttachmentIntoInventory(pAttachObj->getAttachmentItemID());
+
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @remattach[:<folder|attachpt|attachgroup>]=force
+template<> template<>
+ERlvCmdRet RlvForceRemAttachHandler::onCommand(const RlvCommand& rlvCmd)
+{
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	RlvCommandOptionGeneric rlvCmdOption;
+	RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption);
+	if (rlvCmdOption.isSharedFolder())
+		return gRlvHandler.onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags());
+
+	// @remattach:<attachpt>=force - force detach single attachment point
+	if (rlvCmdOption.isAttachmentPoint())
+	{
+		RlvForceWear::instance().forceDetach(rlvCmdOption.getAttachmentPoint());
+		return RLV_RET_SUCCESS;
+	}
+	// @remattach:<group>=force - force detach attachments points belonging to <group>
+	// @remattach=force         - force detach all attachments points
+	else if ( (rlvCmdOption.isAttachmentPointGroup()) || (rlvCmdOption.isEmpty()) )
+	{
+		for (const auto& entryAttachPt : gAgentAvatarp->mAttachmentPoints)
+		{
+			const LLViewerJointAttachment* pAttachPt = entryAttachPt.second;
+			if ( (pAttachPt) && (pAttachPt->getNumObjects()) && ((rlvCmdOption.isEmpty()) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == rlvCmdOption.getAttachmentPointGroup())) )
+			{
+				RlvForceWear::instance().forceDetach(pAttachPt);
+			}
+		}
+		return RLV_RET_SUCCESS;
+	}
+	// @remattach:<uuid>=force - force detach a specific attachment
+	else if (rlvCmdOption.isUUID())
+	{
+		const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmdOption.getUUID());
+		if ( (pAttachObj) && (pAttachObj->isAttachment()) && (pAttachObj->permYouOwner()) )
+			RlvForceWear::instance().forceDetach(pAttachObj);
+		return RLV_RET_SUCCESS;
+	}
+	return RLV_RET_FAILED_OPTION;
+}
+
+// Handles: @remoutfit[:<folder|layer>]=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_REMOUTFIT>::onCommand(const RlvCommand& rlvCmd)
+{
+	RlvCommandOptionGeneric rlvCmdOption;
+	RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption);
+	if (rlvCmdOption.isSharedFolder())
+		return gRlvHandler.onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags());
+
+	if ( (!rlvCmdOption.isWearableType()) && (!rlvCmdOption.isEmpty()) )
+		return RLV_RET_FAILED_OPTION;
+
+	for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++)
+	{
+		if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType()))
+			RlvForceWear::instance().forceRemove((LLWearableType::EType)idxType);
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @setcam_eyeoffset[:<vector3>]=force and @setcam_focusoffset[:<vector3>]=force
+template<> template<>
+ERlvCmdRet RlvForceCamEyeFocusOffsetHandler::onCommand(const RlvCommand& rlvCmd)
+{
+	// Enforce exclusive camera locks
+	if (!RlvActions::canChangeCameraPreset(rlvCmd.getObjectID()))
+		return RLV_RET_FAILED_LOCK;
+
+	LLControlVariable* pOffsetControl = gSavedSettings.getControl("CameraOffsetRLVaView");
+	LLControlVariable* pFocusControl = gSavedSettings.getControl("FocusOffsetRLVaView");
+	LLControlVariable* pControl = (rlvCmd.getBehaviourType() == RLV_BHVR_SETCAM_EYEOFFSET) ? pOffsetControl : pFocusControl;
+	if (rlvCmd.hasOption())
+	{
+		LLVector3 vecOffset;
+		if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), vecOffset))
+			return RLV_RET_FAILED_OPTION;
+		pControl->setValue(vecOffset.getValue());
+	}
+	else
+	{
+		pControl->resetToDefault();
+	}
+
+	gAgentCamera.switchCameraPreset( ((pOffsetControl->isDefault()) && (pFocusControl->isDefault())) ? CAMERA_PRESET_REAR_VIEW : CAMERA_RLV_SETCAM_VIEW);
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @setcam_focus:<uuid>[;<dist>[;<direction>]]=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_FOCUS>::onCommand(const RlvCommand& rlvCmd)
+{
+	std::vector<std::string> optionList;
+	if (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList))
+		return RLV_RET_FAILED_OPTION;
+
+	LLVector3 posAgent;
+	LLVector3d posGlobal;
+	F32 camDistance;
+
+	// Get the focus position/object (and verify it is known)
+	LLUUID idObject; LLVector3 posRegion;
+	if (RlvCommandOptionHelper::parseOption(optionList[0], idObject))
+	{
+		const LLViewerObject* pObj = gObjectList.findObject(idObject);
+		if (!pObj)
+			return RLV_RET_FAILED_OPTION;
+		if (!pObj->isAvatar())
+		{
+			posAgent = pObj->getPositionAgent();
+			posGlobal = pObj->getPositionGlobal();
+		}
+		else
+		{
+			/*const*/ LLVOAvatar* pAvatar = (/*const*/ LLVOAvatar*)pObj;
+			if (pAvatar->mHeadp)
+			{
+				posAgent = pAvatar->mHeadp->getWorldPosition();
+				posGlobal = pAvatar->getPosGlobalFromAgent(posAgent);
+			}
+		}
+		camDistance = pObj->getScale().magVec();
+	}
+	else if (RlvCommandOptionHelper::parseOption(optionList[0], posRegion))
+	{
+		const LLViewerRegion* pRegion = gAgent.getRegion();
+		if (!pRegion)
+			return RLV_RET_FAILED_UNKNOWN;
+		posAgent = pRegion->getPosAgentFromRegion(posRegion);
+		posGlobal = pRegion->getPosGlobalFromRegion(posRegion);
+		camDistance = 0.0f;
+	}
+	else
+	{
+		return RLV_RET_FAILED_OPTION;
+	}
+
+	// Get the camera distance
+	if ( (optionList.size() > 1) && (!optionList[1].empty()) )
+	{
+		if (!RlvCommandOptionHelper::parseOption(optionList[1], camDistance))
+			return RLV_RET_FAILED_OPTION;
+	}
+
+	// Get the directional vector (or calculate it from the current camera position)
+	LLVector3 camDirection;
+	if ( (optionList.size() > 2) && (!optionList[2].empty()) )
+	{
+		if (!RlvCommandOptionHelper::parseOption(optionList[2], camDirection))
+			return RLV_RET_FAILED_OPTION;
+	}
+	else
+	{
+		camDirection = LLViewerCamera::getInstance()->getOrigin() - posAgent;
+	}
+	camDirection.normVec();
+
+	// Move the camera in place
+	gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+	gAgentCamera.setCameraPosAndFocusGlobal(posGlobal + LLVector3d(camDirection * llmax(F_APPROXIMATELY_ZERO, camDistance)), posGlobal, idObject);
+
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @setcam_fov[:<angle>]=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_FOV>::onCommand(const RlvCommand& rlvCmd)
+{
+	if (!RlvActions::canChangeCameraFOV(rlvCmd.getObjectID()))
+		return RLV_RET_FAILED_LOCK;
+
+	F32 nFOV = DEFAULT_FIELD_OF_VIEW;
+	if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nFOV)) )
+		return RLV_RET_FAILED_OPTION;
+
+	LLViewerCamera::getInstance()->setDefaultFOV(nFOV);
+
+	// Don't persist non-default changes that are due to RLV; but do resume persistance once reset back to the default
+	if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX)) )
+	{
+		if (LLControlVariable* pSetting = gSavedSettings.getControl("CameraAngle"))
+			pSetting->setPersist( (pSetting->isDefault()) ? LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO );
+	}
+
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @setcam_mode[:<option>]=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_MODE>::onCommand(const RlvCommand& rlvCmd)
+{
+	const std::string& strOption = rlvCmd.getOption();
+	if ("mouselook" == strOption)
+		gAgentCamera.changeCameraToMouselook();
+	else if ("thirdperson" == strOption)
+		gAgentCamera.changeCameraToThirdPerson();
+	else if ( ("reset" == strOption) || (strOption.empty()) )
+		handle_reset_view();
+	else
+		return RLV_RET_FAILED_OPTION;
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const
+{
+	if ( (!pFolder) || (!RlvInventory::instance().isSharedFolder(pFolder->getUUID())) )
+		return RLV_RET_FAILED_OPTION;
+
+	RlvForceWear::EWearAction eAction = (RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE & nFlags) ? RlvForceWear::ACTION_REMOVE
+																						   : ((RlvBehaviourInfo::FORCEWEAR_WEAR_ADD & nFlags) ? RlvForceWear::ACTION_WEAR_ADD
+																																			  : RlvForceWear::ACTION_WEAR_REPLACE);
+	RlvForceWear::EWearFlags eFlags = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & nFlags) ? RlvForceWear::FLAG_MATCHALL : RlvForceWear::FLAG_DEFAULT;
+
+	RlvForceWear::instance().forceFolder(pFolder, eAction, eFlags);
+	return RLV_RET_SUCCESS;
+}
+
+void RlvHandler::onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) const
+{
+	LLInventoryModel::cat_array_t folders;
+	if (RlvInventory::instance().getPath(idItems, folders))
+	{
+		for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++)
+			onForceWear(folders.at(idxFolder), nFlags);
+
+		// If we're not executing a command then we're a delayed callback and need to manually call done()
+		if ( (!getCurrentCommand()) && (RlvForceWear::instanceExists()) )
+			RlvForceWear::instance().done();
+	}
+}
+
+// Handles: @setgroup:<uuid|name>=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_SETGROUP>::onCommand(const RlvCommand& rlvCmd)
+{
+	if (!RlvActions::canChangeActiveGroup(rlvCmd.getObjectID()))
+	{
+		return RLV_RET_FAILED_LOCK;
+	}
+
+	LLUUID idGroup; bool fValid = false;
+	if (idGroup.set(rlvCmd.getOption()))
+	{
+		fValid = (idGroup.isNull()) || (gAgent.isInGroup(idGroup, true));
+	}
+	else
+	{
+		for (S32 idxGroup = 0, cntGroup = gAgent.mGroups.size(); (idxGroup < cntGroup) && (idGroup.isNull()); idxGroup++)
+			if (boost::iequals(gAgent.mGroups.at(idxGroup).mName, rlvCmd.getOption()))
+				idGroup = gAgent.mGroups.at(idxGroup).mID;
+		fValid = (idGroup.notNull()) || ("none" == rlvCmd.getOption());
+	}
+
+	if (fValid)
+	{
+		gRlvHandler.m_idAgentGroup = idGroup;
+		LLGroupActions::activate(idGroup);
+	}
+
+	return (fValid) ? RLV_RET_SUCCESS : RLV_RET_FAILED_OPTION;
+}
+
+// Handles: @sit:<uuid>=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_SIT>::onCommand(const RlvCommand& rlvCmd)
+{
+	LLViewerObject* pObj = NULL; LLUUID idTarget(rlvCmd.getOption());
+	// Sanity checking - we need to know about the object and it should identify a prim/linkset
+	if ( (idTarget.isNull()) || ((pObj = gObjectList.findObject(idTarget)) == NULL) || (LL_PCODE_VOLUME != pObj->getPCode()) )
+		return RLV_RET_FAILED_OPTION;
+
+	if (!RlvActions::canSit(pObj))
+		return RLV_RET_FAILED_LOCK;
+	else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) )
+	{
+		if (gAgentAvatarp->isSitting())
+			return RLV_RET_FAILED_LOCK;
+		gRlvHandler.m_posSitSource = gAgent.getPositionGlobal();
+	}
+
+	// Copy/paste from handle_sit_or_stand()
+	gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
+	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
+	gMessageSystem->addUUIDFast(_PREHASH_TargetID, pObj->mID);
+	gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3::zero);
+	pObj->getRegion()->sendReliableMessage();
+
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @tpto:<vector>[;<angle>]=force and @tpto:<region>/<vector>[;<angle>]=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_TPTO>::onCommand(const RlvCommand& rlvCmd)
+{
+	std::vector<std::string> optionList;
+	if (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList))
+		return RLV_RET_FAILED_OPTION;
+
+	// We need the look-at first
+	LLVector3 vecLookAt = LLVector3::zero;
+	if (optionList.size() > 1)
+	{
+		float nAngle = 0.0f;
+		if (!RlvCommandOptionHelper::parseOption(optionList[1], nAngle))
+			return RLV_RET_FAILED_OPTION;
+
+		vecLookAt = LLVector3::x_axis;
+		vecLookAt.rotVec(nAngle, LLVector3::z_axis);
+		vecLookAt.normalize();
+	}
+
+	// Next figure out the destination
+	LLVector3d posGlobal;
+	if (RlvCommandOptionHelper::parseOption(optionList[0], posGlobal))
+	{
+		if (optionList.size() == 1)
+			gAgent.teleportViaLocation(posGlobal);
+		else
+		gAgent.teleportViaLocationLookAt(posGlobal, vecLookAt);
+	}
+	else
+	{
+		std::vector<std::string> posList; LLVector3 posRegion;
+		if ( (!RlvCommandOptionHelper::parseStringList(optionList[0], posList, std::string("/"))) || (4 != posList.size()) ||
+		     (!RlvCommandOptionHelper::parseOption(optionList[0].substr(posList[0].size() + 1), posRegion)) )
+		{
+			return RLV_RET_FAILED_OPTION;
+		}
+
+		LLWorldMapMessage::url_callback_t cb = boost::bind(&RlvUtil::teleportCallback, _1, posRegion, vecLookAt);
+		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(posList[0], cb, std::string(""), true);
+	}
+
+	return RLV_RET_SUCCESS;
+}
+
+// ============================================================================
+// Command handlers (RLV_TYPE_REPLY)
+//
+
+ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_REPLY>::processCommand(const RlvCommand& rlvCmd, RlvReplyHandlerFunc* pHandler)
+{
+	// Sanity check - <param> should specify a - valid - reply channel
+	S32 nChannel;
+	if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) )
+		return RLV_RET_FAILED_PARAM;
+
+	std::string strReply;
+	ERlvCmdRet eRet = (*pHandler)(rlvCmd, strReply);
+
+	// If we made it this far then:
+	//   - the command was handled successfully so we send off the response
+	//   - the command failed but we still send off an - empty - response to keep the issuing script from blocking
+	if (nChannel != 0)
+		RlvUtil::sendChatReply(nChannel, strReply);
+	else
+	{
+		if (RlvFloaterConsole* pConsole = LLFloaterReg::findTypedInstance<RlvFloaterConsole>("rlv_console"))
+			pConsole->addCommandReply(rlvCmd.getBehaviour(), strReply);
+	}
+
+	return eRet;
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::processReplyCommand(const RlvCommand& rlvCmd) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+
+	// Try a command processor first
+	ERlvCmdRet eRet = rlvCmd.processCommand();
+	if (RLV_RET_NO_PROCESSOR != eRet)
+	{
+		return eRet;
+	}
+
+	// Sanity check - <param> should specify a - valid - reply channel
+	S32 nChannel;
+	if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) )
+		return RLV_RET_FAILED_PARAM;
+
+	// Process the command the legacy way
+	eRet = RLV_RET_SUCCESS; std::string strReply;
+	switch (rlvCmd.getBehaviourType())
+	{
+		case RLV_BHVR_VERSION:			// @version=<channel>					- Checked: 2010-03-27 (RLVa-1.4.0a)
+		case RLV_BHVR_VERSIONNEW:		// @versionnew=<channel>				- Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.2.0b
+			// NOTE: RLV will respond even if there's an option
+			strReply = RlvStrings::getVersion(rlvCmd.getObjectID(), RLV_BHVR_VERSION == rlvCmd.getBehaviourType());
+			break;
+		case RLV_BHVR_VERSIONNUM:		// @versionnum=<channel>				- Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.4b
+			// NOTE: RLV will respond even if there's an option
+			strReply = RlvStrings::getVersionNum(rlvCmd.getObjectID());
+			break;
+		case RLV_BHVR_GETATTACH:		// @getattach[:<layer>]=<channel>
+			eRet = onGetAttach(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETATTACHNAMES:	// @getattachnames[:<grp>]=<channel>
+		case RLV_BHVR_GETADDATTACHNAMES:// @getaddattachnames[:<grp>]=<channel>
+		case RLV_BHVR_GETREMATTACHNAMES:// @getremattachnames[:<grp>]=<channel>
+			eRet = onGetAttachNames(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETOUTFIT:		// @getoutfit[:<layer>]=<channel>
+			eRet = onGetOutfit(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETOUTFITNAMES:	// @getoutfitnames=<channel>
+		case RLV_BHVR_GETADDOUTFITNAMES:// @getaddoutfitnames=<channel>
+		case RLV_BHVR_GETREMOUTFITNAMES:// @getremoutfitnames=<channel>
+			eRet = onGetOutfitNames(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_FINDFOLDER:		// @findfolder:<criteria>=<channel>
+		case RLV_BHVR_FINDFOLDERS:		// @findfolders:<criteria>=<channel>
+			eRet = onFindFolder(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETPATH:			// @getpath[:<option>]=<channel>
+		case RLV_BHVR_GETPATHNEW:		// @getpathnew[:<option>]=<channel>
+			eRet = onGetPath(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETINV:			// @getinv[:<path>]=<channel>
+			eRet = onGetInv(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETINVWORN:		// @getinvworn[:<path>]=<channel>
+			eRet = onGetInvWorn(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETGROUP:			// @getgroup=<channel>					- Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f
+			strReply = (gAgent.getGroupID().notNull()) ? gAgent.getGroupName() : "none";
+			break;
+		case RLV_BHVR_GETSITID:			// @getsitid=<channel>					- Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+			{
+				// NOTE: RLV-1.16.1 returns a NULL UUID if we're not sitting
+				LLUUID idSitObj;
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) )
+				{
+					const LLViewerObject* pSeatObj = dynamic_cast<LLViewerObject*>(gAgentAvatarp->getRoot());
+					if (pSeatObj)
+						idSitObj = pSeatObj->getID();
+				}
+				strReply = idSitObj.asString();
+			}
+			break;
+		case RLV_BHVR_GETSTATUS:		// @getstatus                           - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+			{
+				std::string strFilter, strSeparator;
+				if (rlvParseGetStatusOption(rlvCmd.getOption(), strFilter, strSeparator))
+				{
+					// NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set
+					rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID());
+					if (itObj != m_Objects.end())
+						strReply = itObj->second.getStatusString(strFilter, strSeparator);
+				}
+			}
+			break;
+		case RLV_BHVR_GETSTATUSALL:		// @getstatusall                        - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+			{
+				std::string strFilter, strSeparator;
+				if (rlvParseGetStatusOption(rlvCmd.getOption(), strFilter, strSeparator))
+				{
+					// NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set
+					for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+						strReply += itObj->second.getStatusString(strFilter, strSeparator);
+				}
+			}
+			break;
+		case RLV_BHVR_UNKNOWN:
+			// Pass unknown commands on to registered command handlers
+			return (notifyCommandHandlers(&RlvExtCommandHandler::onReplyCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN;
+		default:
+			// Fail with "Invalid param" if none of the above handled it
+			return RLV_RET_FAILED_PARAM;
+	}
+
+	// If we made it this far then:
+	//   - the command was handled successfully so we send off the response
+	//   - the command failed but we still send off an - empty - response to keep the issuing script from blocking
+	if (nChannel > 0)
+		RlvUtil::sendChatReply(nChannel, strReply);
+	else
+	{
+		if (RlvFloaterConsole* pConsole = LLFloaterReg::findTypedInstance<RlvFloaterConsole>("rlv_console"))
+			pConsole->addCommandReply(rlvCmd.getBehaviour(), strReply);
+	}
+
+	return eRet;
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType()) || (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType()) ); 
+
+	// (Compatibility: RLV 1.16.1 returns the first random folder it finds while we return a blank on no option)
+	if (rlvCmd.getOption().empty())
+		return RLV_RET_FAILED_OPTION;
+
+	LLInventoryModel::cat_array_t folders;
+	if (RlvInventory::instance().findSharedFolders(rlvCmd.getOption(), folders))
+	{
+		if (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType())
+		{
+			// We need to return an "in depth" result so whoever has the most '/' is our lucky winner
+			// (maxSlashes needs to be initialized to -1 since children of the #RLV folder won't have '/' in their shared path)
+			int maxSlashes = -1, curSlashes; std::string strFolderName;
+			for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++)
+			{
+				strFolderName = RlvInventory::instance().getSharedPath(folders.at(idxFolder));
+
+				curSlashes = std::count(strFolderName.begin(), strFolderName.end(), '/');
+				if (curSlashes > maxSlashes)
+				{
+					maxSlashes = curSlashes;
+					strReply = strFolderName;
+				}
+			}
+		}
+		else if (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType())
+		{
+			for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++)
+			{
+				if (!strReply.empty())
+					strReply.push_back(',');
+				strReply += RlvInventory::instance().getSharedPath(folders.at(idxFolder));
+			}
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-19 (RLVa-1.4.0a) | Modified: RLVa-1.1.0e
+ERlvCmdRet RlvHandler::onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT(RLV_BHVR_GETATTACH == rlvCmd.getBehaviourType());
+
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	// Sanity check - <option> should specify an attachment point or be empty
+	S32 idxAttachPt = 0;
+	if ( (rlvCmd.hasOption()) && ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption())) == 0) )
+		return RLV_RET_FAILED_OPTION;
+
+	// If we're fetching all worn attachments then the reply should start with 0
+	if (0 == idxAttachPt)
+		strReply.push_back('0');
+
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttach->second;
+		if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) )
+		{
+			bool fWorn = (pAttachPt->getNumObjects() > 0) && 
+				( (!RlvSettings::getHideLockedAttach()) || (RlvForceWear::isForceDetachable(pAttachPt, true, rlvCmd.getObjectID())) );
+			strReply.push_back( (fWorn) ? '1' : '0' );
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
+ERlvCmdRet RlvHandler::onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_GETATTACHNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDATTACHNAMES == rlvCmd.getBehaviourType()) || 
+				(RLV_BHVR_GETREMATTACHNAMES == rlvCmd.getBehaviourType()) );
+
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	ERlvAttachGroupType eAttachGroup = rlvAttachGroupFromString(rlvCmd.getOption());
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttach->second;
+		if ( (RLV_ATTACHGROUP_INVALID == eAttachGroup) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == eAttachGroup) )
+		{
+			bool fAdd = false;
+			switch (rlvCmd.getBehaviourType())
+			{
+				case RLV_BHVR_GETATTACHNAMES:		// Every attachment point that has an attached object
+					fAdd = (pAttachPt->getNumObjects() > 0);
+					break;
+				case RLV_BHVR_GETADDATTACHNAMES:	// Every attachment point that can be attached to (wear replace OR wear add)
+					fAdd = (gRlvAttachmentLocks.canAttach(pAttachPt) & RLV_WEAR);
+					break;
+				case RLV_BHVR_GETREMATTACHNAMES:	// Every attachment point that has at least one attachment that can be force-detached
+					fAdd = RlvForceWear::isForceDetachable(pAttachPt);
+					break;
+				default:
+					break;
+			}
+
+			if (fAdd)
+			{
+				if (!strReply.empty())
+					strReply.push_back(',');
+				strReply.append(pAttachPt->getName());
+			}
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @getcam_avdist=<channel>
+template<> template<>
+ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_AVDIST>::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+	if (rlvCmd.hasOption())
+		return RLV_RET_FAILED_OPTION;
+	strReply = llformat("%.3lf", (gAgentCamera.getCameraPositionGlobal() - gAgent.getPositionGlobal()).magVec());
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @getcam_avdistmin=<channel>, @getcam_avdistmax=<channel>, @getcam_fovmin=<channel> and @getcam_fovmax=<channel>
+template<> template<>
+ERlvCmdRet RlvReplyCamMinMaxModifierHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+	if ( (rlvCmd.hasOption()) || (!boost::starts_with(rlvCmd.getBehaviour(), "getcam_")) )
+		return RLV_RET_FAILED_OPTION;
+	ERlvBehaviour eBhvr = RlvBehaviourDictionary::instance().getBehaviourFromString("setcam_" + rlvCmd.getBehaviour().substr(7), RLV_TYPE_ADDREM);
+	if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(eBhvr))
+		strReply = (pBhvrModifier->hasValue()) ? llformat("%.3f", pBhvrModifier->getValue<float>()) : LLStringUtil::null;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @camzoommin/max[:<multiplier>]=n|y - DEPRECATED
+template<> template<>
+ERlvCmdRet RlvBehaviourCamZoomMinMaxHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// NOTE: @camzoommin/max are implemented as semi-synonyms of @setcam_fovmin/max
+	F32 nMult = 1.0f;
+	if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nMult)) )
+		return RLV_RET_FAILED_OPTION;
+
+	RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier( (RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_MODIFIER_SETCAM_FOVMIN : RLV_MODIFIER_SETCAM_FOVMAX);
+	if (pBhvrModifier)
+	{
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+		{
+			gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]++;
+			pBhvrModifier->addValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID());
+		}
+		else
+		{
+			gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]--;
+			pBhvrModifier->removeValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID());
+		}
+	}
+
+	fRefCount = true;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @getcam_fov=<channel>
+template<> template<>
+ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_FOV>::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+	if (rlvCmd.hasOption())
+		return RLV_RET_FAILED_OPTION;
+	strReply = llformat("%.3f", LLViewerCamera::getInstance()->getDefaultFOV());
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @getcam_textures=<channel>
+template<> template<>
+ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_TEXTURES>::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+	if (rlvCmd.hasOption())
+		return RLV_RET_FAILED_OPTION;
+	if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE))
+		strReply = (pBhvrModifier->hasValue()) ? pBhvrModifier->getValue<LLUUID>().asString() : LLStringUtil::null;
+	return RLV_RET_SUCCESS;
+}
+
+// Handles: @getcommand[:<behaviour>[;<type>[;<separator>]]]=<channel>
+template<> template<>
+ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCOMMAND>::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+	std::vector<std::string> optionList;
+	RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList);
+
+	// If a second parameter is present it'll specify the command type
+	ERlvParamType eType = RLV_TYPE_UNKNOWN;
+	if (optionList.size() >= 2)
+	{
+		if ( (optionList[1] == "any") || (optionList[1].empty()) )
+			eType = RLV_TYPE_UNKNOWN;
+		else if (optionList[1] == "add")
+			eType = RLV_TYPE_ADDREM;
+		else if (optionList[1] == "force")
+			eType = RLV_TYPE_FORCE;
+		else if (optionList[1] == "reply")
+			eType = RLV_TYPE_REPLY;
+		else
+			return RLV_RET_FAILED_OPTION;
+	}
+
+	std::list<std::string> cmdList;
+	if (RlvBehaviourDictionary::instance().getCommands((optionList.size() >= 1) ? optionList[0] : LLStringUtil::null, eType, cmdList))
+		strReply = boost::algorithm::join(cmdList, (optionList.size() >= 3) ? optionList[2] : std::string(RLV_OPTION_SEPARATOR) );
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT(RLV_BHVR_GETINV == rlvCmd.getBehaviourType());
+
+	const LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption());
+	if (!pFolder)
+		return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT;
+
+	LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+	gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems);
+	if (!pFolders)
+		return RLV_RET_FAILED;
+
+	for (S32 idxFolder = 0, cntFolder = pFolders->size(); idxFolder < cntFolder; idxFolder++)
+	{
+		// Return all folders that:
+		//   - aren't hidden
+		//   - aren't a folded folder (only really matters when "Enable Legacy Naming" is enabled - see related blog post)
+		//     (we can skip checking for .<composite> folders since the ones we'll want to hide start with '.' anyway)
+		const std::string& strFolder = pFolders->at(idxFolder)->getName();
+		if ( (!strFolder.empty()) && (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && 
+			 (!RlvInventory::isFoldedFolder(pFolders->at(idxFolder).get(), false)) )
+		{
+			if (!strReply.empty())
+				strReply.push_back(',');
+			strReply += strFolder;
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+struct rlv_wear_info { U32 cntWorn, cntTotal, cntChildWorn, cntChildTotal; };
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	// Sanity check - gAgentAvatarp can't be NULL [see RlvForceWear::isWearingItem()]
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+	// Sanity check - folder should exist
+	LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption());
+	if (!pFolder)
+		return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT;
+
+	// Collect everything @attachall would be attaching
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	RlvWearableItemCollector f(pFolder, RlvForceWear::ACTION_WEAR_REPLACE, RlvForceWear::FLAG_MATCHALL);
+	gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f, true);
+
+	rlv_wear_info wi = {0};
+
+	// Add all the folders to a lookup map 
+	std::map<LLUUID, rlv_wear_info> mapFolders;
+	mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(pFolder->getUUID(), wi));
+	for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++)
+		mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(folders.at(idxFolder)->getUUID(), wi));
+
+	// Iterate over all the found items
+	LLViewerInventoryItem* pItem; std::map<LLUUID, rlv_wear_info>::iterator itFolder;
+	for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++)
+	{
+		pItem = items.at(idxItem);
+		if (!RlvForceWear::isWearableItem(pItem))
+			continue;
+
+		// The "folded parent" is the folder this item should be considered a direct descendent of (may or may not match actual parent)
+		const LLUUID& idParent = f.getFoldedParent(pItem->getParentUUID());
+
+		// Walk up the tree: sooner or later one of the parents will be a folder in the map
+		LLViewerInventoryCategory* pParent = gInventory.getCategory(idParent);
+		while ( (itFolder = mapFolders.find(pParent->getUUID())) == mapFolders.end() )
+			pParent = gInventory.getCategory(pParent->getParentUUID());
+
+		U32 &cntWorn  = (idParent == pParent->getUUID()) ? itFolder->second.cntWorn : itFolder->second.cntChildWorn, 
+			&cntTotal = (idParent == pParent->getUUID()) ? itFolder->second.cntTotal : itFolder->second.cntChildTotal;
+
+		if (RlvForceWear::isWearingItem(pItem))
+			cntWorn++;
+		cntTotal++;
+	}
+
+	// Extract the result for the main folder
+	itFolder = mapFolders.find(pFolder->getUUID());
+	wi.cntWorn = itFolder->second.cntWorn;
+	wi.cntTotal = itFolder->second.cntTotal;
+	mapFolders.erase(itFolder);
+
+	// Build the result for each child folder
+	for (itFolder = mapFolders.begin(); itFolder != mapFolders.end(); ++itFolder)
+	{
+		rlv_wear_info& wiFolder = itFolder->second;
+
+		wi.cntChildWorn += wiFolder.cntWorn + wiFolder.cntChildWorn;
+		wi.cntChildTotal += wiFolder.cntTotal + wiFolder.cntChildTotal;
+
+		strReply += llformat(",%s|%d%d", gInventory.getCategory(itFolder->first)->getName().c_str(),
+		 (0 == wiFolder.cntTotal) ? 0 : (0 == wiFolder.cntWorn) ? 1 : (wiFolder.cntWorn != wiFolder.cntTotal) ? 2 : 3,
+		 (0 == wiFolder.cntChildTotal) ? 0 : (0 == wiFolder.cntChildWorn) ? 1 : (wiFolder.cntChildWorn != wiFolder.cntChildTotal) ? 2 : 3
+		);
+	}
+
+	// Now just prepend the root and done
+	strReply = llformat("|%d%d", (0 == wi.cntTotal) ? 0 : (0 == wi.cntWorn) ? 1 : (wi.cntWorn != wi.cntTotal) ? 2 : 3,
+		(0 == wi.cntChildTotal) ? 0 : (0 == wi.cntChildWorn) ? 1 : (wi.cntChildWorn != wi.cntChildTotal) ? 2: 3) + strReply;
+
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-19 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a
+ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT(RLV_BHVR_GETOUTFIT == rlvCmd.getBehaviourType());
+
+	// (Compatibility: RLV-1.16.1 will execute @getoutfit=<channel> if <layer> is invalid while we just return failure)
+	LLWearableType::EType wtType = LLWearableType::WT_INVALID;
+	if ( (rlvCmd.hasOption()) && ((wtType = LLWearableType::typeNameToType(rlvCmd.getOption())) == LLWearableType::WT_INVALID) )
+		return RLV_RET_FAILED_OPTION;
+
+	const LLWearableType::EType wtRlvTypes[] =
+		{ 
+			LLWearableType::WT_GLOVES, LLWearableType::WT_JACKET, LLWearableType::WT_PANTS, LLWearableType::WT_SHIRT, 
+			LLWearableType::WT_SHOES, LLWearableType::WT_SKIRT, LLWearableType::WT_SOCKS, LLWearableType::WT_UNDERPANTS, 
+			LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_SKIN, LLWearableType::WT_EYES, LLWearableType::WT_HAIR, 
+			LLWearableType::WT_SHAPE, LLWearableType::WT_ALPHA, LLWearableType::WT_TATTOO, LLWearableType::WT_PHYSICS
+		};
+
+	for (int idxType = 0, cntType = sizeof(wtRlvTypes) / sizeof(LLWearableType::EType); idxType < cntType; idxType++)
+	{
+		if ( (LLWearableType::WT_INVALID == wtType) || (wtRlvTypes[idxType] == wtType) )
+		{
+			// We never hide body parts, even if they're "locked" and we're hiding locked layers
+			// (nor do we hide a layer if the issuing object is the only one that has this layer locked)
+			bool fWorn = (gAgentWearables.getWearableCount(wtRlvTypes[idxType]) > 0) && 
+				( (!RlvSettings::getHideLockedLayers()) || 
+				  (LLAssetType::AT_BODYPART == LLWearableType::getAssetType(wtRlvTypes[idxType])) ||
+				  (RlvForceWear::isForceRemovable(wtRlvTypes[idxType], true, rlvCmd.getObjectID())) );
+			strReply.push_back( (fWorn) ? '1' : '0' );
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
+ERlvCmdRet RlvHandler::onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_GETOUTFITNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDOUTFITNAMES == rlvCmd.getBehaviourType()) || 
+				(RLV_BHVR_GETREMOUTFITNAMES == rlvCmd.getBehaviourType()) );
+
+	// Sanity check - all these commands are optionless
+	if (rlvCmd.hasOption())
+		return RLV_RET_FAILED_OPTION;
+
+	for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++)
+	{
+		bool fAdd = false; LLWearableType::EType wtType = (LLWearableType::EType)idxType;
+		switch (rlvCmd.getBehaviourType())
+		{
+			case RLV_BHVR_GETOUTFITNAMES:		// Every layer that has at least one worn wearable
+				fAdd = (gAgentWearables.getWearableCount(wtType) > 0);
+				break;
+			case RLV_BHVR_GETADDOUTFITNAMES:	// Every layer that can be worn on (wear replace OR wear add)
+				fAdd = (gRlvWearableLocks.canWear(wtType) & RLV_WEAR);
+				break;
+			case RLV_BHVR_GETREMOUTFITNAMES:	// Every layer that has at least one wearable that can be force-removed
+				fAdd = RlvForceWear::isForceRemovable(wtType);
+				break;
+			default:
+				break;
+		}
+
+		if (fAdd)
+		{
+			if (!strReply.empty())
+				strReply.push_back(',');
+			strReply.append(LLWearableType::getTypeName(wtType));
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+ERlvCmdRet RlvHandler::onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType()) ); 
+
+	RlvCommandOptionGetPath rlvGetPathOption(rlvCmd);
+	if (!rlvGetPathOption.isValid())
+		return RLV_RET_FAILED_OPTION;
+
+	LLInventoryModel::cat_array_t folders;
+	if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders))
+	{
+		if (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType())
+		{
+			strReply = RlvInventory::instance().getSharedPath(folders.at(0));
+		}
+		else if (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType())
+		{
+			for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++)
+			{
+				if (!strReply.empty())
+					strReply.push_back(',');
+				strReply += RlvInventory::instance().getSharedPath(folders.at(idxFolder));
+			}
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..6cac8be2bd6cfb4b721c198b4a44f95aacf82d36
--- /dev/null
+++ b/indra/newview/rlvhandler.h
@@ -0,0 +1,255 @@
+/** 
+ *
+ * Copyright (c) 2009-2016, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_HANDLER_H
+#define RLV_HANDLER_H
+
+#include <stack>
+
+#include "rlvcommon.h"
+#if LL_GNUC
+#include "rlvhelper.h"		// Needed to make GCC happy
+#endif // LL_GNUC
+
+// ============================================================================
+
+class RlvHandler : public LLOldEvents::LLSimpleListener
+{
+public:
+	RlvHandler();
+	~RlvHandler();
+
+	// --------------------------------
+
+	/*
+	 * Rule checking functions
+	 */
+	// NOTE: - to check @detach=n    -> (see RlvAttachmentLocks)
+	//       - to check @addattach=n -> (see RlvAttachmentLocks)
+	//       - to check @remattach=n -> (see RlvAttachmentLocks)
+	//       - to check @addoutfit=n -> (see RlvWearableLocks)
+	//       - to check @remoutfit=n -> (see RlvWearableLocks)
+	//       - to check exceptions   -> isException()
+public:
+	// Returns a list of all objects containing the specified behaviour
+	bool findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& lObjects) const;
+	// Returns TRUE is at least one object contains the specified behaviour (and optional option)
+	bool hasBehaviour(ERlvBehaviour eBhvr) const { return (eBhvr < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBhvr]) : false; }
+	bool hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const;
+	// Returns TRUE if the specified object contains the specified behaviour (and optional option)
+	bool hasBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const;
+	// Returns TRUE if at least one object (except the specified one) contains the specified behaviour (and optional option)
+	bool hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const;
+	bool hasBehaviourExcept(ERlvBehaviour eBhvr, const std::string& strOption, const LLUUID& idObj) const;
+	// Returns TRUE if at least one object in the linkset with specified root ID contains the specified behaviour (and optional option)
+	bool hasBehaviourRoot(const LLUUID& idObjRoot, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const;
+
+	// Adds or removes an exception for the specified behaviour
+	void addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption);
+	void removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption);
+	// Returns TRUE if the specified behaviour has an added exception 
+	bool hasException(ERlvBehaviour eBhvr) const;
+	// Returns TRUE if the specified option was added as an exception for the specified behaviour
+	bool isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck = RLV_CHECK_DEFAULT) const;
+	// Returns TRUE if the specified behaviour should behave "permissive" (rather than "strict"/"secure")
+	bool isPermissive(ERlvBehaviour eBhvr) const;
+
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// Returns TRUE if the composite folder doesn't contain any "locked" items
+	bool canTakeOffComposite(const LLInventoryCategory* pFolder) const;
+	// Returns TRUE if the composite folder doesn't replace any "locked" items
+	bool canWearComposite(const LLInventoryCategory* pFolder) const;
+	// Returns TRUE if the folder is a composite folder and optionally returns the name
+	bool getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const;
+	// Returns TRUE if the inventory item belongs to a composite folder and optionally returns the name and composite folder
+	bool getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const;
+	// Returns TRUE if the folder is a composite folder
+	bool isCompositeFolder(const LLInventoryCategory* pFolder) const { return getCompositeInfo(pFolder, NULL); }
+	// Returns TRUE if the inventory item belongs to a composite folder
+	bool isCompositeDescendent(const LLUUID& idItem) const { return getCompositeInfo(idItem, NULL, NULL); }
+	// Returns TRUE if the inventory item is part of a folded composite folder and should be hidden from @getoufit or @getattach
+	bool isHiddenCompositeItem(const LLUUID& idItem, const std::string& strItemType) const;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	// --------------------------------
+
+	/*
+	 * Helper functions 
+	 */
+public:
+	// Accessors
+	const LLUUID&     getAgentGroup() const			{ return m_idAgentGroup; }					// @setgroup
+	bool              getCanCancelTp() const		{ return m_fCanCancelTp; }					// @accepttp and @tpto
+	void              setCanCancelTp(bool fAllow)	{ m_fCanCancelTp = fAllow; }				// @accepttp and @tpto
+	const LLVector3d& getSitSource() const						{ return m_posSitSource; }		// @standtp
+	void              setSitSource(const LLVector3d& posSource)	{ m_posSitSource = posSource; }	// @standtp
+
+	// Command specific helper functions
+	bool canShowHoverText(const LLViewerObject* pObj) const;									// @showhovertext* command family
+	bool canTouch(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero) const;	// @touch
+	bool filterChat(std::string& strUTF8Text, bool fFilterEmote) const;							// @sendchat, @recvchat and @redirchat
+	bool redirectChatOrEmote(const std::string& strUTF8Test) const;								// @redirchat and @rediremote
+
+	// Command processing helper functions
+	ERlvCmdRet processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj);
+	void       processRetainedCommands(ERlvBehaviour eBhvrFilter = RLV_BHVR_UNKNOWN, ERlvParamType eTypeFilter = RLV_TYPE_UNKNOWN);
+
+	// Returns a pointer to the currently executing command (do *not* save this pointer)
+	const RlvCommand* getCurrentCommand() const { return (!m_CurCommandStack.empty()) ? m_CurCommandStack.top() : NULL; }
+	// Returns the UUID of the object we're currently executing a command for
+	const LLUUID&     getCurrentObject() const	{ return (!m_CurObjectStack.empty()) ? m_CurObjectStack.top() : LLUUID::null; }
+
+	// Initialization
+	static BOOL canDisable();
+	static BOOL isEnabled()	{ return m_fEnabled; }
+	static BOOL setEnabled(BOOL fEnable);
+protected:
+	void clearState();
+
+	// --------------------------------
+
+	/*
+	 * Event handling
+	 */
+public:
+	// The behaviour signal is triggered whenever a command is successfully processed and resulted in adding or removing a behaviour
+	typedef boost::signals2::signal<void (ERlvBehaviour, ERlvParamType)> rlv_behaviour_signal_t;
+	boost::signals2::connection setBehaviourCallback(const rlv_behaviour_signal_t::slot_type& cb )		 { return m_OnBehaviour.connect(cb); }
+	boost::signals2::connection setBehaviourToggleCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviourToggle.connect(cb); }
+	// The command signal is triggered whenever a command is processed
+	typedef boost::signals2::signal<void (const RlvCommand&, ERlvCmdRet, bool)> rlv_command_signal_t;
+	boost::signals2::connection setCommandCallback(const rlv_command_signal_t::slot_type& cb )			 { return m_OnCommand.connect(cb); }
+
+	void addCommandHandler(RlvExtCommandHandler* pHandler);
+	void removeCommandHandler(RlvExtCommandHandler* pHandler);
+protected:
+	void clearCommandHandlers();
+	bool notifyCommandHandlers(rlvExtCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const;
+
+	// Externally invoked event handlers
+public:
+	bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata);			// Implementation of public LLSimpleListener
+	void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	bool onGC();
+	void onLoginComplete();
+	void onSitOrStand(bool fSitting);
+	void onTeleportFailed();
+	void onTeleportFinished(const LLVector3d& posArrival);
+	static void onIdleStartup(void* pParam);
+
+	/*
+	 * Command processing
+	 */
+protected:
+	ERlvCmdRet processCommand(const RlvCommand& rlvCmd, bool fFromObj);
+	ERlvCmdRet processClearCommand(const RlvCommand& rlvCmd);
+
+	// Command handlers (RLV_TYPE_ADD and RLV_TYPE_CLEAR)
+	ERlvCmdRet processAddRemCommand(const RlvCommand& rlvCmd);
+	ERlvCmdRet onAddRemFolderLock(const RlvCommand& rlvCmd, bool& fRefCount);
+	ERlvCmdRet onAddRemFolderLockException(const RlvCommand& rlvCmd, bool& fRefCount);
+	// Command handlers (RLV_TYPE_FORCE)
+	ERlvCmdRet processForceCommand(const RlvCommand& rlvCmd) const;
+	ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const;
+	void       onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) const;
+	// Command handlers (RLV_TYPE_REPLY)
+	ERlvCmdRet processReplyCommand(const RlvCommand& rlvCmd) const;
+	ERlvCmdRet onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const;
+
+	// --------------------------------
+
+	/*
+	 * Member variables
+	 */
+public:
+	typedef std::map<LLUUID, RlvObject> rlv_object_map_t;
+	typedef std::multimap<ERlvBehaviour, RlvException> rlv_exception_map_t;
+protected:
+	rlv_object_map_t      m_Objects;				// Map of objects that have active restrictions (idObj -> RlvObject)
+	rlv_exception_map_t   m_Exceptions;				// Map of currently active restriction exceptions (ERlvBehaviour -> RlvException)
+	S16                   m_Behaviours[RLV_BHVR_COUNT];
+
+	rlv_command_list_t    m_Retained;
+	RlvGCTimer*           m_pGCTimer;
+
+	std::stack<const RlvCommand*> m_CurCommandStack;// Convenience (see @tpto)
+	std::stack<LLUUID>    m_CurObjectStack;			// Convenience (see @tpto)
+
+	rlv_behaviour_signal_t m_OnBehaviour;
+	rlv_behaviour_signal_t m_OnBehaviourToggle;
+	rlv_command_signal_t   m_OnCommand;
+	mutable std::list<RlvExtCommandHandler*> m_CommandHandlers;
+
+	static BOOL			  m_fEnabled;				// Use setEnabled() to toggle this
+
+	bool				m_fCanCancelTp;				// @accepttp=n and @tpto=force
+	mutable LLVector3d	m_posSitSource;				// @standtp=n (mutable because onForceXXX handles are all declared as const)
+	mutable LLUUID		m_idAgentGroup;				// @setgroup=n
+
+	friend class RlvSharedRootFetcher;				// Fetcher needs access to m_fFetchComplete
+	friend class RlvGCTimer;						// Timer clear its own point at destruction
+	template<ERlvBehaviourOptionType optionType> friend struct RlvBehaviourGenericHandler;
+	template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl;
+	template<ERlvParamType, ERlvBehaviour> friend struct RlvCommandHandler;
+
+	// --------------------------------
+
+	/*
+	 * Internal access functions used by unit tests
+	 */
+public:
+	const rlv_object_map_t*    getObjectMap() const		{ return &m_Objects; }
+	//const rlv_exception_map_t* getExceptionMap() const	{ return &m_Exceptions; }
+};
+
+typedef RlvHandler rlv_handler_t;
+extern rlv_handler_t gRlvHandler;
+
+// ============================================================================
+// Inlined member functions
+//
+
+// Checked: 2010-03-27 (RLVa-1.4.0a) | Modified: RLVa-1.0.0f
+inline bool RlvHandler::canShowHoverText(const LLViewerObject *pObj) const
+{
+	return ( (!pObj) || (LL_PCODE_VOLUME != pObj->getPCode()) ||
+		    !( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTALL)) ||
+			   ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTWORLD)) && (!pObj->isHUDAttachment()) ) ||
+			   ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTHUD)) && (pObj->isHUDAttachment()) ) ||
+			   (isException(RLV_BHVR_SHOWHOVERTEXT, pObj->getID(), RLV_CHECK_PERMISSIVE)) ) );
+}
+
+inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const
+{
+	return hasBehaviourExcept(eBhvr, strOption, LLUUID::null);
+}
+
+inline bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const
+{
+	return hasBehaviourExcept(eBhvr, LLStringUtil::null, idObj);
+}
+
+// ============================================================================
+
+#endif // RLV_HANDLER_H
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2f0ac47776c96f78e00698fdbd9a9335da4d2cf9
--- /dev/null
+++ b/indra/newview/rlvhelper.cpp
@@ -0,0 +1,1785 @@
+/**
+ *
+ * Copyright (c) 2009-2016, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ *
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to
+ * abide by those obligations.
+ *
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llappearancemgr.h"
+#include "llattachmentsmgr.h"
+#include "llgesturemgr.h"
+#include "llnotificationsutil.h"
+#include "llviewerobjectlist.h"
+
+#include "rlvcommon.h"
+#include "rlvhelper.h"
+#include "rlvhandler.h"
+#include "rlvinventory.h"
+
+#include <boost/algorithm/string.hpp>
+
+// ============================================================================
+// RlvBehaviourDictionary
+//
+
+/*
+ * Processing of RLVa commands used to be a big switch/case loop with one function for each command type(addrem, reply
+ * and force). This is slowly being replaced with templated command handling which might be more confusing intially
+ * (also due to my poor naming schemes) but is actually far simpler and less error-prone than the old way.
+ *
+ * In the general case you just add a definition for the command below and then write the function body in rlvhandler.cpp
+ * and you're done! Told you this was easy.
+ *
+ * Reply command
+ * =============
+ * Definition: RlvReplyProcessor<RLV_BHVR_COMMANDNAME>("commandname"[, <options>]));
+ * Implement : ERlvCmdRet RlvReplyHandler<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+ *
+ * Force command
+ * =============
+ * Definition: new RlvForceProcessor<RLV_BHVR_COMMANDNAME>("commandname"[, <options>]));
+ * Implement : ERlvCmdRet RlvForceProcessor<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd)
+ *
+ * Behaviours
+ * ==========
+ * Behaviours come in many forms but the added complexity is only in the variety of choices. The implementation is as
+ * easy as reply or force commands.
+ *
+ * For simple behaviours that only require recordkeeping and don't run code when set/unset (see ERlvBehaviourOptionType):
+ *   Definition: RlvBehaviourGenericProcessor<RLV_OPTION_TYPE>("commandname", RLV_BHVR_COMMANDNAME)
+ *   Implement : nothing! (it automagically works)
+ * For simple behaviours that only require recordkeeping and only run code when they toggle:
+ *   Definition: RlvBehaviourGenericToggleProcessor<RLV_BHVR_COMMANDNAME, RLV_OPTION_TYPE>("commandname"))
+ *   Implement : void RlvBehaviourToggleHandler<RLV_BHVR_COMMANDNAME>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+ * For behaviours that require manual processing:
+ *   Definition: RlvBehaviourProcessor<RLV_BHVR_COMMANDNAME>("commandname"))
+ *   Implement : ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
+ * For behaviours that run code when their modifier changes:
+ *   Definition: addModifier(RLV_BHVR_COMMANDNAME, RLV_MODIFIER_COMMANDNAME, new RlvBehaviourModifierHandler<RLV_MODIFIER_COMMANDNAME>(<default>, <auto-add>, <comparator>));
+ *   Implement : void RlvBehaviourModifierHandler::onValueChanged()
+ *
+ */
+RlvBehaviourDictionary::RlvBehaviourDictionary()
+{
+	// Array auto-initialization to 0 is still not supported in VS2013
+	memset(m_BehaviourModifiers, 0, sizeof(RlvBehaviourModifier*) * RLV_MODIFIER_COUNT);
+
+	//
+	// Restrictions
+	//
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("acceptpermission", RLV_BHVR_ACCEPTPERMISSION));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("accepttp", RLV_BHVR_ACCEPTTP, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("accepttprequest", RLV_BHVR_ACCEPTTPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_ADDATTACH, RlvBehaviourAddRemAttachHandler>("addattach"));
+	addEntry(new RlvBehaviourInfo("addoutfit",				RLV_BHVR_ADDOUTFIT,				RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("allowidle", RLV_BHVR_ALLOWIDLE, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("alwaysrun", RLV_BHVR_ALWAYSRUN));
+	addEntry(new RlvBehaviourInfo("attachthis",				RLV_BHVR_ATTACHTHIS,			RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE));
+	addEntry(new RlvBehaviourInfo("attachallthis",			RLV_BHVR_ATTACHTHIS,			RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE));
+	addEntry(new RlvBehaviourInfo("attachthis_except",		RLV_BHVR_ATTACHTHISEXCEPT,		RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE));
+	addEntry(new RlvBehaviourInfo("attachallthis_except",	RLV_BHVR_ATTACHTHISEXCEPT,		RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatwhisper", RLV_BHVR_CHATWHISPER));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatnormal", RLV_BHVR_CHATNORMAL));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatshout", RLV_BHVR_CHATSHOUT));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_DETACH>("detach"));
+	addEntry(new RlvBehaviourInfo("detachthis",				RLV_BHVR_DETACHTHIS,			RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE));
+	addEntry(new RlvBehaviourInfo("detachallthis",			RLV_BHVR_DETACHTHIS,			RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE));
+	addEntry(new RlvBehaviourInfo("detachthis_except",		RLV_BHVR_DETACHTHISEXCEPT,		RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE));
+	addEntry(new RlvBehaviourInfo("detachallthis_except",	RLV_BHVR_DETACHTHISEXCEPT,		RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_EDIT, RLV_OPTION_NONE_OR_EXCEPTION>("edit"));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("editobj", RLV_BHVR_EDITOBJ));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("emote", RLV_BHVR_EMOTE));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("fartouch", RLV_BHVR_FARTOUCH));
+	addModifier(RLV_BHVR_FARTOUCH, RLV_MODIFIER_FARTOUCHDIST, new RlvBehaviourModifier("Fartouch Distance", RLV_MODIFIER_FARTOUCH_DEFAULT, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("fly", RLV_BHVR_FLY));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("interact", RLV_BHVR_INTERACT, RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourInfo("notify",					RLV_BHVR_NOTIFY,				RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("permissive", RLV_BHVR_PERMISSIVE));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvchat", RLV_BHVR_RECVCHAT, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvchatfrom", RLV_BHVR_RECVCHATFROM, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvemote", RLV_BHVR_RECVEMOTE, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvemotefrom", RLV_BHVR_RECVEMOTEFROM, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_RECVIM, RlvBehaviourRecvSendStartIMHandler>("recvim", RlvBehaviourInfo::BHVR_STRICT));
+	addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMIN, new RlvBehaviourModifier("RecvIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifier_CompMax));
+	addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMAX, new RlvBehaviourModifier("RecvIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvimfrom", RLV_BHVR_RECVIMFROM, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourInfo("redirchat",				RLV_BHVR_REDIRCHAT,				RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourInfo("rediremote",				RLV_BHVR_REDIREMOTE,			RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_REMATTACH, RlvBehaviourAddRemAttachHandler>("remattach"));
+	addEntry(new RlvBehaviourInfo("remoutfit",				RLV_BHVR_REMOUTFIT,				RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("rez", RLV_BHVR_REZ));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_SENDCHANNEL, RlvBehaviourSendChannelHandler>("sendchannel", RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_SENDCHANNELEXCEPT, RlvBehaviourSendChannelHandler>("sendchannel_except", RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sendchat", RLV_BHVR_SENDCHAT));
+	addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SENDIM, RlvBehaviourRecvSendStartIMHandler>("sendim", RlvBehaviourInfo::BHVR_STRICT));
+	addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMIN, new RlvBehaviourModifier("SendIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifier_CompMax));
+	addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMAX, new RlvBehaviourModifier("SendIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("sendimto", RLV_BHVR_SENDIMTO, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sendgesture", RLV_BHVR_SENDGESTURE, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETDEBUG, RLV_OPTION_NONE>("setdebug"));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETENV, RLV_OPTION_NONE>("setenv"));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("setgroup", RLV_BHVR_SETGROUP));
+	addEntry(new RlvBehaviourInfo("sharedunwear",			RLV_BHVR_SHAREDUNWEAR,			RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourInfo("sharedwear",				RLV_BHVR_SHAREDWEAR,			RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_SHOWHOVERTEXT>("showhovertext"));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertextall", RLV_BHVR_SHOWHOVERTEXTALL));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertexthud", RLV_BHVR_SHOWHOVERTEXTHUD));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertextworld", RLV_BHVR_SHOWHOVERTEXTWORLD));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWINV, RLV_OPTION_NONE>("showinv"));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showloc", RLV_BHVR_SHOWLOC));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showminimap", RLV_BHVR_SHOWMINIMAP));
+	addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SHOWNAMES>("shownames", RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SHOWNAMETAGS>("shownametags", RlvBehaviourInfo::BHVR_STRICT ));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWNEARBY, RLV_OPTION_NONE>("shownearby", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWSELF, RLV_OPTION_NONE, RlvBehaviourShowSelfToggleHandler>("showself", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWSELFHEAD, RLV_OPTION_NONE, RlvBehaviourShowSelfToggleHandler>("showselfhead", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showworldmap", RLV_BHVR_SHOWWORLDMAP));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sit", RLV_BHVR_SIT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("sittp", RLV_BHVR_SITTP));
+	addModifier(RLV_BHVR_SITTP, RLV_MODIFIER_SITTPDIST, new RlvBehaviourModifier("SitTp Distance", RLV_MODIFIER_SITTP_DEFAULT, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("standtp", RLV_BHVR_STANDTP));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_STARTIM, RlvBehaviourRecvSendStartIMHandler>("startim", RlvBehaviourInfo::BHVR_STRICT));
+	addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMIN, new RlvBehaviourModifier("StartIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifier_CompMax));
+	addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMAX, new RlvBehaviourModifier("StartIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("startimto", RLV_BHVR_STARTIMTO, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("temprun", RLV_BHVR_TEMPRUN));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchall", RLV_BHVR_TOUCHALL));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchattach", RLV_BHVR_TOUCHATTACH));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchattachother", RLV_BHVR_TOUCHATTACHOTHER));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchattachself", RLV_BHVR_TOUCHATTACHSELF));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("touchfar", RLV_BHVR_FARTOUCH, RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchhud", RLV_BHVR_TOUCHHUD, RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchme", RLV_BHVR_TOUCHME));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("touchthis", RLV_BHVR_TOUCHTHIS));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchworld", RLV_BHVR_TOUCHWORLD));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("tplm", RLV_BHVR_TPLM));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("tploc", RLV_BHVR_TPLOC));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("tplocal", RLV_BHVR_TPLOCAL, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addModifier(RLV_BHVR_TPLOCAL, RLV_MODIFIER_TPLOCALDIST, new RlvBehaviourModifier("Local Teleport Distance", RLV_MODIFIER_TPLOCAL_DEFAULT, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("tplure", RLV_BHVR_TPLURE, RlvBehaviourInfo::BHVR_STRICT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("tprequest", RLV_BHVR_TPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourInfo("unsharedunwear",			RLV_BHVR_UNSHAREDUNWEAR,		RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourInfo("unsharedwear",			RLV_BHVR_UNSHAREDWEAR,			RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("unsit", RLV_BHVR_UNSIT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewnote", RLV_BHVR_VIEWNOTE));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewscript", RLV_BHVR_VIEWSCRIPT));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewtexture", RLV_BHVR_VIEWTEXTURE));
+	// Camera
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM, RLV_OPTION_NONE>("setcam"));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addModifier(RLV_BHVR_SETCAM_AVDISTMIN, RLV_MODIFIER_SETCAM_AVDISTMIN, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_AVDISTMIN>("Camera - Avatar Distance (Min)", 0.0f, false, new RlvBehaviourModifier_CompMax()));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addModifier(RLV_BHVR_SETCAM_AVDISTMAX, RLV_MODIFIER_SETCAM_AVDISTMAX, new RlvBehaviourModifier("Camera - Avatar Distance (Max)", F32_MAX, false, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_origindistmin", RLV_BHVR_SETCAM_ORIGINDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addModifier(RLV_BHVR_SETCAM_ORIGINDISTMIN, RLV_MODIFIER_SETCAM_ORIGINDISTMIN, new RlvBehaviourModifier("Camera - Focus Distance (Min)", 0.0f, true, new RlvBehaviourModifier_CompMax));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_origindistmax", RLV_BHVR_SETCAM_ORIGINDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addModifier(RLV_BHVR_SETCAM_ORIGINDISTMAX, RLV_MODIFIER_SETCAM_ORIGINDISTMAX, new RlvBehaviourModifier("Camera - Focus Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addModifier(RLV_BHVR_SETCAM_EYEOFFSET, RLV_MODIFIER_SETCAM_EYEOFFSET, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_EYEOFFSET>("Camera - Eye Offset", LLVector3::zero, true, nullptr));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addModifier(RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_MODIFIER_SETCAM_FOCUSOFFSET, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOCUSOFFSET>("Camera - Focus Offset", LLVector3::zero, true, nullptr));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_SETCAM_FOVMIN, RlvBehaviourSetCamFovHandler>("setcam_fovmin"));
+	addModifier(RLV_BHVR_SETCAM_FOVMIN, RLV_MODIFIER_SETCAM_FOVMIN, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMIN>("Camera - FOV (Min)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifier_CompMax));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_SETCAM_FOVMAX, RlvBehaviourSetCamFovHandler>("setcam_fovmax"));
+	addModifier(RLV_BHVR_SETCAM_FOVMAX, RLV_MODIFIER_SETCAM_FOVMAX, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMAX>("Camera - FOV (Max)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifier_CompMin));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_MOUSELOOK, RLV_OPTION_NONE>("setcam_mouselook"));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("setcam_textures", RLV_BHVR_SETCAM_TEXTURES));
+	addModifier(RLV_BHVR_SETCAM_TEXTURES, RLV_MODIFIER_SETCAM_TEXTURE, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_TEXTURE>("Camera - Forced Texture", IMG_DEFAULT, true, nullptr));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_UNLOCK, RLV_OPTION_NONE>("setcam_unlock"));
+	// Camera (compatibility shim - to be deprecated)
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("camdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("camdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("camtextures", RLV_BHVR_SETCAM_TEXTURES, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_CAMZOOMMIN, RlvBehaviourCamZoomMinMaxHandler>("camzoommin", RlvBehaviourInfo::BHVR_DEPRECATED));
+	addEntry(new RlvBehaviourProcessor<RLV_BHVR_CAMZOOMMAX, RlvBehaviourCamZoomMinMaxHandler>("camzoommax", RlvBehaviourInfo::BHVR_DEPRECATED));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_UNLOCK, RLV_OPTION_NONE>("camunlock", RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED));
+
+	//
+	// Force-wear
+	//
+	addEntry(new RlvBehaviourInfo("attach",					RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	addEntry(new RlvBehaviourInfo("attachall",				RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	addEntry(new RlvBehaviourInfo("attachover",				RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	addEntry(new RlvBehaviourInfo("attachallover",			RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	addEntry(new RlvBehaviourInfo("attachthis",				RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT));
+	addEntry(new RlvBehaviourInfo("attachallthis",			RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT));
+	addEntry(new RlvBehaviourInfo("attachthisover",			RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT));
+	addEntry(new RlvBehaviourInfo("attachallthisover",		RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT));
+	addEntry(new RlvForceProcessor<RLV_BHVR_DETACH, RlvForceRemAttachHandler>("detach",			RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE  | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	addEntry(new RlvBehaviourInfo("detachall",				RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE  | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	addEntry(new RlvBehaviourInfo("detachthis",				RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE  | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT));
+	addEntry(new RlvBehaviourInfo("detachallthis",			RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE  | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT));
+	addEntry(new RlvForceProcessor<RLV_BHVR_REMATTACH, RlvForceRemAttachHandler>("remattach",	RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE  | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	addEntry(new RlvForceProcessor<RLV_BHVR_REMOUTFIT>("remoutfit",                             RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE  | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE));
+	// Synonyms (addoutfit* -> attach*)														   
+	addEntry(new RlvBehaviourInfo("addoutfit",				RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE   | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("addoutfitall",			RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE   | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("addoutfitover",			RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE   | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("addoutfitallover",		RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE   | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("addoutfitthis",			RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("addoutfitallthis",		RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("addoutfitthisover",		RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("addoutfitallthisover",	RLV_CMD_FORCEWEAR,	RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD     | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM));
+	// Synonyms (attach*overorreplace -> attach*)														   
+	addEntry(new RlvBehaviourInfo("attachoverorreplace",	RLV_CMD_FORCEWEAR,  RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE   | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("attachalloverorreplace",	RLV_CMD_FORCEWEAR,  RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE   | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("attachthisoverorreplace",RLV_CMD_FORCEWEAR,  RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE    | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM));
+	addEntry(new RlvBehaviourInfo("attachallthisoverorreplace",RLV_CMD_FORCEWEAR,RLV_TYPE_FORCE,RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM));
+
+	//
+	// Force-only
+	//
+	addEntry(new RlvBehaviourInfo("adjustheight",			RLV_BHVR_ADJUSTHEIGHT,			RLV_TYPE_FORCE));
+	addEntry(new RlvForceProcessor<RLV_BHVR_DETACHME>("detachme"));
+	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUS>("setcam_focus", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOV>("setcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_MODE>("setcam_mode", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvForceProcessor<RLV_BHVR_SETGROUP>("setgroup"));
+	addEntry(new RlvForceProcessor<RLV_BHVR_SIT>("sit"));
+	addEntry(new RlvForceProcessor<RLV_BHVR_TPTO>("tpto"));
+	addEntry(new RlvBehaviourInfo("unsit",					RLV_BHVR_UNSIT,					RLV_TYPE_FORCE));
+
+	//
+	// Reply-only
+	//
+	addEntry(new RlvBehaviourInfo("findfolder",				RLV_BHVR_FINDFOLDER,			RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("findfolders",			RLV_BHVR_FINDFOLDERS,			RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourInfo("getaddattachnames",		RLV_BHVR_GETADDATTACHNAMES,		RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourInfo("getaddoutfitnames",		RLV_BHVR_GETADDOUTFITNAMES,		RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourInfo("getattach",				RLV_BHVR_GETATTACH,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getattachnames",			RLV_BHVR_GETATTACHNAMES,		RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDIST>("getcam_avdist", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDISTMIN, RlvReplyCamMinMaxModifierHandler>("getcam_avdistmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDISTMAX, RlvReplyCamMinMaxModifierHandler>("getcam_avdistmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOV>("getcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOVMIN, RlvReplyCamMinMaxModifierHandler>("getcam_fovmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOVMAX, RlvReplyCamMinMaxModifierHandler>("getcam_fovmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_TEXTURES>("getcam_textures", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvReplyProcessor<RLV_BHVR_GETCOMMAND>("getcommand", RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourInfo("getgroup",				RLV_BHVR_GETGROUP,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getinv",					RLV_BHVR_GETINV,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getinvworn",				RLV_BHVR_GETINVWORN,			RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getoutfit",				RLV_BHVR_GETOUTFIT,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getoutfitnames",			RLV_BHVR_GETOUTFITNAMES,		RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourInfo("getpath",				RLV_BHVR_GETPATH,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getpathnew",				RLV_BHVR_GETPATHNEW,			RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getremattachnames",		RLV_BHVR_GETREMATTACHNAMES,		RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourInfo("getremoutfitnames",		RLV_BHVR_GETREMOUTFITNAMES,		RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL));
+	addEntry(new RlvBehaviourInfo("getsitid",				RLV_BHVR_GETSITID,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getstatus",				RLV_BHVR_GETSTATUS,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("getstatusall",			RLV_BHVR_GETSTATUSALL,			RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("version",				RLV_BHVR_VERSION,				RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("versionnew",				RLV_BHVR_VERSIONNEW,			RLV_TYPE_REPLY));
+	addEntry(new RlvBehaviourInfo("versionnum",				RLV_BHVR_VERSIONNUM,			RLV_TYPE_REPLY));
+
+	// Populate m_String2InfoMap (the tuple <behaviour, type> should be unique)
+	for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList)
+	{
+		RLV_VERIFY(m_String2InfoMap.insert(std::make_pair(std::make_pair(pBhvrInfo->getBehaviour(), (ERlvParamType)pBhvrInfo->getParamTypeMask()), pBhvrInfo)).second == true);
+	}
+
+	// Populate m_Bhvr2InfoMap (there can be multiple entries per ERlvBehaviour)
+	for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList)
+	{
+		if ( (pBhvrInfo->getParamTypeMask() & RLV_TYPE_ADDREM) && (!pBhvrInfo->isSynonym()) )
+		{
+#ifdef RLV_DEBUG
+			for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(pBhvrInfo->getBehaviourType()), m_Bhvr2InfoMap.upper_bound(pBhvrInfo->getBehaviourType())))
+			{
+				RLV_ASSERT( (itBhvr.first != pBhvrInfo->getBehaviourType()) || (itBhvr.second->getBehaviourFlags() != pBhvrInfo->getBehaviourFlags()) );
+			}
+#endif // RLV_DEBUG
+			m_Bhvr2InfoMap.insert(std::pair<ERlvBehaviour, const RlvBehaviourInfo*>(pBhvrInfo->getBehaviourType(), pBhvrInfo));
+		}
+	}
+
+	// Process blocked commands
+	if (RlvSettings::getNoSetEnv())
+		toggleBehaviourFlag("setenv", RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_BLOCKED, true);
+}
+
+RlvBehaviourDictionary::~RlvBehaviourDictionary()
+{
+	for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList)
+		delete pBhvrInfo;
+	m_BhvrInfoList.clear();
+
+	for (int idxBhvrMod = 0; idxBhvrMod < RLV_MODIFIER_COUNT; idxBhvrMod++)
+	{
+		delete m_BehaviourModifiers[idxBhvrMod];
+		m_BehaviourModifiers[idxBhvrMod] = nullptr;
+	}
+}
+
+void RlvBehaviourDictionary::addEntry(const RlvBehaviourInfo* pEntry)
+{
+	// Filter experimental commands (if disabled)
+	static LLCachedControl<bool> sEnableExperimental(gSavedSettings, "RLVaExperimentalCommands");
+	if ( (!pEntry) || ((!sEnableExperimental) && (pEntry->isExperimental())) )
+	{
+		return;
+	}
+
+	// Sanity check for duplicate entries
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	std::for_each(m_BhvrInfoList.begin(), m_BhvrInfoList.end(), 
+	              [&pEntry](const RlvBehaviourInfo* pBhvrInfo) { 
+					RLV_ASSERT_DBG( ((pBhvrInfo->getBehaviour()) != (pEntry->getBehaviour())) || ((pBhvrInfo->getParamTypeMask() & pEntry->getParamTypeMask()) == 0) );
+	              });
+#endif // LL_RELEASE_FOR_DOWNLOAD
+
+	m_BhvrInfoList.push_back(pEntry);
+}
+
+void RlvBehaviourDictionary::addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry)
+{
+	if (eModifier < RLV_MODIFIER_COUNT)
+	{
+		m_BehaviourModifiers[eModifier] = pModifierEntry;
+		m_Bhvr2ModifierMap.insert(std::make_pair(eBhvr, eModifier));
+	}
+}
+
+const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
+{
+	bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec");
+	if (pfStrict)
+		*pfStrict = fStrict;
+
+	rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair( (!fStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType));
+	return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : NULL;
+}
+
+ERlvBehaviour RlvBehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
+{
+	const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict);
+	return (pBhvrInfo) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN;
+}
+
+bool RlvBehaviourDictionary::getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const
+{
+	cmdList.clear();
+	for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList)
+	{
+		if ( (pBhvrInfo->getParamTypeMask() & eParamType) || (RLV_TYPE_UNKNOWN == eParamType) )
+		{
+			std::string strCmd = pBhvrInfo->getBehaviour();
+			if ( (std::string::npos != strCmd.find(strMatch)) || (strMatch.empty()) )
+				cmdList.push_back(strCmd);
+			if ( (pBhvrInfo->hasStrict()) && ((std::string::npos != strCmd.append("_sec").find(strMatch)) || (strMatch.empty())) )
+				cmdList.push_back(strCmd);
+		}
+	}
+	return !cmdList.empty();
+}
+
+bool RlvBehaviourDictionary::getHasStrict(ERlvBehaviour eBhvr) const
+{
+	for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(eBhvr), m_Bhvr2InfoMap.upper_bound(eBhvr)))
+	{
+		// Only restrictions can be strict
+		if (RLV_TYPE_ADDREM != itBhvr.second->getParamTypeMask())
+			continue;
+		return itBhvr.second->hasStrict();
+	}
+	RLV_ASSERT(false);
+	return false;
+}
+
+RlvBehaviourModifier* RlvBehaviourDictionary::getModifierFromBehaviour(ERlvBehaviour eBhvr) const
+{
+	rlv_bhvr2mod_map_t::const_iterator itMod = m_Bhvr2ModifierMap.find(eBhvr);
+	ERlvBehaviourModifier eBhvrMod = (m_Bhvr2ModifierMap.end() != itMod) ? itMod->second : RLV_MODIFIER_UNKNOWN;
+	return (eBhvrMod < RLV_MODIFIER_UNKNOWN) ? m_BehaviourModifiers[eBhvrMod] : nullptr;
+}
+
+void RlvBehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBhvrFlag, bool fEnable)
+{
+	rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair(strBhvr, (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType));
+	if (m_String2InfoMap.end() != itBhvr)
+	{
+		const_cast<RlvBehaviourInfo*>(itBhvr->second)->toggleBehaviourFlag(eBhvrFlag, fEnable);
+	}
+}
+
+// ============================================================================
+// RlvBehaviourModifier
+//
+
+RlvBehaviourModifier::RlvBehaviourModifier(std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator)
+	: m_strName(strName), m_DefaultValue(defaultValue), m_fAddDefaultOnEmpty(fAddDefaultOnEmpty), m_pValueComparator(pValueComparator)
+{
+	m_pValueComparator = (pValueComparator) ? pValueComparator : new RlvBehaviourModifier_Comp();
+}
+
+RlvBehaviourModifier::~RlvBehaviourModifier()
+{
+	if (m_pValueComparator)
+	{
+		delete m_pValueComparator;
+		m_pValueComparator = NULL;
+	}
+}
+
+bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject)
+{
+	if (modValue.which() == m_DefaultValue.which())
+	{
+		m_Values.insert((m_pValueComparator) ? std::lower_bound(m_Values.begin(), m_Values.end(), std::make_pair(modValue, idObject), boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2)) : m_Values.end(), std::make_pair(modValue, idObject));
+		// NOTE: change signal needs to trigger before modifier handlers so cached values have a chance to update properly
+		m_ChangeSignal(getValue());
+		onValueChange();
+		return true;
+	}
+	return false;
+}
+
+const LLUUID& RlvBehaviourModifier::getPrimaryObject() const
+{
+	return (m_pValueComparator) ? m_pValueComparator->m_idPrimaryObject : LLUUID::null;
+}
+
+bool RlvBehaviourModifier::hasValue() const {
+	// If no primary object is set this returns "any value set"; otherwise it returns "any value set by the primary object"
+	if ( (!m_pValueComparator) || (m_pValueComparator->m_idPrimaryObject.isNull()) )
+		return !m_Values.empty();
+	return (!m_Values.empty()) ? m_Values.front().second == m_pValueComparator->m_idPrimaryObject : false;
+}
+
+void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject)
+{
+	if ( (modValue.which() == m_DefaultValue.which()) )
+	{
+		auto itValue = std::find(m_Values.begin(), m_Values.end(), std::make_pair(modValue, idObject));
+		if (m_Values.end() != itValue)
+		{
+			m_Values.erase(itValue);
+			onValueChange();
+			m_ChangeSignal(getValue());
+		}
+	}
+}
+
+void RlvBehaviourModifier::setPrimaryObject(const LLUUID& idPrimaryObject)
+{
+	if (m_pValueComparator)
+	{
+		m_pValueComparator->m_idPrimaryObject = idPrimaryObject;
+		m_Values.sort(boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2));
+		onValueChange();
+		m_ChangeSignal(getValue());
+	}
+}
+
+bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const
+{
+	try
+	{
+		if (typeid(float) == m_DefaultValue.type())
+		{
+			modValue = std::stof(optionValue);
+			return true;
+		}
+		else if (typeid(int) == m_DefaultValue.type())
+		{
+			modValue = std::stoi(optionValue);
+			return true;
+		}
+		else if (typeid(LLVector3) == m_DefaultValue.type())
+		{
+			LLVector3 vecOption;
+			if (3 == sscanf(optionValue.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2))
+			{
+				modValue = vecOption;
+				return true;
+			}
+		}
+		else if (typeid(LLUUID) == m_DefaultValue.type())
+		{
+			LLUUID idOption;
+			if (LLUUID::parseUUID(optionValue, &idOption))
+			{
+				modValue = idOption;
+				return true;
+			}
+		}
+		return false;
+	}
+	catch (const std::invalid_argument&)
+	{
+		return false;
+	}
+}
+
+// ============================================================================
+// RlvCommmand
+//
+
+RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand)
+	: m_fValid(false), m_idObj(idObj), m_pBhvrInfo(NULL), m_eParamType(RLV_TYPE_UNKNOWN), m_fStrict(false), m_fRefCounted(false)
+{
+	if (m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam))
+	{
+		S32 nTemp = 0;
+		if ( ("n" == m_strParam) || ("add" == m_strParam) )
+			m_eParamType = RLV_TYPE_ADD;
+		else if ( ("y" == m_strParam) || ("rem" == m_strParam) )
+			m_eParamType = RLV_TYPE_REMOVE;
+		else if (m_strBehaviour == "clear")						// clear is the odd one out so just make it its own type
+			m_eParamType = RLV_TYPE_CLEAR;
+		else if ("force" == m_strParam)
+			m_eParamType = RLV_TYPE_FORCE;
+		else if (LLStringUtil::convertToS32(m_strParam, nTemp))	// Assume it's a reply command if we can convert <param> to an S32
+			m_eParamType = RLV_TYPE_REPLY;
+		else
+		{
+			m_eParamType = RLV_TYPE_UNKNOWN;
+			m_fValid = false;
+		}
+	}
+
+	if (!m_fValid)
+	{
+		m_strOption = m_strParam = "";
+		return;
+	}
+
+	m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict);
+}
+
+RlvCommand::RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType)
+	: m_fValid(rlvCmd.m_fValid), m_idObj(rlvCmd.m_idObj), m_strBehaviour(rlvCmd.m_strBehaviour), m_pBhvrInfo(rlvCmd.m_pBhvrInfo),
+	  m_eParamType( (RLV_TYPE_UNKNOWN == eParamType) ? rlvCmd.m_eParamType : eParamType),m_fStrict(rlvCmd.m_fStrict), m_strOption(rlvCmd.m_strOption), m_strParam(rlvCmd.m_strParam), m_fRefCounted(false)
+{
+}
+
+bool RlvCommand::parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam)
+{
+	// (See behaviour notes for the command parsing truth table)
+
+	// Format: <behaviour>[:<option>]=<param>
+	int idxParam  = strCommand.find('=');
+	int idxOption = (idxParam > 0) ? strCommand.find(':') : -1;
+	if (idxOption > idxParam - 1)
+		idxOption = -1;
+
+	// If <behaviour> is missing it's always an improperly formatted command
+	if ( (0 == idxOption) || (0 == idxParam) )
+		return false;
+
+	strBehaviour = strCommand.substr(0, (-1 != idxOption) ? idxOption : idxParam);
+	strOption = strParam = "";
+
+	// If <param> is missing it's an improperly formatted command
+	if ( (-1 == idxParam) || ((int)strCommand.length() - 1 == idxParam) )
+	{
+		// Unless "<behaviour> == "clear" AND (idxOption == 0)" 
+		// OR <behaviour> == "clear" AND (idxParam != 0) [see table above]
+		if ( ("clear" == strBehaviour) && ( (!idxOption) || (idxParam) ) )
+			return true;
+		return false;
+	}
+
+	if ( (-1 != idxOption) && (idxOption + 1 != idxParam) )
+		strOption = strCommand.substr(idxOption + 1, idxParam - idxOption - 1);
+	strParam = strCommand.substr(idxParam + 1);
+
+	return true;
+}
+
+// ============================================================================
+// Command option parsing utility classes
+//
+
+template<>
+bool RlvCommandOptionHelper::parseOption<LLUUID>(const std::string& strOption, LLUUID& idOption)
+{
+	idOption.set(strOption);
+	return idOption.notNull();
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<int>(const std::string& strOption, int& nOption)
+{
+	try
+	{
+		nOption = std::stoi(strOption);
+	}
+	catch (const std::invalid_argument&)
+	{
+		return false;
+	}
+	return true;
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<float>(const std::string& strOption, float& nOption)
+{
+	try
+	{
+		nOption = std::stof(strOption);
+	}
+	catch (const std::invalid_argument&)
+	{
+		return false;
+	}
+	return true;
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<LLWearableType::EType>(const std::string& strOption, LLWearableType::EType& wtOption)
+{
+	wtOption = LLWearableType::typeNameToType(strOption);
+	return (LLWearableType::WT_INVALID != wtOption) && (LLWearableType::WT_NONE != wtOption);
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<LLViewerJointAttachment*>(const std::string& strOption, LLViewerJointAttachment*& pAttachPt)
+{
+	pAttachPt = RlvAttachPtLookup::getAttachPoint(strOption);
+	return pAttachPt != NULL;
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<ERlvAttachGroupType>(const std::string& strOption, ERlvAttachGroupType& eAttachGroup)
+{
+	eAttachGroup = rlvAttachGroupFromString(strOption);
+	return eAttachGroup != RLV_ATTACHGROUP_INVALID;
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<LLViewerInventoryCategory*>(const std::string& strOption, LLViewerInventoryCategory*& pFolder)
+{
+	pFolder = RlvInventory::instance().getSharedFolder(strOption);
+	return pFolder != NULL;
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<LLVector3>(const std::string& strOption, LLVector3& vecOption)
+ {
+	if (!strOption.empty())
+	{
+		S32 cntToken = sscanf(strOption.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2);
+		return (3 == cntToken);
+	}
+	return false;
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<LLVector3d>(const std::string& strOption, LLVector3d& vecOption)
+ {
+	if (!strOption.empty())
+	{
+		S32 cntToken = sscanf(strOption.c_str(), "%lf/%lf/%lf", vecOption.mdV + 0, vecOption.mdV + 1, vecOption.mdV + 2);
+		return (3 == cntToken);
+	}
+	return false;
+}
+
+template<>
+bool RlvCommandOptionHelper::parseOption<RlvCommandOptionGeneric>(const std::string& strOption, RlvCommandOptionGeneric& genericOption)
+{
+	LLWearableType::EType wtType(LLWearableType::WT_INVALID); LLUUID idOption; ERlvAttachGroupType eAttachGroup(RLV_ATTACHGROUP_INVALID);
+	LLViewerJointAttachment* pAttachPt = NULL; LLViewerInventoryCategory* pFolder = NULL; LLVector3d posOption; float nOption;
+
+	if (!strOption.empty())																		// <option> could be an empty string
+	{
+		if (RlvCommandOptionHelper::parseOption(strOption, wtType))
+			genericOption = wtType;																// ... or specify a (valid) clothing layer
+		else if (RlvCommandOptionHelper::parseOption(strOption, pAttachPt))
+			genericOption = pAttachPt;															// ... or specify an attachment point
+		else if (RlvCommandOptionHelper::parseOption(strOption, idOption))
+			genericOption = idOption;															// ... or specify an UUID
+		else if (RlvCommandOptionHelper::parseOption(strOption, pFolder))
+			genericOption = pFolder;															// ... or specify a shared folder path
+		else if (RlvCommandOptionHelper::parseOption(strOption, eAttachGroup))
+			genericOption = eAttachGroup;														// ... or specify an attachment point group
+		else if (RlvCommandOptionHelper::parseOption(strOption, posOption))
+			genericOption = posOption;															// ... or specify a vector (region or global coordinates)
+		else if (RlvCommandOptionHelper::parseOption(strOption, nOption))
+			genericOption = nOption;															// ... or specify a number
+		else
+			genericOption = strOption;															// ... or it might just be a string
+	}
+	return true;
+}
+
+bool RlvCommandOptionHelper::parseStringList(const std::string& strOption, std::vector<std::string>& optionList, const std::string& strSeparator)
+{
+	if (!strOption.empty())
+		boost::split(optionList, strOption, boost::is_any_of(strSeparator));
+	return !optionList.empty();
+}
+
+// ============================================================================
+// RlvCommandOption structures
+//
+
+// Checked: 2012-07-28 (RLVa-1.4.7)
+class RlvCommandOptionGetPathCallback
+{
+public:
+	RlvCommandOptionGetPathCallback(const LLUUID& idAttachObj, RlvCommandOptionGetPath::getpath_callback_t cb)
+		: mObjectId(idAttachObj), mCallback(cb)
+	{
+		if (isAgentAvatarValid())
+			mAttachmentConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(&RlvCommandOptionGetPathCallback::onAttachment, this, _1, _3));
+		gIdleCallbacks.addFunction(&onIdle, this);
+	}
+
+	~RlvCommandOptionGetPathCallback()
+	{
+		if (mAttachmentConnection.connected())
+			mAttachmentConnection.disconnect();
+		gIdleCallbacks.deleteFunction(&onIdle, this);
+	}
+
+	void onAttachment(LLViewerObject* pAttachObj, LLVOAvatarSelf::EAttachAction eAction)
+	{
+		if ( (LLVOAvatarSelf::ACTION_ATTACH == eAction) && (pAttachObj->getID() == mObjectId) )
+		{
+			uuid_vec_t idItems(1, pAttachObj->getAttachmentItemID());
+			mCallback(idItems);
+			delete this;
+		}
+	}
+
+	static void onIdle(void* pData)
+	{
+		RlvCommandOptionGetPathCallback* pInstance = reinterpret_cast<RlvCommandOptionGetPathCallback*>(pData);
+		if (pInstance->mExpirationTimer.getElapsedTimeF32() > 30.0f)
+			delete pInstance;
+	}
+
+protected:
+	LLUUID                      mObjectId;
+	RlvCommandOptionGetPath::getpath_callback_t mCallback;
+	boost::signals2::connection mAttachmentConnection;
+	LLFrameTimer                mExpirationTimer;
+};
+
+// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b
+RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb)
+	: m_fCallback(false)
+{
+	m_fValid = true;	// Assume the option will be a valid one until we find out otherwise
+
+	// @getpath[:<option>]=<channel> => <option> is transformed to a list of inventory item UUIDs to get the path of
+	RlvCommandOptionGeneric rlvCmdOption;
+	RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption);
+	if (rlvCmdOption.isWearableType())			// <option> can be a clothing layer
+	{
+		getItemIDs(rlvCmdOption.getWearableType(), m_idItems);
+	}
+	else if (rlvCmdOption.isAttachmentPoint())	// ... or it can specify an attachment point
+	{
+		getItemIDs(rlvCmdOption.getAttachmentPoint(), m_idItems);
+	}
+	else if (rlvCmdOption.isUUID())				// ... or it can specify a specific attachment
+	{
+		const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmdOption.getUUID());
+		if ( (pAttachObj) && (pAttachObj->isAttachment()) && (pAttachObj->permYouOwner()) )
+			m_idItems.push_back(pAttachObj->getAttachmentItemID());
+		else
+			m_fValid = false;
+	}
+	else if (rlvCmdOption.isEmpty())			// ... or it can be empty (in which case we act on the object that issued the command)
+	{
+		const LLViewerObject* pObj = gObjectList.findObject(rlvCmd.getObjectID());
+		if (pObj)
+		{
+			if (pObj->isAttachment())
+				m_idItems.push_back(pObj->getAttachmentItemID());
+		}
+		else if (!cb.empty())
+		{
+			new RlvCommandOptionGetPathCallback(rlvCmd.getObjectID(), cb);
+			m_fCallback = true;
+			return;
+		}
+	}
+	else										// ... but anything else isn't a valid option
+	{
+		m_fValid = false;
+		return;
+	}
+
+	if (!cb.empty())
+	{
+		cb(getItemIDs());
+	}
+}
+
+// Checked: 2013-10-12 (RLVa-1.4.9)
+bool RlvCommandOptionGetPath::getItemIDs(const LLViewerJointAttachment* pAttachPt, uuid_vec_t& idItems)
+{
+	uuid_vec_t::size_type cntItemsPrev = idItems.size();
+
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	RlvFindAttachmentsOnPoint f(pAttachPt);
+	gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, false, f);
+	for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
+	{
+		const LLViewerInventoryItem* pItem = *itItem;
+		if (pItem)
+			idItems.push_back(pItem->getLinkedUUID());
+	}
+
+	return (cntItemsPrev != idItems.size());
+}
+
+// Checked: 2013-10-12 (RLVa-1.4.9)
+bool RlvCommandOptionGetPath::getItemIDs(LLWearableType::EType wtType, uuid_vec_t& idItems)
+{
+	uuid_vec_t::size_type cntItemsPrev = idItems.size();
+
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	LLFindWearablesOfType f(wtType);
+	gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, false, f);
+	for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
+	{
+		const LLViewerInventoryItem* pItem = *itItem;
+		if (pItem)
+			idItems.push_back(pItem->getLinkedUUID());
+	}
+
+	return (cntItemsPrev != idItems.size());
+}
+
+// Checked: 2015-03-30 (RLVa-1.5.0)
+RlvCommandOptionAdjustHeight::RlvCommandOptionAdjustHeight(const RlvCommand& rlvCmd)
+	: m_nPelvisToFoot(0.0f), m_nPelvisToFootDeltaMult(0.0f), m_nPelvisToFootOffset(0.0f)
+{
+	std::vector<std::string> cmdTokens;
+	boost::split(cmdTokens, rlvCmd.getOption(), boost::is_any_of(std::string(";")));
+	if (1 == cmdTokens.size())
+	{
+		m_fValid = (LLStringUtil::convertToF32(cmdTokens[0], m_nPelvisToFootOffset));
+		m_nPelvisToFootOffset /= 100;
+	}
+	else if ( (2 <= cmdTokens.size()) && (cmdTokens.size() <= 3) )
+	{
+		m_fValid = (LLStringUtil::convertToF32(cmdTokens[0], m_nPelvisToFoot)) &&
+			 (LLStringUtil::convertToF32(cmdTokens[1], m_nPelvisToFootDeltaMult)) && 
+			 ( (2 == cmdTokens.size()) || (LLStringUtil::convertToF32(cmdTokens[2], m_nPelvisToFootOffset)) );
+	}
+}
+
+// =========================================================================
+// RlvObject
+//
+
+RlvObject::RlvObject(const LLUUID& idObj) : m_idObj(idObj), m_nLookupMisses(0)
+{
+	LLViewerObject* pObj = gObjectList.findObject(idObj);
+	m_fLookup = (NULL != pObj);
+	m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0;
+	m_idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null;
+}
+
+bool RlvObject::addCommand(const RlvCommand& rlvCmd)
+{
+	RLV_ASSERT(RLV_TYPE_ADD == rlvCmd.getParamType());
+
+	// Don't add duplicate commands for this object (ie @detach=n followed by another @detach=n later on)
+	for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+	{
+		if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && 
+			 (itCmd->isStrict() == rlvCmd.isStrict() ) )
+		{
+			return false;
+		}
+	}
+
+	// Now that we know it's not a duplicate, add it to the end of the list
+	m_Commands.push_back(rlvCmd);
+
+	return true;
+}
+
+bool RlvObject::removeCommand(const RlvCommand& rlvCmd)
+{
+	RLV_ASSERT(RLV_TYPE_REMOVE == rlvCmd.getParamType());
+
+	for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+	{
+		//if (*itCmd == rlvCmd) <- commands will never be equal since one is an add and the other is a remove *rolls eyes*
+		if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && 
+			 (itCmd->isStrict() == rlvCmd.isStrict() ) )
+		{
+			m_Commands.erase(itCmd);
+			return true;
+		}
+	}
+	return false;	// Command was never added so nothing to remove now
+}
+
+bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const
+{
+	for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+		if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption().empty()) && ((!fStrictOnly) || (itCmd->isStrict())) )
+			return true;
+	return false;
+}
+
+bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const
+{
+	for (const RlvCommand& rlvCmd : m_Commands)
+	{
+		// The specified behaviour is contained within the current object if:
+		//   - the (parsed) behaviour matches
+		//   - the option matches (or we're checking for an empty option and the command was reference counted)
+		//   - we're not matching on strict (or it is a strict command)
+		if ( (rlvCmd.getBehaviourType() == eBehaviour) &&
+			 ( (rlvCmd.getOption() == strOption) || ((strOption.empty()) && (rlvCmd.isRefCounted())) ) &&
+			 ( (!fStrictOnly) ||(rlvCmd.isStrict()) ) )
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2009-11-27 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+std::string RlvObject::getStatusString(const std::string& strFilter, const std::string& strSeparator) const
+{
+	std::string strStatus, strCmd;
+
+	for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+	{
+		strCmd = itCmd->asString();
+		if ( (strFilter.empty()) || (std::string::npos != strCmd.find(strFilter)) )
+			strStatus.append(strSeparator).append(strCmd);
+	}
+
+	return strStatus;
+}
+
+// ============================================================================
+// RlvForceWear
+//
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+bool RlvForceWear::isWearingItem(const LLInventoryItem* pItem)
+{
+	if (pItem)
+	{
+		switch (pItem->getActualType())
+		{
+			case LLAssetType::AT_BODYPART:
+			case LLAssetType::AT_CLOTHING:
+				return gAgentWearables.isWearingItem(pItem->getUUID());
+			case LLAssetType::AT_OBJECT:
+				return (isAgentAvatarValid()) && (gAgentAvatarp->isWearingAttachment(pItem->getUUID()));
+			case LLAssetType::AT_GESTURE:
+				return LLGestureMgr::instance().isGestureActive(pItem->getUUID());
+			case LLAssetType::AT_LINK:
+				return isWearingItem(gInventory.getItem(pItem->getLinkedUUID()));
+			default:
+				break;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-21 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags)
+{
+	// [See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items]
+	if (!gAgentWearables.areWearablesLoaded())
+	{
+		LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded");
+		return;
+	}
+	if (!isAgentAvatarValid())
+		return;
+
+	// Grab a list of all the items we'll be wearing/attaching
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	RlvWearableItemCollector f(pFolder, eAction, eFlags);
+	gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f, true);
+
+	// TRUE if we've already encountered this LLWearableType::EType (used only on wear actions and only for AT_CLOTHING)
+	bool fSeenWType[LLWearableType::WT_COUNT] = { false };
+
+	EWearAction eCurAction = eAction;
+	for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++)
+	{
+		LLViewerInventoryItem* pRlvItem = items.at(idxItem);
+		LLViewerInventoryItem* pItem = (LLAssetType::AT_LINK == pRlvItem->getActualType()) ? pRlvItem->getLinkedItem() : pRlvItem;
+
+		// If it's wearable it should be worn on detach
+//		if ( (ACTION_DETACH == eAction) && (isWearableItem(pItem)) && (!isWearingItem(pItem)) )
+//			continue;
+
+		// Each folder can specify its own EWearAction override
+		if (isWearAction(eAction))
+			eCurAction = f.getWearAction(pRlvItem->getParentUUID());
+		else
+			eCurAction = eAction;
+
+		//  NOTES: * if there are composite items then RlvWearableItemCollector made sure they can be worn (or taken off depending)
+		//         * some scripts issue @remattach=force,attach:worn-items=force so we need to attach items even if they're currently worn
+		switch (pItem->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+				RLV_ASSERT(isWearAction(eAction));	// RlvWearableItemCollector shouldn't be supplying us with body parts on detach
+			case LLAssetType::AT_CLOTHING:
+				if (isWearAction(eAction))
+				{
+					// The first time we encounter any given clothing type we use 'eCurAction' (replace or add)
+					// The second time we encounter a given clothing type we'll always add (rather than replace the previous iteration)
+					eCurAction = (!fSeenWType[pItem->getWearableType()]) ? eCurAction : ACTION_WEAR_ADD;
+
+					ERlvWearMask eWearMask = gRlvWearableLocks.canWear(pRlvItem);
+					if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) ||
+						 ((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) )
+					{
+						// The check for whether we're replacing a currently worn composite item happens in onWearableArrived()
+						if (!isAddWearable(pItem))
+							addWearable(pRlvItem, eCurAction);
+						fSeenWType[pItem->getWearableType()] = true;
+					}
+				}
+				else
+				{
+					const LLViewerWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getUUID());
+					if ( (pWearable) && (isForceRemovable(pWearable, false)) )
+						remWearable(pWearable);
+				}
+				break;
+
+			case LLAssetType::AT_OBJECT:
+				if (isWearAction(eAction))
+				{
+					ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(pRlvItem);
+					if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) ||
+						 ((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) )
+					{
+						if (!isAddAttachment(pRlvItem))
+						{
+							#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+							// We still need to check whether we're about to replace a currently worn composite item
+							// (which we're not if we're just reattaching an attachment we're already wearing)
+							LLViewerInventoryCategory* pCompositeFolder = NULL;
+							if ( (pAttachPt->getObject()) && (RlvSettings::getEnableComposites()) && 
+								 (pAttachPt->getItemID() != pItem->getUUID()) &&
+								 (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pCompositeFolder)) )
+							{
+								// If we can't take off the composite folder this item would replace then don't allow it to get attached
+								if (gRlvHandler.canTakeOffComposite(pCompositeFolder))
+								{
+									forceFolder(pCompositeFolder, ACTION_DETACH, FLAG_DEFAULT);
+									addAttachment(pRlvItem);
+								}
+							}
+							else
+							#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+							{
+								addAttachment(pRlvItem, eCurAction);
+							}
+						}
+					}
+				}
+				else
+				{
+					const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(pItem->getUUID());
+					if ( (pAttachObj) && (isForceDetachable(pAttachObj, false)) )
+						remAttachment(pAttachObj);
+				}
+				break;
+
+			case LLAssetType::AT_GESTURE:
+				if (isWearAction(eAction))
+				{
+					if (std::find_if(m_addGestures.begin(), m_addGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_addGestures.end())
+						m_addGestures.push_back(pRlvItem);
+				}
+				else
+				{
+					if (std::find_if(m_remGestures.begin(), m_remGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_remGestures.end())
+						m_remGestures.push_back(pRlvItem);
+				}
+				break;
+
+			default:
+				break;
+		}
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvForceWear::isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Attachment can be detached by an RLV command if:
+	//   - it's not "remove locked" by anything (or anything except the object specified by pExceptObj)
+	//   - it's strippable
+	//   - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	LLViewerInventoryCategory* pFolder = NULL;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	return 
+	  (
+		(pAttachObj) && (pAttachObj->isAttachment())
+		&& ( (idExcept.isNull()) ? (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj))
+		                         : (!gRlvAttachmentLocks.isLockedAttachmentExcept(pAttachObj, idExcept)) )
+		&& (isStrippable(pAttachObj->getAttachmentItemID()))
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		&& ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || 
+	         (!gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) )
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	  );
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvForceWear::isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Attachment point can be detached by an RLV command if there's at least one attachment that can be removed
+	for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+			itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+	{
+		if (isForceDetachable(*itAttachObj, fCheckComposite, idExcept))
+			return true;
+	}
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.1.0i
+void RlvForceWear::forceDetach(const LLViewerObject* pAttachObj)
+{
+	// Sanity check - no need to process duplicate removes
+	if ( (!pAttachObj) || (isRemAttachment(pAttachObj)) )
+		return;
+
+	if (isForceDetachable(pAttachObj))
+	{
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		LLViewerInventoryCategory* pFolder = NULL;
+		if ( (RlvSettings::getEnableComposites()) && 
+			 (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) )
+		{
+			// Attachment belongs to a composite folder so detach the entire folder (if we can take it off)
+			if (gRlvHandler.canTakeOffComposite(pFolder))
+				forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT);
+		}
+		else
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		{
+			remAttachment(pAttachObj);
+		}
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvForceWear::forceDetach(const LLViewerJointAttachment* pAttachPt)
+{
+	for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+			itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+	{
+		forceDetach(*itAttachObj);
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+bool RlvForceWear::isForceRemovable(const LLViewerWearable* pWearable, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Wearable can be removed by an RLV command if:
+	//   - its asset type is AT_CLOTHING
+	//   - it's not "remove locked" by anything (or anything except the object specified by idExcept)
+	//   - it's strippable
+	//   - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	LLViewerInventoryCategory* pFolder = NULL;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	return 
+	  (
+		(pWearable) && (LLAssetType::AT_CLOTHING == pWearable->getAssetType()) 
+		&& ( (idExcept.isNull()) ? !gRlvWearableLocks.isLockedWearable(pWearable)
+		                         : !gRlvWearableLocks.isLockedWearableExcept(pWearable, idExcept) )
+		&& (isStrippable(pWearable->getItemID()))
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		&& ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || 
+		     (!gRlvHandler.getCompositeInfo(pWearable->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) )
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	  );
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvForceWear::isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Wearable type can be removed by an RLV command if there's at least one currently worn wearable that can be removed
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++)
+		if (isForceRemovable(gAgentWearables.getViewerWearable(wtType, idxWearable), fCheckComposite, idExcept))
+			return true;
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvForceWear::forceRemove(const LLViewerWearable* pWearable)
+{
+	// Sanity check - no need to process duplicate removes
+	if ( (!pWearable) || (isRemWearable(pWearable)) )
+		return;
+
+	if (isForceRemovable(pWearable))
+	{
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		LLViewerInventoryCategory* pFolder = NULL;
+		if ( (RlvSettings::getEnableComposites()) && 
+			 (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) )
+		{
+			// Wearable belongs to a composite folder so detach the entire folder (if we can take it off)
+			if (gRlvHandler.canTakeOffComposite(pFolder))
+				forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT);
+		}
+		else
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		{
+			remWearable(pWearable);
+		}
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvForceWear::forceRemove(LLWearableType::EType wtType)
+{
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++)
+		forceRemove(gAgentWearables.getViewerWearable(wtType, idxWearable));
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+bool RlvForceWear::isStrippable(const LLInventoryItem* pItem)
+{
+	// An item is exempt from @detach or @remoutfit if:
+	//   - its name contains "nostrip" (anywhere in the name)
+	//   - its parent folder contains "nostrip" (anywhere in the name)
+	if (pItem)
+	{
+		// If the item is an inventory link then we first examine its target before examining the link itself (and never its name)
+		if (LLAssetType::AT_LINK == pItem->getActualType())
+		{
+			if (!isStrippable(pItem->getLinkedUUID()))
+				return false;
+		}
+		else
+		{
+			if (std::string::npos != pItem->getName().find(RLV_FOLDER_FLAG_NOSTRIP))
+				return false;
+		}
+
+		LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+		while (pFolder)
+		{
+			if (std::string::npos != pFolder->getName().find(RLV_FOLDER_FLAG_NOSTRIP))
+				return false;
+			// If the item's parent is a folded folder then we need to check its parent as well
+			if ( (gInventory.getRootFolderID() != pFolder->getParentUUID()) && (RlvInventory::isFoldedFolder(pFolder, true)) )
+				pFolder = gInventory.getCategory(pFolder->getParentUUID());
+			else
+				pFolder = NULL;
+		}
+	}
+	return true;
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction)
+{
+	// Remove it from 'm_remAttachments' if it's queued for detaching
+	const LLViewerObject* pAttachObj = (isAgentAvatarValid()) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL;
+	if ( (pAttachObj) && (isRemAttachment(pAttachObj)) )
+		m_remAttachments.erase(std::remove(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj), m_remAttachments.end());
+
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pItem, true);
+	if (ACTION_WEAR_ADD == eAction)
+	{
+		// Insert it at the back if it's not already there
+		idxAttachPt |= ATTACHMENT_ADD;
+		if (!isAddAttachment(pItem))
+		{
+			addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt);
+			if (itAddAttachments == m_addAttachments.end())
+			{
+				m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t()));
+				itAddAttachments = m_addAttachments.find(idxAttachPt);
+			}
+			itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem);
+		}
+	}
+	else if (ACTION_WEAR_REPLACE == eAction)
+	{
+		// Replace all pending attachments on this attachment point with the specified item (don't clear if it's the default attach point)
+		addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt | ATTACHMENT_ADD);
+		if ( (0 != idxAttachPt) && (itAddAttachments != m_addAttachments.end()) )
+			itAddAttachments->second.clear();
+
+		itAddAttachments = m_addAttachments.find(idxAttachPt);
+		if (itAddAttachments == m_addAttachments.end())
+		{
+			m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t()));
+			itAddAttachments = m_addAttachments.find(idxAttachPt);
+		}
+
+		if (0 != idxAttachPt)
+			itAddAttachments->second.clear();
+		itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem);
+	}
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::remAttachment(const LLViewerObject* pAttachObj)
+{
+	// Remove it from 'm_addAttachments' if it's queued for attaching
+	const LLViewerInventoryItem* pItem = (pAttachObj->isAttachment()) ? gInventory.getItem(pAttachObj->getAttachmentItemID()) : NULL;
+	if (pItem)
+	{
+		addattachments_map_t::iterator itAddAttachments = m_addAttachments.begin();
+		while (itAddAttachments != m_addAttachments.end())
+		{
+			LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			if (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end())
+				wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end());
+
+			if (wearItems.empty())
+				m_addAttachments.erase(itAddAttachments++);
+			else
+				++itAddAttachments;
+		}
+	}
+
+	// Add it to 'm_remAttachments' if it's not already there
+	if (!isRemAttachment(pAttachObj))
+	{
+		m_remAttachments.push_back(const_cast<LLViewerObject*>(pAttachObj));
+	}
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction)
+{
+	const LLViewerWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID());
+	// When replacing remove all currently worn wearables of this type *unless* the item is currently worn
+	if ( (ACTION_WEAR_REPLACE == eAction) && (!pWearable) )
+		forceRemove(pItem->getWearableType());
+	// Remove it from 'm_remWearables' if it's pending removal
+	if ( (pWearable) && (isRemWearable(pWearable)) )
+		m_remWearables.erase(std::remove(m_remWearables.begin(), m_remWearables.end(), pWearable), m_remWearables.end());
+
+	addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType());
+	if (itAddWearables == m_addWearables.end())
+	{
+		m_addWearables.insert(addwearable_pair_t(pItem->getWearableType(), LLInventoryModel::item_array_t()));
+		itAddWearables = m_addWearables.find(pItem->getWearableType());
+	}
+
+	if (ACTION_WEAR_ADD == eAction)				// Add it at the back if it's not already there
+	{
+		if (!isAddWearable(pItem))
+			itAddWearables->second.push_back((LLViewerInventoryItem*)pItem);
+	}
+	else if (ACTION_WEAR_REPLACE == eAction)	// Replace all pending wearables of this type with the specified item
+	{
+		itAddWearables->second.clear();
+		itAddWearables->second.push_back((LLViewerInventoryItem*)pItem);
+	}
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::remWearable(const LLViewerWearable* pWearable)
+{
+	// Remove it from 'm_addWearables' if it's queued for wearing
+	const LLViewerInventoryItem* pItem = gInventory.getItem(pWearable->getItemID());
+	if ( (pItem) && (isAddWearable(pItem)) )
+	{
+		addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType());
+
+		LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+		wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end());
+		if (wearItems.empty())
+			m_addWearables.erase(itAddWearables);
+	}
+
+	// Add it to 'm_remWearables' if it's not already there
+	if (!isRemWearable(pWearable))
+		m_remWearables.push_back(pWearable);
+}
+
+// Checked: 2015-05-05 (RLVa-1.4.12)
+void RlvForceWear::updatePendingAttachments()
+{
+	if (RlvForceWear::instanceExists())
+	{
+		RlvForceWear* pThis = RlvForceWear::getInstance();
+		for (const pendingattachments_map_t::value_type& itAttach : pThis->m_pendingAttachments)
+			LLAttachmentsMgr::instance().addAttachmentRequest(itAttach.first, itAttach.second & ~ATTACHMENT_ADD, itAttach.second & ATTACHMENT_ADD);
+		pThis->m_pendingAttachments.clear();
+	}
+}
+
+// Checked: 2015-05-05 (RLVa-1.4.12)
+void RlvForceWear::addPendingAttachment(const LLUUID& idItem, U8 idxPoint)
+{
+	auto itAttach = m_pendingAttachments.find(idItem);
+	if (m_pendingAttachments.end() == itAttach)
+		m_pendingAttachments.insert(std::make_pair(idItem, idxPoint));
+	else
+		itAttach->second = idxPoint;
+}
+
+// Checked: 2015-05-05 (RLVa-1.4.12)
+void RlvForceWear::remPendingAttachment(const LLUUID& idItem)
+{
+	m_pendingAttachments.erase(idItem);
+}
+
+// Checked: 2015-05-05 (RLVa-1.4.12)
+void RlvForceWear::done()
+{
+	// Sanity check - don't go through all the motions below only to find out there's nothing to actually do
+	if ( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) &&
+		 (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) )
+	{
+		return;
+	}
+
+	//
+	// Process removals
+	//
+
+	uuid_vec_t remItems;
+
+	// Wearables
+	if (m_remWearables.size())
+	{
+		for (const LLViewerWearable* pWearable : m_remWearables)
+			remItems.push_back(pWearable->getItemID());
+		m_remWearables.clear();
+	}
+
+	// Gestures
+	if (m_remGestures.size())
+	{
+		// NOTE: LLGestureMgr::deactivateGesture() will call LLAppearanceMgr::removeCOFItemLinks() for us and supply its own callback
+		for (const LLViewerInventoryItem* pItem : m_remGestures)
+			LLGestureMgr::instance().deactivateGesture(pItem->getUUID());
+		m_remGestures.clear();
+	}
+
+	// Attachments
+	if (m_remAttachments.size())
+	{
+		LLAgentWearables::userRemoveMultipleAttachments(m_remAttachments);
+		for (const LLViewerObject* pAttachObj : m_remAttachments)
+			remItems.push_back(pAttachObj->getAttachmentItemID());
+		m_remAttachments.clear();
+	}
+
+	//
+	// Process additions
+	//
+
+	// Wearables need to be split into AT_BODYPART and AT_CLOTHING for COF
+	LLInventoryModel::item_array_t addBodyParts, addClothing;
+	for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.cbegin(); itAddWearables != m_addWearables.cend(); ++itAddWearables)
+	{
+		// NOTE: LLAppearanceMgr will filter our duplicates so no need for us to check here
+		for (LLViewerInventoryItem* pItem : itAddWearables->second)
+		{
+			if (LLAssetType::AT_BODYPART == pItem->getType())
+				addBodyParts.push_back(pItem);
+			else
+				addClothing.push_back(pItem);
+		}
+	}
+	m_addWearables.clear();
+
+	// Until LL provides a way for updateCOF to selectively attach add/replace we have to deal with attachments ourselves
+	for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.cbegin(); itAddAttachments != m_addAttachments.cend(); ++itAddAttachments)
+	{
+		for (const LLViewerInventoryItem* pItem : itAddAttachments->second)
+			addPendingAttachment(pItem->getLinkedUUID(), itAddAttachments->first);
+	}
+	m_addAttachments.clear();
+
+	//
+	// Tie it all together
+	//
+
+	//          |    Wearables    |   Attachments    |   Gestures      |
+	//          |======================================================|
+	// Add    : | LLAppearanceMgr | <custom>         | LLAppearanceMgr |
+	// Remove : | LLAppearanceMgr | LLAppearanceMgr  | LLGestureMgr    |
+	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(false, false, boost::bind(RlvForceWear::updatePendingAttachments));
+
+	if (!remItems.empty())
+	{
+		LLAppearanceMgr::instance().removeItemsFromAvatar(remItems, cb, true);
+	}
+
+	if ( (addBodyParts.empty()) && (!addClothing.empty()) && (m_addGestures.empty()) )
+	{
+		// Clothing items only
+		uuid_vec_t idClothing;
+		for (const LLViewerInventoryItem* pItem : addClothing)
+			idClothing.push_back(pItem->getUUID());
+		LLAppearanceMgr::instance().wearItemsOnAvatar(idClothing, false, false, cb);
+	}
+	else if ( (!addBodyParts.empty()) || (!addClothing.empty()) || (!m_addGestures.empty()) )
+	{
+		// Mixture of body parts, clothing and/or gestures
+		LLInventoryModel::item_array_t addAttachments;
+		LLAppearanceMgr::instance().updateCOF(addBodyParts, addClothing, addAttachments, m_addGestures, true, LLUUID::null, cb);
+
+		m_addGestures.clear();
+	}
+
+	// Make sure there are no leftovers for the next cycle
+	RLV_ASSERT( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) );
+	RLV_ASSERT( (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) );
+}
+
+// Checked: 2010-02-17 (RLVa-1.1.0o) | Modified: RLVa-1.1.0o
+/*
+void RlvForceWear::onWearableArrived(LLWearable* pWearable, void* pParam)
+{
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// If this wearable will end up replacing a currently worn one that belongs to a composite folder then we need to detach the composite
+	LLViewerInventoryCategory* pFolder = NULL;
+	if ( (RlvSettings::getEnableComposites()) && (pWearable) && (gAgent.getWearable(pWearable->getType())) )
+	{
+		// If we're just rewearing the same item we're already wearing then we're not replacing a composite folder
+		LLWearableHoldingPattern* pWearData = (LLWearableHoldingPattern*)pParam; LLUUID idItem;
+		for (LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin();
+				itWearable != pWearData->mFoundList.end(); ++itWearable)
+		{
+			LLFoundData* pFound = *itWearable;
+			if (pWearable->getID() == pFound->mAssetID)
+			{
+				idItem = pFound->mItemID;
+				break;
+			}
+		}
+		if ( (idItem.notNull()) && (idItem != gAgent.getWearableItem(pWearable->getType())) && 
+			 (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(pWearable->getType()), NULL, &pFolder)) )
+		{
+			RlvForceWear rlvWear;
+			rlvWear.forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT);
+			rlvWear.done();
+		}
+	}
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	wear_inventory_category_on_avatar_loop(pWearable, pParam);
+}
+*/
+
+// ============================================================================
+// RlvBehaviourNotifyObserver
+//
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+RlvBehaviourNotifyHandler::RlvBehaviourNotifyHandler()
+{
+	// NOTE: the reason we use rlv_command_signal_t instead of the better-suited rlv_behaviour_signal_t is because
+	//       RLV will notify scripts about "invalid" commands so we need to as well
+	m_ConnCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvBehaviourNotifyHandler::onCommand, this, _1, _2, _3));
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvBehaviourNotifyHandler::onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal)
+{
+	if (fInternal)
+		return;
+
+	switch (rlvCmd.getParamType())
+	{
+		case RLV_TYPE_ADD:
+		case RLV_TYPE_REMOVE:
+			sendNotification(rlvCmd.asString(), "=" + rlvCmd.getParam());
+			break;
+		case RLV_TYPE_CLEAR:
+			sendNotification(rlvCmd.asString());
+			break;
+		default:
+			break;
+	}
+}
+
+// Checked: 2011-03-31 (RLVa-1.3.0f) | Modify: RLVa-1.3.0f
+void RlvBehaviourNotifyHandler::sendNotification(const std::string& strText, const std::string& strSuffix)
+{
+	if (instanceExists())
+	{
+		RlvBehaviourNotifyHandler* pThis = getInstance();
+
+		// NOTE: notifications have two parts (which are concatenated without token) where only the first part is subject to the filter
+		for (std::multimap<LLUUID, notifyData>::const_iterator itNotify = pThis->m_Notifications.begin(); 
+				itNotify != pThis->m_Notifications.end(); ++itNotify)
+		{
+			if ( (itNotify->second.strFilter.empty()) || (boost::icontains(strText, itNotify->second.strFilter)) )
+				RlvUtil::sendChatReply(itNotify->second.nChannel, "/" + strText + strSuffix);
+		}
+	}
+}
+
+// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f
+void RlvBehaviourNotifyHandler::onWear(LLWearableType::EType eType, bool fAllowed)
+{
+	sendNotification(llformat("worn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str()));
+}
+
+// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f
+void RlvBehaviourNotifyHandler::onTakeOff(LLWearableType::EType eType, bool fAllowed)
+{
+	sendNotification(llformat("unworn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str()));
+}
+
+// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f
+void RlvBehaviourNotifyHandler::onAttach(const LLViewerJointAttachment* pAttachPt, bool fAllowed)
+{
+	sendNotification(llformat("attached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str()));
+}
+
+// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f
+void RlvBehaviourNotifyHandler::onDetach(const LLViewerJointAttachment* pAttachPt, bool fAllowed)
+{
+	sendNotification(llformat("detached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str()));
+}
+
+// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f
+void RlvBehaviourNotifyHandler::onReattach(const LLViewerJointAttachment* pAttachPt, bool fAllowed)
+{
+	sendNotification(llformat("reattached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str()));
+}
+
+// =========================================================================
+// Various helper classes/timers/functors
+//
+
+// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+BOOL RlvGCTimer::tick()
+{
+	bool fContinue = gRlvHandler.onGC();
+	if (!fContinue)
+		gRlvHandler.m_pGCTimer = NULL;
+	return !fContinue;
+}
+
+// ============================================================================
+// Various helper functions
+//
+
+// ============================================================================
+// Attachment group helper functions
+//
+
+// Has to match the order of ERlvAttachGroupType
+const std::string cstrAttachGroups[RLV_ATTACHGROUP_COUNT] = { "head", "torso", "arms", "legs", "hud" };
+
+// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e
+ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup)
+{
+	switch (idxGroup)
+	{
+		case 0: // Right Hand
+		case 1: // Right Arm
+		case 3: // Left Arm
+		case 4: // Left Hand
+			return RLV_ATTACHGROUP_ARMS;
+		case 2: // Head
+			return RLV_ATTACHGROUP_HEAD;
+		case 5: // Left Leg
+		case 7: // Right Leg
+			return RLV_ATTACHGROUP_LEGS;
+		case 6: // Torso
+			return RLV_ATTACHGROUP_TORSO;
+		case 8: // HUD
+			return RLV_ATTACHGROUP_HUD;
+		default:
+			return RLV_ATTACHGROUP_INVALID;
+	}
+}
+
+// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e
+ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup)
+{
+	for (int idx = 0; idx < RLV_ATTACHGROUP_COUNT; idx++)
+		if (cstrAttachGroups[idx] == strGroup)
+			return (ERlvAttachGroupType)idx;
+	return RLV_ATTACHGROUP_INVALID;
+}
+
+// =========================================================================
+// String helper functions
+//
+
+// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b
+std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch /*=NULL*/)
+{
+	if (pidxMatch)
+		*pidxMatch = std::string::npos;	// Assume we won't find anything
+
+	std::string::size_type idxIt, idxStart; int cntLevel = 1;
+	if ((idxStart = strText.find_first_of('(')) == std::string::npos)
+		return std::string();
+
+	const char* pstrText = strText.c_str(); idxIt = idxStart;
+	while ( (cntLevel > 0) && (++idxIt < strText.length()) )
+	{
+		if ('(' == pstrText[idxIt])
+			cntLevel++;
+		else if (')' == pstrText[idxIt])
+			cntLevel--;
+	}
+
+	if (idxIt < strText.length())
+	{
+		if (pidxMatch)
+			*pidxMatch = idxStart;	// Return the character index of the starting '('
+		return strText.substr(idxStart + 1, idxIt - idxStart - 1);
+	}
+	return std::string();
+}
+
+// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b
+std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart /*=NULL*/)
+{
+	if (pidxStart)
+		*pidxStart = std::string::npos;	// Assume we won't find anything
+
+	// Extracts the last - matched - parenthesised text from the input string
+	std::string::size_type idxIt, idxEnd; int cntLevel = 1;
+	if ((idxEnd = strText.find_last_of(')')) == std::string::npos)
+		return std::string();
+
+	const char* pstrText = strText.c_str(); idxIt = idxEnd;
+	while ( (cntLevel > 0) && (--idxIt >= 0) && (idxIt < strText.length()) )
+	{
+		if (')' == pstrText[idxIt])
+			cntLevel++;
+		else if ('(' == pstrText[idxIt])
+			cntLevel--;
+	}
+
+	if ( (idxIt >= 0) && (idxIt < strText.length()) )	// NOTE: allow for std::string::size_type to be signed or unsigned
+	{
+		if (pidxStart)
+			*pidxStart = idxIt;		// Return the character index of the starting '('
+		return strText.substr(idxIt + 1, idxEnd - idxIt - 1);
+	}
+	return std::string();
+}
+
+// =========================================================================
diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f9dc3c722f2f8dce59fbc178d580b17df6dee60
--- /dev/null
+++ b/indra/newview/rlvhelper.h
@@ -0,0 +1,825 @@
+/**
+ *
+ * Copyright (c) 2009-2016, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ *
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to
+ * abide by those obligations.
+ *
+ */
+
+#ifndef RLV_HELPER_H
+#define RLV_HELPER_H
+
+#include "lleventtimer.h"
+#include "llinventorymodel.h"
+#include "llviewerinventory.h"
+#include "llwearabletype.h"
+
+#include "rlvdefines.h"
+#include "rlvcommon.h"
+
+// ============================================================================
+// Forward declarations
+//
+
+class RlvBehaviourModifier;
+
+// ============================================================================
+// RlvBehaviourInfo class - Generic behaviour descriptor (used by restrictions, reply and force commands)
+//
+
+class RlvBehaviourInfo
+{
+public:
+	enum EBehaviourFlags
+	{
+		// General behaviour flags
+		BHVR_STRICT       = 0x0001,				// Behaviour has a "_sec" version
+		BHVR_SYNONYM      = 0x0002,				// Behaviour is a synonym of another
+		BHVR_EXTENDED     = 0x0004,				// Behaviour is part of the RLVa extended command set
+		BHVR_EXPERIMENTAL = 0x0008,				// Behaviour is part of the RLVa experimental command set
+		BHVR_BLOCKED      = 0x0010,				// Behaviour is blocked
+		BHVR_DEPRECATED   = 0x0020,				// Behaviour is deprecated
+		BHVR_GENERAL_MASK = 0x0FFF,
+
+		// Force-wear specific flags
+		FORCEWEAR_WEAR_REPLACE   = 0x0001 << 16,
+		FORCEWEAR_WEAR_ADD       = 0x0002 << 16,
+		FORCEWEAR_WEAR_REMOVE    = 0x0004 << 16,
+		FORCEWEAR_NODE           = 0x0010 << 16,
+		FORCEWEAR_SUBTREE        = 0x0020 << 16,
+		FORCEWEAR_CONTEXT_NONE   = 0x0100 << 16,
+		FORCEWEAR_CONTEXT_OBJECT = 0x0200 << 16,
+		FORCEWEAR_MASK           = 0xFFFF << 16
+	};
+
+	RlvBehaviourInfo(std::string strBhvr, ERlvBehaviour eBhvr, U32 maskParamType, U32 nBhvrFlags = 0)
+		: m_strBhvr(strBhvr), m_eBhvr(eBhvr), m_maskParamType(maskParamType), m_nBhvrFlags(nBhvrFlags) {}
+	virtual ~RlvBehaviourInfo() {}
+
+	const std::string&	getBehaviour() const      { return m_strBhvr; }
+	ERlvBehaviour		getBehaviourType() const  { return m_eBhvr; }
+	U32					getBehaviourFlags() const { return m_nBhvrFlags; }
+	U32					getParamTypeMask() const  { return m_maskParamType; }
+	bool                hasStrict() const         { return m_nBhvrFlags & BHVR_STRICT; }
+	bool                isBlocked() const         { return m_nBhvrFlags & BHVR_BLOCKED; }
+	bool                isExperimental() const    { return m_nBhvrFlags & BHVR_EXPERIMENTAL; }
+	bool                isExtended() const        { return m_nBhvrFlags & BHVR_EXTENDED; }
+	bool                isSynonym() const         { return m_nBhvrFlags & BHVR_SYNONYM; } 
+	void                toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable);
+
+	virtual ERlvCmdRet  processCommand(const RlvCommand& rlvCmd) const { return RLV_RET_NO_PROCESSOR; }
+
+protected:
+	std::string   m_strBhvr;
+	ERlvBehaviour m_eBhvr;
+	U32           m_nBhvrFlags;
+	U32           m_maskParamType;
+};
+
+// ============================================================================
+// RlvBehaviourDictionary and related classes
+//
+
+class RlvBehaviourDictionary : public LLSingleton<RlvBehaviourDictionary>
+{
+	friend class LLSingleton<RlvBehaviourDictionary>;
+	friend class RlvFloaterBehaviours;
+protected:
+	RlvBehaviourDictionary();
+	~RlvBehaviourDictionary();
+public:
+	void addEntry(const RlvBehaviourInfo* pEntry);
+	void addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry);
+
+	/*
+	 * General helper functions
+	 */
+public:
+	ERlvBehaviour           getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const;
+	const RlvBehaviourInfo*	getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const;
+	bool                    getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const;
+	bool                    getHasStrict(ERlvBehaviour eBhvr) const;
+	RlvBehaviourModifier*   getModifier(ERlvBehaviourModifier eBhvrMod) const { return (eBhvrMod < RLV_MODIFIER_COUNT) ? m_BehaviourModifiers[eBhvrMod] : nullptr; }
+	RlvBehaviourModifier*   getModifierFromBehaviour(ERlvBehaviour eBhvr) const;
+	void                    toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBvhrFlag, bool fEnable);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	typedef std::list<const RlvBehaviourInfo*> rlv_bhvrinfo_list_t;
+	typedef std::map<std::pair<std::string, ERlvParamType>, const RlvBehaviourInfo*> rlv_string2info_map_t;
+	typedef std::multimap<ERlvBehaviour, const RlvBehaviourInfo*> rlv_bhvr2info_map_t;
+	typedef std::map<ERlvBehaviour, ERlvBehaviourModifier> rlv_bhvr2mod_map_t;
+
+	rlv_bhvrinfo_list_t   m_BhvrInfoList;
+	rlv_string2info_map_t m_String2InfoMap;
+	rlv_bhvr2info_map_t	  m_Bhvr2InfoMap;
+	rlv_bhvr2mod_map_t    m_Bhvr2ModifierMap;
+	RlvBehaviourModifier* m_BehaviourModifiers[RLV_MODIFIER_COUNT];
+};
+
+// ============================================================================
+// RlvCommandHandler and related classes
+//
+
+typedef ERlvCmdRet(RlvBhvrHandlerFunc)(const RlvCommand&, bool&);
+typedef void(RlvBhvrToggleHandlerFunc)(ERlvBehaviour, bool);
+typedef ERlvCmdRet(RlvForceHandlerFunc)(const RlvCommand&);
+typedef ERlvCmdRet(RlvReplyHandlerFunc)(const RlvCommand&, std::string&);
+
+//
+// RlvCommandHandlerBaseImpl - Base implementation for each command type (the old process(AddRem|Force|Reply)Command functions)
+//
+template<ERlvParamType paramType> struct RlvCommandHandlerBaseImpl;
+template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM> { static ERlvCmdRet processCommand(const RlvCommand&, RlvBhvrHandlerFunc*, RlvBhvrToggleHandlerFunc* = nullptr); };
+template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_FORCE>  { static ERlvCmdRet processCommand(const RlvCommand&, RlvForceHandlerFunc*); };
+template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_REPLY>  { static ERlvCmdRet processCommand(const RlvCommand&, RlvReplyHandlerFunc*);
+};
+
+//
+// RlvCommandHandler - The actual command handler (Note that a handler is more general than a processor; a handler can - for instance - be used by multiple processors)
+//
+#if LL_WINDOWS
+	#define RLV_TEMPL_FIX(x) template<x>
+#else
+	#define RLV_TEMPL_FIX(x) template<typename Placeholder = int>
+#endif // LL_WINDOWS
+
+template <ERlvParamType templParamType, ERlvBehaviour templBhvr>
+struct RlvCommandHandler
+{
+	RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_ADDREM>::type) static ERlvCmdRet onCommand(const RlvCommand&, bool&);
+	RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_ADDREM>::type) static void onCommandToggle(ERlvBehaviour, bool);
+	RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_FORCE>::type)  static ERlvCmdRet onCommand(const RlvCommand&);
+	RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_REPLY>::type)  static ERlvCmdRet onCommand(const RlvCommand&, std::string&);
+};
+
+// Aliases to improve readability in definitions
+template<ERlvBehaviour templBhvr> using RlvBehaviourHandler = RlvCommandHandler<RLV_TYPE_ADDREM, templBhvr>;
+template<ERlvBehaviour templBhvr> using RlvBehaviourToggleHandler = RlvBehaviourHandler<templBhvr>;
+template<ERlvBehaviour templBhvr> using RlvForceHandler = RlvCommandHandler<RLV_TYPE_FORCE, templBhvr>;
+template<ERlvBehaviour templBhvr> using RlvReplyHandler = RlvCommandHandler<RLV_TYPE_REPLY, templBhvr>;
+
+// List of shared handlers
+typedef RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_EYEOFFSET> RlvBehaviourCamEyeFocusOffsetHandler;	// Shared between @setcam_eyeoffset and @setcam_focusoffset
+typedef RlvBehaviourHandler<RLV_BHVR_REMATTACH> RlvBehaviourAddRemAttachHandler;					// Shared between @addattach and @remattach
+typedef RlvBehaviourHandler<RLV_BHVR_SENDCHANNEL> RlvBehaviourSendChannelHandler;					// Shared between @sendchannel and @sendchannel_except
+typedef RlvBehaviourHandler<RLV_BHVR_SENDIM> RlvBehaviourRecvSendStartIMHandler;					// Shared between @recvim, @sendim and @startim
+typedef RlvBehaviourHandler<RLV_BHVR_SETCAM_FOVMIN> RlvBehaviourSetCamFovHandler;					// Shared between @setcam_fovmin and @setcam_fovmax
+typedef RlvBehaviourToggleHandler<RLV_BHVR_SHOWSELF> RlvBehaviourShowSelfToggleHandler;				// Shared between @showself and @showselfhead
+typedef RlvBehaviourHandler<RLV_BHVR_CAMZOOMMIN> RlvBehaviourCamZoomMinMaxHandler;					// Shared between @camzoommin and @camzoommax (deprecated)
+typedef RlvReplyHandler<RLV_BHVR_GETCAM_AVDISTMIN> RlvReplyCamMinMaxModifierHandler;				// Shared between @getcam_avdistmin and @getcam_avdistmax
+typedef RlvForceHandler<RLV_BHVR_REMATTACH> RlvForceRemAttachHandler;								// Shared between @remattach and @detach
+typedef RlvForceHandler<RLV_BHVR_SETCAM_EYEOFFSET> RlvForceCamEyeFocusOffsetHandler;				// Shared between @setcam_eyeoffset and @setcam_focusoffset
+
+//
+// RlvCommandProcessor - Templated glue class that brings RlvBehaviourInfo, RlvCommandHandlerBaseImpl and RlvCommandHandler together
+//
+template <ERlvParamType templParamType, ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<templParamType, templBhvr>, typename baseImpl = RlvCommandHandlerBaseImpl<templParamType>>
+class RlvCommandProcessor : public RlvBehaviourInfo
+{
+public:
+	// Default constructor used by behaviour specializations
+	RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr != RLV_BHVR_UNKNOWN>::type)
+	RlvCommandProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, templBhvr, templParamType, nBhvrFlags) {}
+
+	// Constructor used when we don't want to specialize on behaviour (see RlvBehaviourGenericProcessor)
+	RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr == RLV_BHVR_UNKNOWN>::type)
+	RlvCommandProcessor(const std::string& strBhvr, ERlvBehaviour eBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, eBhvr, templParamType, nBhvrFlags) {}
+
+	ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return baseImpl::processCommand(rlvCmd, &handlerImpl::onCommand); }
+};
+
+// Aliases to improve readability in definitions
+template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_ADDREM, templBhvr>> using RlvBehaviourProcessor = RlvCommandProcessor<RLV_TYPE_ADDREM, templBhvr, handlerImpl>;
+template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_FORCE, templBhvr>> using RlvForceProcessor = RlvCommandProcessor<RLV_TYPE_FORCE, templBhvr, handlerImpl>;
+template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_REPLY, templBhvr>> using RlvReplyProcessor = RlvCommandProcessor<RLV_TYPE_REPLY, templBhvr, handlerImpl>;
+
+// Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense)
+template<ERlvBehaviourOptionType templOptionType> struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); };
+template<ERlvBehaviourOptionType templOptionType> using RlvBehaviourGenericProcessor = RlvBehaviourProcessor<RLV_BHVR_UNKNOWN, RlvBehaviourGenericHandler<templOptionType>>;
+
+// ============================================================================
+// RlvBehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions)
+//
+
+template <ERlvBehaviour eBhvr, typename handlerImpl = RlvBehaviourHandler<eBhvr>, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>>
+class RlvBehaviourToggleProcessor : public RlvBehaviourInfo
+{
+public:
+	RlvBehaviourToggleProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, eBhvr, RLV_TYPE_ADDREM, nBhvrFlags) {}
+	ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM>::processCommand(rlvCmd, &handlerImpl::onCommand, &toggleHandlerImpl::onCommandToggle); }
+};
+template <ERlvBehaviour eBhvr, ERlvBehaviourOptionType optionType, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>> using RlvBehaviourGenericToggleProcessor = RlvBehaviourToggleProcessor<eBhvr, RlvBehaviourGenericHandler<optionType>, toggleHandlerImpl>;
+
+// ============================================================================
+// RlvBehaviourModifier - stores behaviour modifiers in an - optionally - sorted list and returns the first element (or default value if there are no modifiers)
+//
+
+typedef std::pair<RlvBehaviourModifierValue, LLUUID> RlvBehaviourModifierValueTuple;
+
+struct RlvBehaviourModifier_Comp
+{
+	virtual ~RlvBehaviourModifier_Comp() {}
+	virtual bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs)
+	{
+		// Values that match the primary object take precedence (otherwise maintain relative ordering)
+		if ( (rhs.second == m_idPrimaryObject) && (lhs.second != m_idPrimaryObject) )
+			return false;
+		return true;
+	}
+
+	LLUUID m_idPrimaryObject;
+};
+struct RlvBehaviourModifier_CompMin : public RlvBehaviourModifier_Comp
+{
+	bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override
+	{
+		if ( (m_idPrimaryObject.isNull()) || ((lhs.second == m_idPrimaryObject) && (rhs.second == m_idPrimaryObject)) )
+			return lhs.first < rhs.first;
+		return RlvBehaviourModifier_Comp::operator()(lhs, rhs);
+	}
+};
+struct RlvBehaviourModifier_CompMax : public RlvBehaviourModifier_Comp
+{
+	bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override
+	{
+		if ( (m_idPrimaryObject.isNull()) || ((lhs.second == m_idPrimaryObject) && (rhs.second == m_idPrimaryObject)) )
+			return rhs.first < lhs.first;
+		return RlvBehaviourModifier_Comp::operator()(lhs, rhs);
+	}
+};
+
+class RlvBehaviourModifier
+{
+public:
+	RlvBehaviourModifier(const std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator = nullptr);
+	virtual ~RlvBehaviourModifier();
+
+	/*
+	 * Member functions
+	 */
+protected:
+	virtual void onValueChange() const {}
+public:
+	bool                             addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject);
+	bool                             convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const;
+	bool                             getAddDefault() const { return m_fAddDefaultOnEmpty; }
+	const RlvBehaviourModifierValue& getDefaultValue() const { return m_DefaultValue; }
+	const LLUUID&                    getPrimaryObject() const;
+	const std::string&               getName() const { return m_strName; }
+	const RlvBehaviourModifierValue& getValue() const { return (hasValue()) ? m_Values.front().first : m_DefaultValue; }
+	template<typename T> const T&    getValue() const { return boost::get<T>(getValue()); }
+	bool                             hasValue() const;
+	void                             removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject);
+	void                             setPrimaryObject(const LLUUID& idPrimaryObject);
+
+	typedef boost::signals2::signal<void(const RlvBehaviourModifierValue& newValue)> change_signal_t;
+	change_signal_t& getSignal() { return m_ChangeSignal; }
+
+	/*
+	 * Member variables
+	 */
+protected:
+	std::string                          m_strName;
+	RlvBehaviourModifierValue            m_DefaultValue;
+	bool                                 m_fAddDefaultOnEmpty;
+	std::list<RlvBehaviourModifierValueTuple> m_Values;
+	change_signal_t                      m_ChangeSignal;
+	RlvBehaviourModifier_Comp*           m_pValueComparator;
+};
+
+template<ERlvBehaviourModifier eBhvrMod>
+class RlvBehaviourModifierHandler : public RlvBehaviourModifier
+{
+public:
+	//using RlvBehaviourModifier::RlvBehaviourModifier; // Needs VS2015 and up
+	RlvBehaviourModifierHandler(const std::string& strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator)
+		: RlvBehaviourModifier(strName, defaultValue, fAddDefaultOnEmpty, pValueComparator) {}
+protected:
+	void onValueChange() const override;
+};
+
+// Inspired by LLControlCache<T>
+template<typename T>
+class RlvBehaviourModifierCache : public LLRefCount, public LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier>
+{
+public:
+	RlvBehaviourModifierCache(ERlvBehaviourModifier eModifier)
+		: LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier>(eModifier)
+	{
+		RlvBehaviourModifier* pBhvrModifier = (eModifier < RLV_MODIFIER_COUNT) ? RlvBehaviourDictionary::instance().getModifier(eModifier) : nullptr;
+		if (pBhvrModifier)
+		{
+			mConnection = pBhvrModifier->getSignal().connect(boost::bind(&RlvBehaviourModifierCache<T>::handleValueChange, this, _1));
+			mCachedValue = pBhvrModifier->getValue<T>();
+		}
+		else
+		{
+			mCachedValue = {};
+		}
+	}
+	~RlvBehaviourModifierCache() {}
+
+	/*
+	 * Member functions
+	 */
+public:
+	const T& getValue() const { return mCachedValue; }
+protected:
+	void handleValueChange(const RlvBehaviourModifierValue& newValue) { mCachedValue = boost::get<T>(newValue); }
+
+	/*
+	 * Member variables
+	 */
+protected:
+	T mCachedValue;
+	boost::signals2::scoped_connection mConnection;
+};
+
+// Inspired by LLCachedControl<T>
+template <typename T>
+class RlvCachedBehaviourModifier
+{
+public:
+	RlvCachedBehaviourModifier(ERlvBehaviourModifier eModifier)
+	{
+		if ((mCachedModifierPtr = RlvBehaviourModifierCache<T>::getInstance(eModifier)) == nullptr)
+			mCachedModifierPtr = new RlvBehaviourModifierCache<T>(eModifier);
+	}
+
+	/*
+	 * Operators
+	 */
+public:
+	operator const T&() const { return mCachedModifierPtr->getValue(); }
+	const T& operator()() { return mCachedModifierPtr->getValue(); }
+
+	/*
+	 * Member variables
+	 */
+protected:
+	LLPointer<RlvBehaviourModifierCache<T>> mCachedModifierPtr;
+};
+
+// ============================================================================
+// RlvCommand
+//
+
+class RlvCommand
+{
+public:
+	explicit RlvCommand(const LLUUID& idObj, const std::string& strCommand);
+	RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType = RLV_TYPE_UNKNOWN);
+
+	/*
+	 * Member functions
+	 */
+public:
+	std::string        asString() const;
+	const std::string& getBehaviour() const		{ return m_strBehaviour; }
+	ERlvBehaviour      getBehaviourType() const	{ return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; }
+	U32                getBehaviourFlags() const{ return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourFlags() : 0; }
+	const LLUUID&      getObjectID() const		{ return m_idObj; }
+	const std::string& getOption() const		{ return m_strOption; }
+	const std::string& getParam() const			{ return m_strParam; }
+	ERlvParamType      getParamType() const		{ return m_eParamType; }
+	bool               hasOption() const		{ return !m_strOption.empty(); }
+	bool               isBlocked() const        { return (m_pBhvrInfo) ? m_pBhvrInfo->isBlocked() : false; }
+	bool               isRefCounted() const     { return m_fRefCounted; }
+	bool               isStrict() const			{ return m_fStrict; }
+	bool               isValid() const			{ return m_fValid; }
+	ERlvCmdRet         processCommand() const   { return (m_pBhvrInfo) ? m_pBhvrInfo->processCommand(*this) : RLV_RET_NO_PROCESSOR; }
+
+protected:
+	static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption,  std::string& strParam);
+	bool               markRefCounted() const   { return m_fRefCounted = true; }
+
+	/*
+	 * Operators
+	 */
+public:
+	bool operator ==(const RlvCommand&) const;
+
+	/*
+	 * Member variables
+	 */
+protected:
+	bool                    m_fValid;
+	LLUUID                  m_idObj;
+	std::string             m_strBehaviour;
+	const RlvBehaviourInfo* m_pBhvrInfo;
+	ERlvParamType           m_eParamType;
+	bool                    m_fStrict;
+	std::string             m_strOption;
+	std::string             m_strParam;
+	mutable bool            m_fRefCounted;
+
+	friend class RlvHandler;
+	friend class RlvObject;
+	template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl;
+};
+
+// ============================================================================
+// Command option parsing utility classes
+//
+
+class RlvCommandOptionHelper
+{
+public:
+	// NOTE: this function is destructive (reference value may still change on parsing failure)
+	template<typename T> static bool parseOption(const std::string& strOption, T& valueOption);
+	template<typename T> static T parseOption(const std::string& strOption)
+	{
+		T value;
+		parseOption<T>(strOption, value);
+		return value;
+	}
+	static bool parseStringList(const std::string& strOption, std::vector<std::string>& optionList, const std::string& strSeparator = std::string(RLV_OPTION_SEPARATOR));
+};
+
+struct RlvCommandOptionGeneric
+{
+	bool isAttachmentPoint() const      { return (!isEmpty()) && (typeid(LLViewerJointAttachment*) == m_varOption.type()); }
+	bool isAttachmentPointGroup() const { return (!isEmpty()) && (typeid(ERlvAttachGroupType) == m_varOption.type()); }
+	bool isEmpty() const                { return typeid(boost::blank) == m_varOption.type(); }
+	bool isNumber() const               { return (!isEmpty()) && (typeid(float) == m_varOption.type()); }
+	bool isSharedFolder() const         { return (!isEmpty()) && (typeid(LLViewerInventoryCategory*) == m_varOption.type()); }
+	bool isString() const               { return (!isEmpty()) && (typeid(std::string) == m_varOption.type()); }
+	bool isUUID() const                 { return (!isEmpty()) && (typeid(LLUUID) == m_varOption.type()); }
+	bool isVector() const               { return (!isEmpty()) && (typeid(LLVector3d) == m_varOption.type()); }
+	bool isWearableType() const         { return (!isEmpty()) && (typeid(LLWearableType::EType) == m_varOption.type()); }
+
+	LLViewerJointAttachment*   getAttachmentPoint() const { return (isAttachmentPoint()) ? boost::get<LLViewerJointAttachment*>(m_varOption) : NULL; }
+	ERlvAttachGroupType        getAttachmentPointGroup() const { return (isAttachmentPointGroup()) ? boost::get<ERlvAttachGroupType>(m_varOption) : RLV_ATTACHGROUP_INVALID; }
+	LLViewerInventoryCategory* getSharedFolder() const { return (isSharedFolder()) ? boost::get<LLViewerInventoryCategory*>(m_varOption) : NULL; }
+	float                      getNumber() const { return (isNumber()) ? boost::get<float>(m_varOption) : 0.0f; }
+	const std::string&         getString() const { return (isString()) ? boost::get<std::string>(m_varOption) : LLStringUtil::null; }
+	const LLUUID&              getUUID() const { return (isUUID()) ? boost::get<LLUUID>(m_varOption) : LLUUID::null; }
+	const LLVector3d&          getVector() const { return (isVector()) ? boost::get<LLVector3d>(m_varOption) : LLVector3d::zero; }
+	LLWearableType::EType      getWearableType() const { return (isWearableType()) ? boost::get<LLWearableType::EType>(m_varOption) : LLWearableType::WT_INVALID; }
+
+	typedef boost::variant<boost::blank, LLViewerJointAttachment*, ERlvAttachGroupType, LLViewerInventoryCategory*, std::string, LLUUID, LLWearableType::EType, LLVector3d, float> rlv_option_generic_t;
+	void operator=(const rlv_option_generic_t& optionValue) { m_varOption = optionValue; }
+protected:
+	rlv_option_generic_t m_varOption;
+};
+
+// ============================================================================
+// Command option parsing utility classes (these still need refactoring to fit the new methodology)
+//
+
+struct RlvCommandOption
+{
+protected:
+	RlvCommandOption() : m_fValid(false) {}
+public:
+	virtual ~RlvCommandOption() {}
+
+public:
+	virtual bool isEmpty() const { return false; }
+	virtual bool isValid() const { return m_fValid; }
+protected:
+	bool m_fValid;
+};
+
+struct RlvCommandOptionGetPath : public RlvCommandOption
+{
+	typedef boost::function<void(const uuid_vec_t&)> getpath_callback_t;
+	RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb = NULL);
+
+	bool              isCallback() const { return m_fCallback; }
+	/*virtual*/ bool  isEmpty() const	 { return m_idItems.empty(); }
+	const uuid_vec_t& getItemIDs() const { return m_idItems; }
+
+	// NOTE: Both functions are COF-based rather than items gathered from mAttachedObjects or gAgentWearables
+	static bool getItemIDs(const LLViewerJointAttachment* pAttachPt, uuid_vec_t& idItems);
+	static bool getItemIDs(LLWearableType::EType wtType, uuid_vec_t& idItems);
+
+protected:
+	bool       m_fCallback; // TRUE if a callback is schedueled
+	uuid_vec_t m_idItems;
+};
+
+struct RlvCommandOptionAdjustHeight : public RlvCommandOption
+{
+	RlvCommandOptionAdjustHeight(const RlvCommand& rlvCmd);
+
+	F32 m_nPelvisToFoot;
+	F32 m_nPelvisToFootDeltaMult;
+	F32 m_nPelvisToFootOffset;
+};
+
+// ============================================================================
+// RlvObject
+//
+
+class RlvObject
+{
+public:
+	RlvObject(const LLUUID& idObj);
+
+	/*
+	 * Member functions
+	 */
+public:
+	bool addCommand(const RlvCommand& rlvCmd);
+	bool removeCommand(const RlvCommand& rlvCmd);
+
+	std::string getStatusString(const std::string& strFilter, const std::string& strSeparator) const;
+	bool        hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const;
+	bool        hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const;
+
+
+	/*
+	 * Accessors
+	 */
+public:
+	S32           getAttachPt() const	{ return m_idxAttachPt; }
+	const LLUUID& getObjectID() const	{ return m_idObj; }
+	const LLUUID& getRootID() const		{ return m_idRoot; }
+	bool          hasLookup() const     { return m_fLookup; }
+	const rlv_command_list_t* getCommandList() const { return &m_Commands; }
+
+	/*
+	 * Member variables
+	 */
+protected:
+	S32                m_idxAttachPt;		// The object's attachment point (or 0 if it's not an attachment)
+	LLUUID             m_idObj;				// The object's UUID
+	LLUUID             m_idRoot;			// The UUID of the object's root (may or may not be different from m_idObj)
+	bool               m_fLookup;			// TRUE if the object existed in gObjectList at one point in time
+	S16                m_nLookupMisses;		// Count of unsuccessful lookups in gObjectList by the GC
+	rlv_command_list_t m_Commands;			// List of behaviours held by this object (in the order they were received)
+
+	friend class RlvHandler;
+};
+
+// ============================================================================
+// RlvForceWear
+//
+
+class RlvForceWear : public LLSingleton<RlvForceWear>
+{
+protected:
+	RlvForceWear() {}
+
+public:
+	// Folders
+	enum EWearAction { ACTION_WEAR_REPLACE, ACTION_WEAR_ADD, ACTION_REMOVE };
+	enum EWearFlags { FLAG_NONE = 0x00, FLAG_MATCHALL = 0x01, FLAG_DEFAULT = FLAG_NONE };
+	void forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags);
+
+	// Generic
+	static bool isWearAction(EWearAction eAction) { return (ACTION_WEAR_REPLACE == eAction) || (ACTION_WEAR_ADD == eAction); }
+	static bool isWearableItem(const LLInventoryItem* pItem);
+	static bool isWearingItem(const LLInventoryItem* pItem);
+
+	// Nostrip
+	static bool isStrippable(const LLUUID& idItem) { return isStrippable(gInventory.getItem(idItem)); }
+	static bool isStrippable(const LLInventoryItem* pItem);
+
+	// Attachments
+	static bool isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	static bool isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	void forceDetach(const LLViewerObject* pAttachObj);
+	void forceDetach(const LLViewerJointAttachment* ptAttachPt);
+
+	// Wearables
+	static bool isForceRemovable(const LLViewerWearable* pWearable, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	static bool isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	void forceRemove(const LLViewerWearable* pWearable);
+	void forceRemove(LLWearableType::EType wtType);
+
+public:
+	void done();
+protected:
+	void addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction);
+	void remAttachment(const LLViewerObject* pAttachObj);
+	void addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction);
+	void remWearable(const LLViewerWearable* pWearable);
+
+	// Convenience (prevents long lines that run off the screen elsewhere)
+	bool isAddAttachment(const LLViewerInventoryItem* pItem) const
+	{
+		bool fFound = false;
+		for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); 
+				(!fFound) && (itAddAttachments != m_addAttachments.end()); ++itAddAttachments)
+		{
+			const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end());
+		}
+		return fFound;
+	}
+	bool isRemAttachment(const LLViewerObject* pAttachObj) const
+	{
+		return std::find(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj) != m_remAttachments.end();
+	}
+	bool isAddWearable(const LLViewerInventoryItem* pItem) const
+	{
+		bool fFound = false;
+		for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); 
+				(!fFound) && (itAddWearables != m_addWearables.end()); ++itAddWearables)
+		{
+			const LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+			fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end());
+		}
+		return fFound;
+	}
+	bool isRemWearable(const LLViewerWearable* pWearable) const
+	{
+		return std::find(m_remWearables.begin(), m_remWearables.end(), pWearable) != m_remWearables.end();
+	}
+
+	/*
+	 * Pending attachments
+	 */
+public:
+	static void updatePendingAttachments();
+protected:
+	void addPendingAttachment(const LLUUID& idItem, U8 idxPoint);
+	void remPendingAttachment(const LLUUID& idItem);
+
+protected:
+	typedef std::pair<LLWearableType::EType, LLInventoryModel::item_array_t> addwearable_pair_t;
+	typedef std::map<LLWearableType::EType, LLInventoryModel::item_array_t> addwearables_map_t;
+	addwearables_map_t               m_addWearables;
+	typedef std::pair<S32, LLInventoryModel::item_array_t> addattachment_pair_t;
+	typedef std::map<S32, LLInventoryModel::item_array_t> addattachments_map_t;
+	addattachments_map_t             m_addAttachments;
+	LLInventoryModel::item_array_t   m_addGestures;
+	std::vector<LLViewerObject*>     m_remAttachments;	// This should match the definition of LLAgentWearables::llvo_vec_t
+	std::list<const LLViewerWearable*> m_remWearables;
+	LLInventoryModel::item_array_t   m_remGestures;
+
+	typedef std::map<LLUUID, U8> pendingattachments_map_t;
+	pendingattachments_map_t         m_pendingAttachments;
+
+private:
+	friend class LLSingleton<RlvForceWear>;
+};
+
+// ============================================================================
+// RlvBehaviourNotifyObserver
+//
+
+class RlvBehaviourNotifyHandler : public LLSingleton<RlvBehaviourNotifyHandler>
+{
+	friend class LLSingleton<RlvBehaviourNotifyHandler>;
+protected:
+	RlvBehaviourNotifyHandler();
+	virtual ~RlvBehaviourNotifyHandler() { if (m_ConnCommand.connected()) m_ConnCommand.disconnect(); }
+
+public:
+	void addNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter)
+	{
+		m_Notifications.insert(std::pair<LLUUID, notifyData>(idObj, notifyData(nChannel, strFilter)));
+	}
+	void removeNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter)
+	{
+		for (std::multimap<LLUUID, notifyData>::iterator itNotify = m_Notifications.lower_bound(idObj), 
+				endNotify = m_Notifications.upper_bound(idObj); itNotify != endNotify; ++itNotify)
+		{
+			if ( (itNotify->second.nChannel == nChannel) && (itNotify->second.strFilter == strFilter) )
+			{
+				m_Notifications.erase(itNotify);
+				break;
+			}
+		}
+		if (m_Notifications.empty())
+			delete this;	// Delete ourself if we have nothing to do
+	}
+	static void sendNotification(const std::string& strText, const std::string& strSuffix = LLStringUtil::null);
+
+	/*
+	 * Event handlers
+	 */
+public:
+	static void	onWear(LLWearableType::EType eType, bool fAllowed);
+	static void	onTakeOff(LLWearableType::EType eType, bool fAllowed);
+	static void	onAttach(const LLViewerJointAttachment* pAttachPt, bool fAllowed);
+	static void	onDetach(const LLViewerJointAttachment* pAttachPt, bool fAllowed);
+	static void	onReattach(const LLViewerJointAttachment* pAttachPt, bool fAllowed);
+protected:
+	void		onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal);
+
+protected:
+	struct notifyData
+	{
+		S32         nChannel;
+		std::string strFilter;
+		notifyData(S32 channel, const std::string& filter) : nChannel(channel), strFilter(filter) {}
+	};
+	std::multimap<LLUUID, notifyData> m_Notifications;
+	boost::signals2::connection m_ConnCommand;
+};
+
+// ============================================================================
+// RlvException
+//
+
+struct RlvException
+{
+public:
+	LLUUID				idObject;    // UUID of the object that added the exception
+	ERlvBehaviour		eBehaviour;  // Behaviour the exception applies to
+	RlvExceptionOption	varOption;   // Exception data (type is dependent on eBehaviour)
+
+	RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {}
+private:
+	RlvException();
+};
+
+// ============================================================================
+// Various helper classes/timers/functors
+//
+
+class RlvGCTimer : public LLEventTimer
+{
+public:
+	RlvGCTimer() : LLEventTimer(30.0) {}
+	virtual BOOL tick();
+};
+
+// NOTE: Unused as of SL-3.7.2
+class RlvCallbackTimerOnce : public LLEventTimer
+{
+public:
+	typedef boost::function<void ()> nullary_func_t;
+public:
+	RlvCallbackTimerOnce(F32 nPeriod, nullary_func_t cb) : LLEventTimer(nPeriod), m_Callback(cb) {}
+	/*virtual*/ BOOL tick()
+	{
+		m_Callback();
+		return TRUE;
+	}
+protected:
+	nullary_func_t m_Callback;
+};
+
+// NOTE: Unused as of SL-3.7.2
+inline void rlvCallbackTimerOnce(F32 nPeriod, RlvCallbackTimerOnce::nullary_func_t cb)
+{
+	// Timer will automatically delete itself after the callback
+	new RlvCallbackTimerOnce(nPeriod, cb);
+}
+
+// ============================================================================
+// Various helper functions
+//
+
+ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup);
+ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup);
+
+std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch = NULL);
+std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart = NULL);
+
+// ============================================================================
+// Inlined class member functions
+//
+
+inline void RlvBehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable)
+{
+	if (fEnable)
+		m_nBhvrFlags |= eBhvrFlag;
+	else
+		m_nBhvrFlags &= ~eBhvrFlag;
+}
+
+// Checked: 2009-09-19 (RLVa-1.0.3d)
+inline std::string RlvCommand::asString() const
+{
+	// NOTE: @clear=<param> should be represented as clear:<param>
+	return (m_eParamType != RLV_TYPE_CLEAR)
+		? (!m_strOption.empty()) ? (std::string(getBehaviour())).append(":").append(m_strOption) : (std::string(getBehaviour()))
+	    : (!m_strParam.empty())  ? (std::string(getBehaviour())).append(":").append(m_strParam)  : (std::string(getBehaviour()));
+}
+
+inline bool RlvCommand::operator ==(const RlvCommand& rhs) const
+{
+	// The specification notes that "@detach=n" is semantically identical to "@detach=add" (same for "y" and "rem"
+	return (getBehaviour() == rhs.getBehaviour()) && (m_strOption == rhs.m_strOption) &&
+		( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) );
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem)
+{
+	LLAssetType::EType assetType = (pItem) ? pItem->getType() : LLAssetType::AT_NONE;
+	return 
+		(LLAssetType::AT_BODYPART == assetType) || (LLAssetType::AT_CLOTHING == assetType) ||
+		(LLAssetType::AT_OBJECT == assetType) || (LLAssetType::AT_GESTURE == assetType);
+}
+
+// ============================================================================
+
+#endif // RLV_HELPER_H
diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..082cc6065b5d1eeeb2ed9b7a260bb0192915e838
--- /dev/null
+++ b/indra/newview/rlvinventory.cpp
@@ -0,0 +1,882 @@
+/** 
+ *
+ * Copyright (c) 2009-2014, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llstartup.h"
+#include "llviewerfoldertype.h"
+#include "llviewermessage.h"
+
+#include "rlvinventory.h"
+
+#include "boost/algorithm/string.hpp"
+
+// ============================================================================
+// Static variable initialization
+//
+
+const std::string RlvInventory::cstrSharedRoot = RLV_ROOT_FOLDER;
+
+// ============================================================================
+// Helper classes
+//
+
+// TODO-RLVa: [RLVa-1.2.1] This class really shouldn't be calling "fetchSharedLinks" directly so find a better way
+class RlvSharedInventoryFetcher : public LLInventoryFetchDescendentsObserver
+{
+public:
+	RlvSharedInventoryFetcher(const uuid_vec_t& idFolders): LLInventoryFetchDescendentsObserver(idFolders) {}
+	virtual ~RlvSharedInventoryFetcher() {}
+
+	virtual void done()
+	{
+		RLV_INFOS << "Shared folders fetch completed" << LL_ENDL;
+		RlvInventory::instance().m_fFetchComplete = true;
+		RlvInventory::instance().fetchSharedLinks();
+
+		gInventory.removeObserver(this);
+		delete this;
+	}
+};
+
+// ============================================================================
+// RlvInventory member functions
+//
+
+// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+RlvInventory::RlvInventory()
+	: m_fFetchStarted(false), m_fFetchComplete(false)
+{
+}
+
+// Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+RlvInventory::~RlvInventory()
+{
+	if (gInventory.containsObserver(this))
+		gInventory.removeObserver(this);
+}
+
+// Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+void RlvInventory::changed(U32 mask)
+{
+	const LLInventoryModel::changed_items_t& idsChanged = gInventory.getChangedIDs();
+	if (std::find(idsChanged.begin(), idsChanged.end(), m_idRlvRoot) != idsChanged.end())
+	{
+		gInventory.removeObserver(this);
+
+		LLUUID idRlvRootPrev = m_idRlvRoot;
+		m_idRlvRoot.setNull();
+
+		if (idRlvRootPrev != getSharedRootID())
+			m_OnSharedRootIDChanged();
+	}
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h
+void RlvInventory::fetchSharedInventory()
+{
+	// Sanity check - don't fetch if we're already fetching, or if we don't have a shared root
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	if ( (m_fFetchStarted) || (!pRlvRoot) )
+		return;
+
+	// Grab all the folders under the shared root
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	gInventory.collectDescendents(pRlvRoot->getUUID(), folders, items, FALSE);
+
+	// Add them to the "to fetch" list
+	uuid_vec_t idFolders;
+	idFolders.push_back(pRlvRoot->getUUID());
+	for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++)
+		idFolders.push_back(folders.at(idxFolder)->getUUID());
+
+	// Now fetch them all in one go
+	RlvSharedInventoryFetcher* pFetcher = new RlvSharedInventoryFetcher(idFolders);
+
+	RLV_INFOS << "Starting fetch of " << idFolders.size() << " shared folders" << RLV_ENDL;
+	pFetcher->startFetch();
+	m_fFetchStarted = true;
+
+	if (pFetcher->isFinished())
+		pFetcher->done();
+	else
+		gInventory.addObserver(pFetcher);
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h
+void RlvInventory::fetchSharedLinks()
+{
+	// TOFIX-RLVa: [RLVa-1.2.1] Finish adding support for AT_LINK_FOLDER
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	if (!pRlvRoot)
+		return;
+
+	// Grab all the inventory links under the shared root
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; RlvIsLinkType f;
+	gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f, false);
+
+	// Add them to the "to fetch" list based on link type
+	uuid_vec_t idFolders, idItems;
+	for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++)
+	{
+		const LLViewerInventoryItem* pItem = items.at(idxItem);
+		switch (pItem->getActualType())
+		{
+			case LLAssetType::AT_LINK:
+				idItems.push_back(pItem->getLinkedUUID());
+				break;
+			case LLAssetType::AT_LINK_FOLDER:
+				idFolders.push_back(pItem->getLinkedUUID());
+				break;
+			default:
+				break;;
+		}
+	}
+
+	RLV_INFOS << "Starting link target fetch of " << idItems.size() << " items and " << idFolders.size() << " folders" << RLV_ENDL;
+
+	// Fetch all the link item targets
+	LLInventoryFetchItemsObserver itemFetcher(idItems);
+	itemFetcher.startFetch();
+
+	// Fetch all the link folder targets
+	// TODO!
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvInventory::fetchWornItems()
+{
+	uuid_vec_t idItems;
+
+	// Fetch all currently worn clothing layers and body parts
+	for (int type = 0; type < LLWearableType::WT_COUNT; type++)
+	{
+		// RELEASE-RLVa: [SL-2.0.0] Needs rewriting once 'LLAgentWearables::MAX_WEARABLES_PER_TYPE > 1'
+		const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0);
+		if (idItem.notNull())
+			idItems.push_back(idItem);
+	}
+
+	// Fetch all currently worn attachments
+	if (isAgentAvatarValid())
+	{
+		for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); 
+				itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt)
+		{
+			const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+			if (pAttachPt)
+			{
+				for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					 itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+				{
+					const LLViewerObject* pAttachObj = (*itAttachObj);
+					if ( (pAttachObj) && (pAttachObj->getAttachmentItemID().notNull()) )
+						idItems.push_back(pAttachObj->getAttachmentItemID());
+				}
+			}
+		}
+	}
+
+	LLInventoryFetchItemsObserver itemFetcher(idItems);
+	itemFetcher.startFetch();
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h
+bool RlvInventory::findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const
+{
+	// Sanity check - can't do anything without a shared root
+	const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
+	if (!pRlvRoot)
+		return false;
+
+	folders.clear();
+	LLInventoryModel::item_array_t items;
+	RlvCriteriaCategoryCollector f(strCriteria);
+	gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f);
+
+	return (folders.size() != 0);
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+bool RlvInventory::getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const
+{
+	// Sanity check - can't do anything without a shared root
+	const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
+	if (!pRlvRoot)
+		return false;
+
+	folders.clear();
+	for (uuid_vec_t::const_iterator itItem = idItems.begin(); itItem != idItems.end(); ++itItem)
+	{
+		const LLInventoryItem* pItem = gInventory.getItem(*itItem);
+		if ( (pItem) && (gInventory.isObjectDescendentOf(pItem->getUUID(), pRlvRoot->getUUID())) )
+		{
+			// If the containing folder is a folded folder we need its parent
+			LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+			if (RlvInventory::instance().isFoldedFolder(pFolder, true))
+				pFolder = gInventory.getCategory(pFolder->getParentUUID());
+			folders.push_back(pFolder);
+		}
+	}
+
+	return (folders.size() != 0);
+}
+
+// Checked: 2011-10-06 (RLVa-1.4.2a) | Modified: RLVa-1.4.2a
+const LLUUID& RlvInventory::getSharedRootID() const
+{
+	if ( (m_idRlvRoot.isNull()) && (gInventory.isInventoryUsable()) )
+	{
+		LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+		gInventory.getDirectDescendentsOf(gInventory.getRootFolderID(), pFolders, pItems);
+		if (pFolders)
+		{
+			// NOTE: we might have multiple #RLV folders (pick the first one with sub-folders; otherwise the last one with no sub-folders)
+			const LLViewerInventoryCategory* pFolder;
+			for (S32 idxFolder = 0, cntFolder = pFolders->size(); idxFolder < cntFolder; idxFolder++)
+			{
+				if ( ((pFolder = pFolders->at(idxFolder)) != NULL) && (cstrSharedRoot == pFolder->getName()) )
+				{
+					m_idRlvRoot = pFolder->getUUID();
+					if (getDirectDescendentsFolderCount(pFolder) > 0)
+						break;
+				}
+			}
+			if ( (m_idRlvRoot.notNull()) && (!gInventory.containsObserver((RlvInventory*)this)) )
+				gInventory.addObserver((RlvInventory*)this);
+		}
+	}
+	return m_idRlvRoot;
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.1a
+LLViewerInventoryCategory* RlvInventory::getSharedFolder(const LLUUID& idParent, const std::string& strFolderName, bool fMatchPartial) const
+{
+	LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+	gInventory.getDirectDescendentsOf(idParent, pFolders, pItems);
+	if ( (!pFolders) || (strFolderName.empty()) )
+		return NULL;
+
+	// If we can't find an exact match then we'll settle for a "contains" match
+	LLViewerInventoryCategory* pPartial = NULL;
+	for (LLInventoryModel::cat_array_t::const_iterator itFolder = pFolders->begin(); itFolder != pFolders->end(); ++itFolder)
+	{
+		LLViewerInventoryCategory* pFolder = *itFolder;
+		const std::string& strName = pFolder->getName();
+
+		if (boost::iequals(strName, strFolderName))
+			return pFolder;		// Found an exact match, no need to keep on going
+		else if ( (fMatchPartial) && (!pPartial) && (RLV_FOLDER_PREFIX_HIDDEN != strName[0]) && (boost::icontains(strName, strFolderName)) )
+			pPartial = pFolder;	// Found a partial (non-hidden) match, but we might still find an exact one (first partial match wins)
+	}
+
+	return pPartial;
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-0.2.0e
+LLViewerInventoryCategory* RlvInventory::getSharedFolder(const std::string& strPath, bool fMatchPartial) const
+{
+	// Sanity check - no shared root => no shared folder
+	LLViewerInventoryCategory* pRlvRoot = getSharedRoot(), *pFolder = pRlvRoot;
+	if (!pRlvRoot)
+		return NULL;
+
+	// Walk the path (starting at the root)
+	boost_tokenizer tokens(strPath, boost::char_separator<char>("/", "", boost::drop_empty_tokens));
+	for (boost_tokenizer::const_iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken)
+	{
+		pFolder = getSharedFolder(pFolder->getUUID(), *itToken, fMatchPartial);
+		if (!pFolder)
+			return NULL;	// No such folder
+	}
+
+	return pFolder;			// If strPath was empty or just a bunch of //// then: pFolder == pRlvRoot
+}
+
+// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-0.2.0g
+std::string RlvInventory::getSharedPath(const LLViewerInventoryCategory* pFolder) const
+{
+	// Sanity check - no shared root or no folder => no path
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	if ( (!pRlvRoot) || (!pFolder) || (pRlvRoot->getUUID() == pFolder->getUUID()) )
+		return std::string();
+
+	const LLUUID& idRLV  = pRlvRoot->getUUID();
+	const LLUUID& idRoot = gInventory.getRootFolderID();
+	std::string strPath;
+
+	// Walk up the tree until we reach the top
+	RLV_ASSERT(gInventory.isObjectDescendentOf(pFolder->getUUID(), pRlvRoot->getUUID()));
+	while (pFolder)
+	{
+		strPath = "/" + pFolder->getName() + strPath;
+
+		const LLUUID& idParent = pFolder->getParentUUID();
+		if (idRLV == idParent)			// Reached the shared root, we're done
+			break;
+		else if (idRoot == idParent)	// We reached the agent's inventory root (indicative of a logic error elsewhere)
+			return std::string();
+
+		pFolder = gInventory.getCategory(idParent);
+	}
+
+	return strPath.erase(0, 1);
+}
+
+// Checked: 2011-10-06 (RLVa-1.4.2a) | Added: RLVa-1.4.2a
+S32 RlvInventory::getDirectDescendentsFolderCount(const LLInventoryCategory* pFolder)
+{
+	LLInventoryModel::cat_array_t* pFolders = NULL; LLInventoryModel::item_array_t* pItems = NULL;
+	if (pFolder)
+		gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems);
+	return (pFolders) ? pFolders->size() : 0;
+}
+
+// Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d
+S32 RlvInventory::getDirectDescendentsItemCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType)
+{
+	S32 cntType = 0;
+	if (pFolder)
+	{
+		LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+		gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems);
+
+		if (pItems)
+		{
+			for (S32 idxItem = 0, cntItem = pItems->size(); idxItem < cntItem; idxItem++)
+				if (pItems->at(idxItem)->getType() == filterType)
+					cntType++;
+		}
+	}
+	return cntType;
+}
+
+// Checked: 2012-11-28 (RLVa-1.4.8)
+bool RlvInventory::isGiveToRLVOffer(const LLOfferInfo& offerInfo)
+{
+	if ( (!RlvSettings::getForbidGiveToRLV()) && (RlvInventory::instance().getSharedRoot()) )
+	{
+		if (offerInfo.mFromObject)
+		{
+			return 
+				(IM_TASK_INVENTORY_OFFERED == offerInfo.mIM) && 
+				(LLAssetType::AT_CATEGORY == offerInfo.mType) && (offerInfo.mDesc.find(RLV_PUTINV_PREFIX) == 1);
+		}
+		else
+		{
+			return
+				(IM_INVENTORY_OFFERED == offerInfo.mIM) && 
+				(LLAssetType::AT_CATEGORY == offerInfo.mType) && (offerInfo.mDesc.find(RLV_PUTINV_PREFIX) == 0);
+		}
+	}
+	return false;
+}
+
+// ============================================================================
+// RlvRenameOnWearObserver member functions
+//
+
+// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvRenameOnWearObserver::done()
+{
+	gInventory.removeObserver(this);
+
+	// We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers()
+	doOnIdleOneTime(boost::bind(&RlvRenameOnWearObserver::doneIdle, this));
+}
+
+// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvRenameOnWearObserver::doneIdle()
+{
+	const LLViewerInventoryCategory* pRlvRoot = NULL;
+	if ( (RlvSettings::getEnableSharedWear()) || (!RlvSettings::getSharedInvAutoRename()) || (LLStartUp::getStartupState() < STATE_STARTED) || 
+		 (!isAgentAvatarValid()) || ((pRlvRoot = RlvInventory::instance().getSharedRoot()) == NULL) )
+	{
+		delete this;
+		return;
+	}
+
+	const LLViewerJointAttachment* pAttachPt = NULL; S32 idxAttachPt = 0;
+	RLV_ASSERT(mComplete.size() > 0);	// Catch instances where we forgot to call startFetch()
+	for (uuid_vec_t::const_iterator itItem = mComplete.begin(); itItem != mComplete.end(); ++itItem)
+	{
+		const LLUUID& idAttachItem = *itItem;
+
+		// If the item resides under #RLV we'll rename it directly; otherwise settle for "renaming" all of its links residing under #RLV
+		LLInventoryModel::item_array_t items;
+		if (gInventory.isObjectDescendentOf(idAttachItem, pRlvRoot->getUUID()))
+			items.push_back(gInventory.getItem(idAttachItem));
+//		// LL kind of messed up the collectLinkedItems (now collectLinksTo) function but I'm not sure if this use-case if worth fixing it for
+//		else
+//			items = gInventory.collectLinkedItems(idAttachItem, pRlvRoot->getUUID());
+		if (items.empty())
+			continue;
+
+		if ( ((pAttachPt = gAgentAvatarp->getWornAttachmentPoint(idAttachItem)) == NULL) ||
+			 ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt)) == 0) )
+		{
+			RLV_ASSERT(false);
+			continue;
+		}
+
+		for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++)
+		{
+			LLViewerInventoryItem* pItem = items.at(idxItem);
+			if (!pItem)
+				continue;
+
+			S32 idxAttachPtItem = RlvAttachPtLookup::getAttachPointIndex(pItem);
+			if ( (idxAttachPt == idxAttachPtItem) || (idxAttachPtItem) )
+				continue;
+
+			std::string strAttachPt = pAttachPt->getName();
+			LLStringUtil::toLower(strAttachPt);
+
+			// If we can modify the item then we rename it directly, otherwise we create a new folder and move it
+			if (pItem->getPermissions().allowModifyBy(gAgent.getID()))
+			{
+				std::string strName = pItem->getName();
+				LLStringUtil::truncate(strName, DB_INV_ITEM_NAME_STR_LEN - strAttachPt.length() - 3);
+
+				strName += " (" + strAttachPt + ")";
+
+				pItem->rename(strName);
+				pItem->updateServer(FALSE);
+				gInventory.addChangedMask(LLInventoryObserver::LABEL, pItem->getUUID());
+			}
+			else
+			{
+				// Don't do anything if the item is a direct descendant of the shared root, or a folded folder
+				LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+				if ( (pFolder) && (pFolder->getUUID() != pRlvRoot->getUUID()) && (!RlvInventory::isFoldedFolder(pFolder, false)) )
+				{
+					std::string strFolderName = ".(" + strAttachPt + ")";
+
+					// Rename the item's parent folder if it's called "New Folder", isn't directly under #RLV and contains exactly 1 object
+					if ( (LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_NONE) == pFolder->getName()) && 
+						 (pFolder->getParentUUID() != pRlvRoot->getUUID()) && 
+						 (1 == RlvInventory::getDirectDescendentsItemCount(pFolder, LLAssetType::AT_OBJECT)) )
+					{
+						pFolder->rename(strFolderName);
+						pFolder->updateServer(FALSE);
+						gInventory.addChangedMask(LLInventoryObserver::LABEL, pFolder->getUUID());
+					}
+					else
+					{
+						// "No modify" item with a non-renameable parent: create a new folder named and move the item into it
+						inventory_func_type f = boost::bind(RlvRenameOnWearObserver::onCategoryCreate, _1, pItem->getUUID());
+						LLUUID idFolder = gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName, f);
+						if (idFolder.notNull())
+						{
+							// Not using the new 'CreateInventoryCategory' cap so manually invoke the callback
+							RlvRenameOnWearObserver::onCategoryCreate(idFolder, pItem->getUUID());
+						}
+					}
+				}
+			}
+		}
+	}
+	gInventory.notifyObservers();
+
+	delete this;
+}
+
+// Checked: 2012-03-22 (RLVa-1.4.6) | Added: RLVa-1.4.6
+void RlvRenameOnWearObserver::onCategoryCreate(const LLUUID& idFolder, const LLUUID idItem)
+{
+	if ( (idFolder.notNull()) && (idItem.notNull()) )
+		move_inventory_item(gAgent.getID(), gAgent.getSessionID(), idItem, idFolder, std::string(), NULL);
+}
+
+// ============================================================================
+// "Give to #RLV" helper classes
+//
+
+// Checked: 2014-01-07 (RLVa-1.4.10)
+bool RlvGiveToRLVOffer::createDestinationFolder(const std::string& strPath)
+{
+	// NOTE: derived classes will delete the instance in their onDestinationCreated override, so don't do anything after triggering the callback
+
+	m_DestPath.clear();
+	if (0 == strPath.find(RLV_PUTINV_PREFIX))
+	{
+		boost::split(m_DestPath, strPath, boost::is_any_of(std::string(RLV_PUTINV_SEPARATOR)));
+	}
+
+	if ( (m_DestPath.size() >= 2) && (m_DestPath.size() <= RLV_PUTINV_MAXDEPTH) )
+	{
+		const std::string strFolder = m_DestPath.front();
+		if (RLV_ROOT_FOLDER == strFolder)
+		{
+			m_DestPath.pop_front();
+
+			const LLUUID& idRlvRoot = RlvInventory::instance().getSharedRootID();
+			if (idRlvRoot.notNull())
+			{
+				onCategoryCreateCallback(idRlvRoot, this);
+			}
+			else
+			{
+				inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, this);
+				const LLUUID idTemp = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, RLV_ROOT_FOLDER, f);
+				if (idTemp.notNull())
+					onCategoryCreateCallback(idTemp, this);
+			}
+			return true;
+		}
+	}
+	m_DestPath.clear();
+	return false;
+}
+
+// Checked: 2014-01-07 (RLVa-1.4.10)
+void RlvGiveToRLVOffer::onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOffer* pInstance)
+{
+	if (idFolder.isNull())
+	{
+		// Problem encountered, abort move
+		pInstance->onDestinationCreated(LLUUID::null, LLStringUtil::null);
+		return;
+	}
+
+	while (pInstance->m_DestPath.size() > 1)
+	{
+		std::string strFolder = pInstance->m_DestPath.front();
+		pInstance->m_DestPath.pop_front();
+
+		const LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(idFolder, strFolder, false);
+		if (pFolder)
+		{
+			idFolder = pFolder->getUUID();
+		}
+		else
+		{
+			LLInventoryObject::correctInventoryName(strFolder);
+			inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, pInstance);
+			const LLUUID idTemp = gInventory.createNewCategory(idFolder, LLFolderType::FT_NONE, strFolder, f);
+			if (idTemp.notNull())
+				onCategoryCreateCallback(idTemp, pInstance);
+			return;
+		}
+	}
+
+	// Destination folder should exist at this point (we'll be deallocated when the function returns)
+	pInstance->onDestinationCreated(idFolder, pInstance->m_DestPath.front());
+}
+
+// Checked: 2014-01-07 (RLVa-1.4.10)
+void RlvGiveToRLVOffer::moveAndRename(const LLUUID& idFolder, const LLUUID& idDestination, const std::string& strName)
+{
+	const LLViewerInventoryCategory* pDest = gInventory.getCategory(idDestination);
+	const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder);
+	if ( (pDest) && (pFolder) )
+	{
+		LLPointer<LLViewerInventoryCategory> pNewFolder = new LLViewerInventoryCategory(pFolder);
+		if (pDest->getUUID() != pFolder->getParentUUID())
+		{
+			LLInventoryModel::update_list_t update;
+			LLInventoryModel::LLCategoryUpdate updOldParent(pFolder->getParentUUID(), -1);
+			update.push_back(updOldParent);
+			LLInventoryModel::LLCategoryUpdate updNewParent(pDest->getUUID(), 1);
+			update.push_back(updNewParent);
+			gInventory.accountForUpdate(update);
+
+			pNewFolder->setParent(pDest->getUUID());
+			pNewFolder->updateParentOnServer(FALSE);
+		}
+
+		pNewFolder->rename(strName);
+		pNewFolder->updateServer(FALSE);
+		gInventory.updateCategory(pNewFolder);
+
+		gInventory.notifyObservers();
+	}
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0)
+void RlvGiveToRLVTaskOffer::changed(U32 mask)
+{
+	if (mask & LLInventoryObserver::ADD)
+	{
+		LLMessageSystem* pMsg = gMessageSystem;
+		if ( (pMsg->getMessageName()) && (0 == strcmp(pMsg->getMessageName(), "BulkUpdateInventory")) )
+		{
+			LLUUID idTransaction;
+			pMsg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, idTransaction);
+			if (m_idTransaction == idTransaction)
+			{
+				LLUUID idInvObject;
+				for (S32 idxBlock = 0, cntBlock = pMsg->getNumberOfBlocksFast(_PREHASH_FolderData); idxBlock < cntBlock; idxBlock++)
+				{
+					pMsg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, idInvObject, idxBlock);
+					if ( (idInvObject.notNull()) && (std::find(m_Folders.begin(), m_Folders.end(), idInvObject) == m_Folders.end()) )
+						m_Folders.push_back(idInvObject);
+				}
+
+				done();
+			}
+		}
+	}
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0)
+void RlvGiveToRLVTaskOffer::done()
+{
+	gInventory.removeObserver(this);
+
+	// We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers()
+	doOnIdleOneTime(boost::bind(&RlvGiveToRLVTaskOffer::doneIdle, this));
+}
+
+// Checked: 2014-01-07 (RLVa-1.4.10)
+void RlvGiveToRLVTaskOffer::doneIdle()
+{
+	const LLViewerInventoryCategory* pFolder = (m_Folders.size()) ? gInventory.getCategory(m_Folders.front()) : NULL;
+	if ( (!pFolder) || (!createDestinationFolder(pFolder->getName())) )
+		delete this;
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0)
+void RlvGiveToRLVTaskOffer::onDestinationCreated(const LLUUID& idFolder, const std::string& strName)
+{
+	const LLViewerInventoryCategory* pTarget = (idFolder.notNull()) ? gInventory.getCategory(idFolder) : NULL;
+	if (pTarget)
+	{
+		const LLUUID& idOfferedFolder = m_Folders.front();
+		moveAndRename(idOfferedFolder, idFolder, strName);
+		RlvBehaviourNotifyHandler::sendNotification("accepted_in_rlv inv_offer " + RlvInventory::instance().getSharedPath(idOfferedFolder));
+	}
+	delete this;
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0)
+void RlvGiveToRLVAgentOffer::done()
+{
+	gInventory.removeObserver(this);
+
+	// We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers()
+	doOnIdleOneTime(boost::bind(&RlvGiveToRLVAgentOffer::doneIdle, this));
+}
+
+// Checked: 2014-01-07 (RLVa-1.4.10)
+void RlvGiveToRLVAgentOffer::doneIdle()
+{
+	const LLViewerInventoryCategory* pFolder = (mComplete.size()) ? gInventory.getCategory(mComplete.front()) : NULL;
+	if ( (!pFolder) || (!createDestinationFolder(pFolder->getName())) )
+		delete this;
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0)
+void RlvGiveToRLVAgentOffer::onDestinationCreated(const LLUUID& idFolder, const std::string& strName)
+{
+	if ( (idFolder.notNull()) && (mComplete.size()) )
+		moveAndRename(mComplete[0], idFolder, strName);
+	delete this;
+}
+
+// ============================================================================
+// RlvWearableItemCollector
+//
+
+// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+RlvWearableItemCollector::RlvWearableItemCollector(const LLInventoryCategory* pFolder, RlvForceWear::EWearAction eAction, RlvForceWear::EWearFlags eFlags)
+	: m_idFolder(pFolder->getUUID()), m_eWearAction(eAction), m_eWearFlags(eFlags), 
+	  m_strWearAddPrefix(RlvSettings::getWearAddPrefix()), m_strWearReplacePrefix(RlvSettings::getWearReplacePrefix())
+{
+	m_Wearable.push_back(m_idFolder);
+
+	// Wear prefixes can't/shouldn't start with '.'
+	if ( (m_strWearAddPrefix.length() > 1) && (RLV_FOLDER_PREFIX_HIDDEN == m_strWearAddPrefix[0]) )
+		m_strWearAddPrefix.clear();
+	if ( (m_strWearReplacePrefix.length() > 1) && (RLV_FOLDER_PREFIX_HIDDEN == m_strWearReplacePrefix[0]) )
+		m_strWearReplacePrefix.clear();
+
+	// If there's a prefix on the "root" folder then it will override what we were passed in the constructor
+	m_eWearAction = getWearActionNormal(pFolder);
+	m_WearActionMap.insert(std::pair<LLUUID, RlvForceWear::EWearAction>(m_idFolder, m_eWearAction));
+}
+
+// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+RlvForceWear::EWearAction RlvWearableItemCollector::getWearActionNormal(const LLInventoryCategory* pFolder)
+{
+	RLV_ASSERT_DBG(!RlvInventory::isFoldedFolder(pFolder, false));
+	if ( (RlvForceWear::ACTION_WEAR_REPLACE == m_eWearAction) && (!m_strWearAddPrefix.empty()) &&
+		 (boost::algorithm::starts_with(pFolder->getName(), m_strWearAddPrefix)))
+	{
+		return RlvForceWear::ACTION_WEAR_ADD;
+	}
+	else if ( (RlvForceWear::ACTION_WEAR_ADD == m_eWearAction) && (!m_strWearReplacePrefix.empty()) &&
+		      (boost::algorithm::starts_with(pFolder->getName(), m_strWearReplacePrefix)) )
+	{
+		return RlvForceWear::ACTION_WEAR_REPLACE;
+	}
+	return (pFolder->getUUID() != m_idFolder) ? getWearAction(pFolder->getParentUUID()) : m_eWearAction;
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0e
+const LLUUID& RlvWearableItemCollector::getFoldedParent(const LLUUID& idFolder) const
+{
+	std::map<LLUUID, LLUUID>::const_iterator itFolder = m_FoldingMap.end(), itCur = m_FoldingMap.find(idFolder);
+	while (itCur != m_FoldingMap.end())
+	{
+		itFolder = itCur;
+		itCur = m_FoldingMap.find(itFolder->second);
+	}
+	return (m_FoldingMap.end() == itFolder) ? idFolder : itFolder->second;
+}
+
+// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+RlvForceWear::EWearAction RlvWearableItemCollector::getWearAction(const LLUUID& idFolder) const
+{
+	LLUUID idCurFolder(idFolder); std::map<LLUUID, RlvForceWear::EWearAction>::const_iterator itCurFolder;
+	while ((itCurFolder = m_WearActionMap.find(idCurFolder)) == m_WearActionMap.end())
+	{
+		const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idCurFolder);
+		if ((!pFolder) || (gInventory.getRootFolderID() == pFolder->getParentUUID()))
+			break;
+		idCurFolder = pFolder->getParentUUID();
+	}
+	return (itCurFolder != m_WearActionMap.end()) ? itCurFolder->second : m_eWearAction;
+}
+
+// Checked: 2010-09-30 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d
+bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder)
+{
+	// We treat folder links differently since they won't exist in the wearable folder list yet and their ancestry isn't relevant
+	bool fLinkedFolder = isLinkedFolder(pFolder->getUUID());
+	if ( (!fLinkedFolder) && (m_Wearable.end() == std::find(m_Wearable.begin(), m_Wearable.end(), pFolder->getParentUUID())) )
+		return false;															// Not a linked folder or the child of a wearable folder
+
+	const std::string& strFolder = pFolder->getName();
+	if (strFolder.empty())														// Shouldn't happen but does... naughty Lindens
+		return false;
+
+	bool fAttach = RlvForceWear::isWearAction(m_eWearAction);
+	bool fMatchAll = (!fLinkedFolder) && (m_eWearFlags & RlvForceWear::FLAG_MATCHALL);
+
+	if ( (!fLinkedFolder) && (RlvInventory::isFoldedFolder(pFolder, false)) )	// Check for folder that should get folded under its parent
+	{
+		if ( (!fAttach) || (1 == RlvInventory::getDirectDescendentsItemCount(pFolder, LLAssetType::AT_OBJECT)) )
+		{																		// When attaching there should only be 1 attachment in it
+			m_Folded.push_front(pFolder->getUUID());
+			m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), pFolder->getParentUUID()));
+		}
+	}
+	else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && 					// Collect from any non-hidden child folder for *all
+		      ( (fMatchAll) || (fLinkedFolder) ) && 							// ... and collect from linked folders
+			  (!isLinkedFolder(pFolder->getParentUUID())) )						// ... but never from non-folded linked folder descendents
+	{
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		if ( (!RlvSettings::getEnableComposites()) ||							// ... if we're not checking composite folders
+			 (!gRlvHandler.isCompositeFolder(pFolder)) ||						// ... or if it's not a composite folder
+		     ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) ||		// ... or if we're attaching and can attach it OR
+			 (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) )		// ... or if we're detaching and can detach it
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		{
+			m_Wearable.push_front(pFolder->getUUID());
+			m_WearActionMap.insert(std::pair<LLUUID, RlvForceWear::EWearAction>(pFolder->getUUID(), getWearActionNormal(pFolder)));
+		}
+		return (!fLinkedFolder) && (pFolder->getParentUUID() == m_idFolder);	// Convenience for @getinvworn
+	}
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	else if ( (RlvSettings::getEnableComposites()) &&
+			  (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) &&						// Hidden folder that's a... 
+			  (gRlvHandler.isCompositeFolder(pFolder)) &&						// ... composite folder which we...
+		      ( ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) ||		// ... are attaching and can attach OR
+			    (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) )	// ... are detaching and can detach
+	{
+		m_Wearable.push_front(pFolder->getUUID());
+		m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent));
+	}
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	return false;
+}
+
+// Checked: 2010-09-30 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d
+bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem)
+{
+	bool fAttach = RlvForceWear::isWearAction(m_eWearAction);
+
+	if ( (!fAttach) && (!RlvForceWear::isStrippable(pItem)) )							// Don't process "nostrip" items on detach
+		return false;
+
+	const LLUUID& idParent = pItem->getParentUUID(); bool fRet = false;
+	switch (pItem->getType())
+	{
+		case LLAssetType::AT_BODYPART:
+			if (!fAttach)
+				break;																	// Don't process body parts on detach
+		case LLAssetType::AT_CLOTHING:
+			fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) ||
+					 ( (fAttach) && (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) &&
+					   (RlvForceWear::isStrippable(pItem)) ) );
+			break;
+		case LLAssetType::AT_OBJECT:
+			fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || 
+				     (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) ) &&
+				   ( (!fAttach) || (RlvAttachPtLookup::hasAttachPointName(pItem)) || (RlvSettings::getEnableSharedWear()) );
+			break;
+		case LLAssetType::AT_GESTURE:
+			fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent));
+			break;
+		case LLAssetType::AT_CATEGORY:
+			if (LLAssetType::AT_LINK_FOLDER == pItem->getActualType())
+			{
+				const LLUUID& idLinkedFolder = pItem->getLinkedUUID();
+				LLViewerInventoryCategory* pLinkedFolder = gInventory.getCategory(idLinkedFolder);
+				// Link can't point to an outfit folder, or start a second level of indirection, or have the base folder as an ancestor
+				if ( (pLinkedFolder) && (LLFolderType::FT_OUTFIT != pLinkedFolder->getPreferredType()) &&
+					 (gInventory.isObjectDescendentOf(pItem->getUUID(), m_idFolder)) && 
+					 (!gInventory.isObjectDescendentOf(idLinkedFolder, m_idFolder)) )
+				{
+					// Fold the contents of the linked folder under the folder the link is a child of
+					m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(idLinkedFolder, pItem->getParentUUID()));
+					m_Linked.push_front(idLinkedFolder);
+				}
+			}
+			break;
+		default:
+			break;
+	}
+	return fRet;
+}
+
+// Checked: 2010-03-20 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d
+bool RlvWearableItemCollector::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem)
+{
+	// NOTE: this is used for more than was originally intended so only modify if you're sure it won't break something obscure
+	return (pFolder) ? onCollectFolder(pFolder) : ( (pItem) ? onCollectItem(pItem) : false );
+}
+
+// ============================================================================
+// General purpose inventory helper classes
+//
+
+// Checked: 2013-10-12 (RLVa-1.4.9)
+bool RlvFindAttachmentsOnPoint::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem)
+{
+#ifndef RLV_DEPRECATE_ATTACHPTNAMING
+	// First check if the item is attached to the attachment point; fall back to the item name otherwise
+	return (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) &&
+		( ((m_pAttachPt) && (m_pAttachPt->getAttachedObject(pItem->getLinkedUUID()))) || (RlvAttachPtLookup::getAttachPoint(pItem) == m_pAttachPt) );
+#else
+	return (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (m_pAttachPt) && (m_pAttachPt->getAttachedObject(pItem->getLinkedUUID()));
+#endif // RLV_DEPRECATE_LEGACY_ATTACHPT
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d1f2ca34e12e62065b647842820bb5706e806a9
--- /dev/null
+++ b/indra/newview/rlvinventory.h
@@ -0,0 +1,344 @@
+/** 
+ *
+ * Copyright (c) 2009-2014, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_INVENTORY_H
+#define RLV_INVENTORY_H
+
+#include "llinventoryfunctions.h"
+#include "llinventoryobserver.h"
+#include "llsingleton.h"
+
+#include "rlvhelper.h"
+#include "rlvlocks.h"
+
+// ============================================================================
+// Forward declarations
+//
+
+class LLOfferInfo;
+
+// ============================================================================
+// RlvInventory class declaration
+//
+
+class RlvInventory : public LLSingleton<RlvInventory>, public LLInventoryObserver
+{
+protected:
+	RlvInventory();
+public:
+	~RlvInventory();
+
+	// LLInventoryObserver override
+	/*virtual*/ void changed(U32 mask);
+
+	/*
+	 * #RLV Shared inventory
+	 */
+public:
+	typedef boost::signals2::signal<void (void)> callback_signal_t;
+	void						addSharedRootIDChangedCallback(const callback_signal_t::slot_type& cb) { m_OnSharedRootIDChanged.connect(cb); }
+	// Find all folders that match a supplied criteria (clears the output array)
+	bool						findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const;
+	// Gets the shared path for any shared items present in idItems (clears the output array)
+	bool						getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const;
+	// Returns a pointer to the shared root folder (if there is one)
+	LLViewerInventoryCategory*	getSharedRoot() const;
+	const LLUUID&				getSharedRootID() const;
+	// Returns a subfolder of idParent that starts with strFolderName (exact match > partial match)
+	LLViewerInventoryCategory*	getSharedFolder(const LLUUID& idParent, const std::string& strFolderName, bool fMatchPartial = true) const;
+	// Looks up a folder from a path (relative to the shared root)
+	LLViewerInventoryCategory*	getSharedFolder(const std::string& strPath, bool fMatchPartial = true) const;
+	// Returns the path of the supplied folder (relative to the shared root)
+	std::string					getSharedPath(const LLViewerInventoryCategory* pFolder) const;
+	std::string					getSharedPath(const LLUUID& idFolder) const;
+	// Returns TRUE if the supplied folder is a descendent of the #RLV folder
+	bool						isSharedFolder(const LLUUID& idFolder);
+	// Returns TRUE if the inventory offer is a "give to #RLV" offer
+	bool						isGiveToRLVOffer(const LLOfferInfo& offerInfo);
+
+	/*
+	 * Inventory fetching
+	 */
+public:
+	void fetchSharedInventory();
+	void fetchWornItems();
+protected:
+	void fetchSharedLinks();
+
+	/*
+	 * General purpose helper functions
+	 */
+public:
+	// Returns the number of sub-folders of the specified folder
+	static S32 getDirectDescendentsFolderCount(const LLInventoryCategory* pFolder);
+	// Returns the number of direct descendents of the specified folder that have the specified type asset type
+	static S32 getDirectDescendentsItemCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType);
+	// Returns the folder the items of the specified folder should folded into (can be the folder itself)
+	static const LLUUID& getFoldedParent(const LLUUID& idFolder, bool fCheckComposite);
+	// A "folded folder" is a folder whose items logically belong to the grandparent rather than the parent
+	static bool isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	bool				m_fFetchStarted;			// TRUE if we fired off an inventory fetch
+	bool				m_fFetchComplete;			// TRUE if everything was fetched
+	mutable LLUUID		m_idRlvRoot;
+	callback_signal_t	m_OnSharedRootIDChanged;
+
+private:
+	static const std::string cstrSharedRoot;
+	friend class RlvSharedInventoryFetcher;
+	friend class LLSingleton<RlvInventory>;
+};
+
+// ============================================================================
+// RlvRenameOnWearObserver - Handles "auto-rename-on-wear" for (linked) items living under #RLV
+//
+
+class RlvRenameOnWearObserver : public LLInventoryFetchItemsObserver
+{
+public:
+	RlvRenameOnWearObserver(const LLUUID& idItem) : LLInventoryFetchItemsObserver(idItem) {}
+	virtual ~RlvRenameOnWearObserver() {}
+	virtual void done();
+protected:
+	void doneIdle();
+	static void onCategoryCreate(const LLUUID& idFolder, const LLUUID idItem);
+};
+
+// ============================================================================
+// "Give to #RLV" helper classes
+//
+
+class RlvGiveToRLVOffer
+{
+protected:
+	RlvGiveToRLVOffer() {}
+	virtual ~RlvGiveToRLVOffer() {}
+protected:
+	bool         createDestinationFolder(const std::string& strPath);
+	virtual void onDestinationCreated(const LLUUID& idFolder, const std::string& strName) = 0;
+	void         moveAndRename(const LLUUID& idFolder, const LLUUID& idDestination, const std::string& strName);
+private:
+	static void  onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOffer* pInstance);
+
+private:
+	std::list<std::string> m_DestPath;
+};
+
+// [See LLInventoryTransactionObserver which says it's not entirely complete?]
+// NOTE: the offer may span mulitple BulkUpdateInventory messages so if we're no longer around then (ie due to "delete this") then
+//       we'll miss those; in this specific case we only care about the *folder* though and that will be in the very first message
+class RlvGiveToRLVTaskOffer : public LLInventoryObserver, RlvGiveToRLVOffer
+{
+public:
+	RlvGiveToRLVTaskOffer(const LLUUID& idTransaction) : RlvGiveToRLVOffer(), m_idTransaction(idTransaction) {}
+	/*virtual*/ void changed(U32 mask);
+protected:
+	/*virtual*/ void done();
+	            void doneIdle();
+	/*virtual*/ void onDestinationCreated(const LLUUID& idFolder, const std::string& strName);
+
+protected:
+	typedef std::vector<LLUUID> folder_ref_t;
+	folder_ref_t m_Folders;
+	LLUUID       m_idTransaction;
+};
+
+class RlvGiveToRLVAgentOffer : public LLInventoryFetchDescendentsObserver, RlvGiveToRLVOffer
+{
+public:
+	RlvGiveToRLVAgentOffer(const LLUUID& idFolder) : RlvGiveToRLVOffer(), LLInventoryFetchDescendentsObserver(idFolder) {}
+	/*virtual*/ ~RlvGiveToRLVAgentOffer() {}
+public:
+	/*virtual*/ void done();
+protected:
+	            void doneIdle();
+	/*virtual*/ void onDestinationCreated(const LLUUID& idFolder, const std::string& strName);
+};
+
+// ============================================================================
+// RlvCriteriaCategoryCollector - Criteria based folder matching filter used by @findfolder and @findfolders
+//
+
+class RlvCriteriaCategoryCollector : public LLInventoryCollectFunctor
+{
+public:
+	RlvCriteriaCategoryCollector(const std::string& strCriteria)
+	{
+		std::string::size_type idxIt, idxLast = 0;
+		while (idxLast < strCriteria.length())
+		{
+			idxIt = strCriteria.find("&&", idxLast);
+			if (std::string::npos == idxIt)
+				idxIt = strCriteria.length();
+			if (idxIt != idxLast)
+				m_Criteria.push_back(strCriteria.substr(idxLast, idxIt - idxLast));
+			idxLast = idxIt + 2;
+		}
+	}
+	virtual ~RlvCriteriaCategoryCollector() {}
+
+	virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem)
+	{
+		if ( (!pFolder) || (m_Criteria.empty()) )	// We're only interested in matching folders, we don't care about items
+			return false;							// (if there are no criteria then we don't want to return a match)
+
+		std::string strFolderName = pFolder->getName();
+		LLStringUtil::toLower(strFolderName);
+
+		// NOTE: hidden or "give to #RLV" folders can never be a match
+		if ( (strFolderName.empty()) ||	
+			 (RLV_FOLDER_PREFIX_HIDDEN == strFolderName[0]) || (RLV_FOLDER_PREFIX_PUTINV == strFolderName[0]) )
+		{
+			return false;
+		}
+
+		for (std::list<std::string>::const_iterator itCrit = m_Criteria.begin(); itCrit != m_Criteria.end(); ++itCrit)
+			if (std::string::npos == strFolderName.find(*itCrit))
+				return false;
+		return true;
+	}
+
+protected:
+	std::list<std::string> m_Criteria;
+};
+
+// ============================================================================
+// RlvWearableItemCollector - Inventory item filter used by attach/detach/attachall/detachall/getinvworn
+//
+
+class RlvWearableItemCollector : public LLInventoryCollectFunctor
+{
+public:
+	RlvWearableItemCollector(const LLInventoryCategory* pFolder, RlvForceWear::EWearAction eAction, RlvForceWear::EWearFlags eFlags);
+	virtual ~RlvWearableItemCollector() {}
+
+	virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem);
+
+	const LLUUID&             getFoldedParent(const LLUUID& idFolder) const;
+	RlvForceWear::EWearAction getWearAction(const LLUUID& idFolder) const;
+	RlvForceWear::EWearAction getWearActionNormal(const LLInventoryCategory* pFolder);
+	RlvForceWear::EWearAction getWearActionFolded(const LLInventoryCategory* pFolder);
+	bool                      isLinkedFolder(const LLUUID& idFolder);
+protected:
+	const LLUUID              m_idFolder;
+	RlvForceWear::EWearAction m_eWearAction;
+	RlvForceWear::EWearFlags  m_eWearFlags;
+
+	bool onCollectFolder(const LLInventoryCategory* pFolder);
+	bool onCollectItem(const LLInventoryItem* pItem);
+
+	std::list<LLUUID> m_Folded;
+	std::list<LLUUID> m_Linked;
+	std::list<LLUUID> m_Wearable;
+	std::map<LLUUID, LLUUID>                    m_FoldingMap;
+	std::map<LLUUID, RlvForceWear::EWearAction> m_WearActionMap;
+
+	std::string m_strWearAddPrefix;
+	std::string m_strWearReplacePrefix;
+};
+
+// ============================================================================
+// General purpose inventory helper classes
+//
+
+class RlvIsLinkType : public LLInventoryCollectFunctor
+{
+public:
+	RlvIsLinkType() {}
+	/*virtual*/ ~RlvIsLinkType() {}
+	virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) { return (pItem) && (pItem->getIsLinkType()); }
+};
+
+// If the attachment item is linked in COF but isn't worn (or just detached) the function will return inconsistent information
+class RlvFindAttachmentsOnPoint : public LLInventoryCollectFunctor
+{
+public:
+	RlvFindAttachmentsOnPoint(const LLViewerJointAttachment* pAttachPt) : m_pAttachPt(pAttachPt) {}
+	/*virtual*/ ~RlvFindAttachmentsOnPoint() {}
+	virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem);
+protected:
+	const LLViewerJointAttachment* m_pAttachPt;
+};
+
+// ============================================================================
+// RlvInventory inlined member functions
+//
+
+// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+inline LLViewerInventoryCategory* RlvInventory::getSharedRoot() const
+{
+	const LLUUID& idRlvRoot = getSharedRootID();
+	return (idRlvRoot.notNull()) ? gInventory.getCategory(idRlvRoot) : NULL;
+}
+
+// Checked: 2011-11-26 (RLVa-1.5.4a) | Added: RLVa-1.5.4a
+inline const LLUUID& RlvInventory::getFoldedParent(const LLUUID& idFolder, bool fCheckComposite)
+{
+	LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder);
+	while ((pFolder) && (isFoldedFolder(pFolder, fCheckComposite)))
+		pFolder = gInventory.getCategory(pFolder->getParentUUID());
+	return (pFolder) ? pFolder->getUUID() : LLUUID::null;
+}
+
+// Checked: 2011-11-26 (RLVa-1.5.4a) | Added: RLVa-1.5.4a
+inline std::string RlvInventory::getSharedPath(const LLUUID& idFolder) const
+{
+	return getSharedPath(gInventory.getCategory(idFolder));
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline bool RlvInventory::isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite)
+{
+	return
+	  // If legacy naming isn't enabled we can return early if the folder name doesn't start with a '.' (= the most common case)
+	  (pFolder) && ( (RlvSettings::getEnableLegacyNaming()) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) &&
+	  (
+		// .(<attachpt>) type folder
+		(0 != RlvAttachPtLookup::getAttachPointIndex(pFolder))
+		// .(nostrip) folder
+		|| ( (pFolder) && (".(" RLV_FOLDER_FLAG_NOSTRIP ")" == pFolder->getName()) )
+		// Composite folder (if composite folders are enabled and we're asked to look for them)
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		|| ( (fCheckComposite) && (RlvSettings::getEnableComposites()) &&
+		     (pFolder) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) && (isCompositeFolder(pFolder)) )
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	  );
+}
+
+// Checked: 2010-08-29 (RLVa-1.2.0c) | Added: RLVa-1.2.0c
+inline bool RlvInventory::isSharedFolder(const LLUUID& idFolder)
+{
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	return (pRlvRoot) ? (pRlvRoot->getUUID() != idFolder) && (gInventory.isObjectDescendentOf(idFolder, pRlvRoot->getUUID())) : false;
+}
+
+// ============================================================================
+// RlvWearableItemCollector inlined member functions
+//
+
+// Checked: 2010-09-30 (RLVa-1.2.1d) | Added: RLVa-1.2.1d
+inline bool RlvWearableItemCollector::isLinkedFolder(const LLUUID& idFolder)
+{
+	return (!m_Linked.empty()) && (m_Linked.end() != std::find(m_Linked.begin(), m_Linked.end(), idFolder));
+}
+
+// ============================================================================
+
+#endif // RLV_INVENTORY_H
diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b7ac55da32f7d6bbef51e58837e9235c30355c9b
--- /dev/null
+++ b/indra/newview/rlvlocks.cpp
@@ -0,0 +1,1294 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llattachmentsmgr.h"
+#include "lloutfitobserver.h"
+#include "llviewerobjectlist.h"
+#include "llviewermenu.h"
+#include "pipeline.h"
+
+#include "rlvlocks.h"
+#include "rlvhelper.h"
+#include "rlvinventory.h"
+
+
+// ============================================================================
+// RlvAttachPtLookup member functions
+//
+
+std::map<std::string, S32> RlvAttachPtLookup::m_AttachPtLookupMap;
+
+// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachPtLookup::initLookupTable()
+{
+	static bool fInitialized = false;
+	if (!fInitialized)
+	{
+		if ( (gAgentAvatarp) && (gAgentAvatarp->mAttachmentPoints.size() > 0) )
+		{
+			std::string strAttachPtName;
+			for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+					 itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+			{
+				const LLViewerJointAttachment* pAttachPt = itAttach->second;
+				if (pAttachPt)
+				{
+					strAttachPtName = pAttachPt->getName();
+					LLStringUtil::toLower(strAttachPtName);
+					m_AttachPtLookupMap.insert(std::pair<std::string, S32>(strAttachPtName, itAttach->first));
+
+					// HACK: the RLV API randomly renames "Avatar Center" to "Root" so make sure we add it (but keep the official name)
+					if ("avatar center" == strAttachPtName)
+					{
+						m_AttachPtLookupMap.insert(std::pair<std::string, S32>("root", itAttach->first));
+					}
+				}
+			}
+			fInitialized = true;
+		}
+	}
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-0.2.2a
+S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerJointAttachment* pAttachPt)
+{
+	if (isAgentAvatarValid())
+	{
+		for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+				itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+		{
+			if (itAttach->second == pAttachPt)
+				return itAttach->first;
+		}
+	}
+	return 0;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b
+S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryCategory* pFolder)
+{
+	if (!pFolder)
+		return 0;
+
+	// RLVa-1.0.1 added support for legacy matching (See http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/)
+	if (RlvSettings::getEnableLegacyNaming())
+		return getAttachPointIndexLegacy(pFolder);
+
+	// Otherwise the only valid way to specify an attachment point in a folder name is: ^\.\(\s+attachpt\s+\)
+	std::string::size_type idxMatch;
+	std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch);
+	LLStringUtil::trim(strAttachPt);
+
+	return ( (1 == idxMatch) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) ? getAttachPointIndex(strAttachPt) : 0;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks /*=true*/)
+{
+	// Sanity check - if it's not an object then it can't have an attachment point
+	if ( (!pItem) || (LLAssetType::AT_OBJECT != pItem->getType()) )
+		return 0;
+
+	// If the item is an inventory link then we first examine its target before examining the link itself
+	if ( (LLAssetType::AT_LINK == pItem->getActualType()) && (fFollowLinks) )
+	{
+		S32 idxAttachPt = getAttachPointIndex(gInventory.getItem(pItem->getLinkedUUID()), false);
+		if (idxAttachPt)
+			return idxAttachPt;
+	}
+
+	// The attachment point should be placed at the end of the item's name, surrounded by parenthesis
+	// (if there is no such text then strAttachPt will be an empty string which is fine since it means we'll look at the item's parent)
+	// (if the item is an inventory link then we only look at its containing folder and never examine its name)
+	std::string strAttachPt = 
+		(LLAssetType::AT_LINK != pItem->getActualType()) ? rlvGetLastParenthesisedText(pItem->getName()) : LLStringUtil::null;
+	LLStringUtil::trim(strAttachPt);
+
+	// If the item is modify   : we look at the item's name first and only then at the containing folder
+	// If the item is no modify: we look at the containing folder's name first and only then at the item itself
+	S32 idxAttachPt = 0;
+	if (pItem->getPermissions().allowModifyBy(gAgent.getID()))
+	{
+		idxAttachPt = (!strAttachPt.empty()) ? getAttachPointIndex(strAttachPt) : 0;
+		if (!idxAttachPt)
+			idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID()));
+	}
+	else
+	{
+		idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID()));
+		if ( (!idxAttachPt) && (!strAttachPt.empty()) )
+			idxAttachPt = getAttachPointIndex(strAttachPt);
+	}
+	return idxAttachPt;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.0.1b
+S32 RlvAttachPtLookup::getAttachPointIndexLegacy(const LLInventoryCategory* pFolder)
+{
+	// Hopefully some day this can just be deprecated (see http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/)
+	if ( (!pFolder) || (pFolder->getName().empty()) )
+		return 0;
+
+	// Check for a (...) block *somewhere* in the name
+	std::string::size_type idxMatch;
+	std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch);
+	if (!strAttachPt.empty())
+	{
+		// Could be "(attachpt)", ".(attachpt)" or "Folder name (attachpt)"
+		if ( (0 != idxMatch) && ((1 != idxMatch) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) &&	// No '(' or '.(' start
+			 (idxMatch + strAttachPt.length() + 1 != pFolder->getName().length()) )								// or there's extra text
+		{
+			// It's definitely not one of the first two so assume it's the last form (in which case we need the last paranthesised block)
+			strAttachPt = rlvGetLastParenthesisedText(pFolder->getName());
+		}
+	}
+	else
+	{
+		// There's no paranthesised block, but it could still be "attachpt" or ".attachpt" (just strip away the '.' from the last one)
+		strAttachPt = pFolder->getName();
+		if (RLV_FOLDER_PREFIX_HIDDEN == strAttachPt[0])
+			strAttachPt.erase(0, 1);
+	}
+	return getAttachPointIndex(strAttachPt);
+}
+
+// ============================================================================
+// RlvAttachmentLocks member functions
+//
+
+RlvAttachmentLocks gRlvAttachmentLocks;
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+#ifndef RLV_RELEASE
+	LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj);
+	// Assertion: the object specified by idAttachObj exists/is rezzed, is an attachment and always specifies the root
+	RLV_VERIFY( (pDbgObj) && (pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit()) );
+#endif // RLV_RELEASE
+
+	m_AttachObjRem.insert(std::pair<LLUUID, LLUUID>(idAttachObj, idRlvObj));
+	updateLockedHUD();
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	// NOTE: m_AttachPtXXX can contain duplicate <idxAttachPt, idRlvObj> pairs (ie @detach:spine=n,detach=n from an attachment on spine)
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		m_AttachPtRem.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj));
+		updateLockedHUD();
+	}
+	if (eLock & RLV_LOCK_ADD)
+		m_AttachPtAdd.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj));
+}
+
+// Checked: 2011-05-22 (RLVa-1.3.1b) | Added: RLVa-1.3.1b
+bool RlvAttachmentLocks::canAttach() const
+{
+	if (isAgentAvatarValid())
+	{
+		for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); 
+				itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt)
+		{
+			if (!isLockedAttachmentPoint(itAttachPt->first, RLV_LOCK_ADD))
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+bool RlvAttachmentLocks::canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll /*=false*/) const
+{
+	//   (fDetachAll) | (isLockedAttachment)
+	//   ===================================
+	//        F       |         F             => unlocked attachment => return true
+	//        F       |         T             => locked attachment   => keep going
+	//        T       |         F             => unlocked attachment => keep going
+	//        T       |         T             => locked attachment   => return false
+	//  -> inside the loop : (A xor (not B)) condition and return !fDetachAll
+	//  -> outside the loop: return fDetachAll
+	//       fDetachAll == false : return false => all attachments are locked
+	//       fDetachAll == true  : return true  => all attachments are unlocked
+	if (pAttachPt)
+	{
+		for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+				itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+		{
+			if ( (fDetachAll) ^ (!isLockedAttachment(*itAttachObj)) )
+				return !fDetachAll;
+		}
+	}
+	return (pAttachPt) && (fDetachAll);
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvAttachmentLocks::hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const
+{
+	if (pAttachPt)
+	{
+		for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+				itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+		{
+			if (isLockedAttachment(*itAttachObj))
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvAttachmentLocks::isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedAttachment(pObj);
+
+	// If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem
+	RLV_ASSERT( (!pObj) || (pObj == pObj->getRootEdit()) );
+
+	// Loop over every object that has the specified attachment locked (but ignore any locks owned by idRlvObj)
+	for (rlv_attachobjlock_map_t::const_iterator itAttachObj = m_AttachObjRem.lower_bound(pObj->getID()), 
+			endAttachObj = m_AttachObjRem.upper_bound(pObj->getID()); itAttachObj != endAttachObj; ++itAttachObj)
+	{
+		if (itAttachObj->second != idRlvObj)
+			return true;
+	}
+	return isLockedAttachmentPointExcept(RlvAttachPtLookup::getAttachPointIndex(pObj), RLV_LOCK_REMOVE, idRlvObj);
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.0.5b
+bool RlvAttachmentLocks::isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedAttachmentPoint(idxAttachPt, eLock);
+
+	// Loop over every object that has the specified attachment point locked (but ignore any locks owned by idRlvObj)
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (itAttachPt->second != idRlvObj)
+				return true;
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (itAttachPt->second != idRlvObj)
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+#ifndef RLV_RELEASE
+	// NOTE: pObj *can* be NULL [see comments for @detach=n in RlvHandler::onAddRemDetach()]
+	const LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj);
+	// Assertion: if the object exists then it's an attachment and always specifies the root
+	RLV_VERIFY( (!pDbgObj) || ((pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit())) );
+#endif // RLV_RELEASE
+
+	// NOTE: try to remove the lock even if pObj isn't an attachment (ie in case the user was able to "Drop" it)
+	RLV_ASSERT( m_AttachObjRem.lower_bound(idAttachObj) != m_AttachObjRem.upper_bound(idAttachObj) ); // The lock should always exist
+	for (rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.lower_bound(idAttachObj), 
+			endAttachObj = m_AttachObjRem.upper_bound(idAttachObj); itAttachObj != endAttachObj; ++itAttachObj)
+	{
+		if (idRlvObj == itAttachObj->second)
+		{
+			m_AttachObjRem.erase(itAttachObj);
+			updateLockedHUD();
+			break;
+		}
+	}
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		RLV_ASSERT( m_AttachPtRem.lower_bound(idxAttachPt) != m_AttachPtRem.upper_bound(idxAttachPt) ); // The lock should always exist
+		for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (idRlvObj == itAttachPt->second)
+			{
+				m_AttachPtRem.erase(itAttachPt);
+				updateLockedHUD();
+				break;
+			}
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		RLV_ASSERT( m_AttachPtAdd.lower_bound(idxAttachPt) != m_AttachPtAdd.upper_bound(idxAttachPt) ); // The lock should always exist
+		for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (idRlvObj == itAttachPt->second)
+			{
+				m_AttachPtAdd.erase(itAttachPt);
+				break;
+			}
+		}
+	}
+}
+
+// Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+void RlvAttachmentLocks::updateLockedHUD()
+{
+	if (!isAgentAvatarValid())
+		return;
+
+	m_fHasLockedHUD = false;
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+		if ( (pAttachPt) && (pAttachPt->getIsHUDAttachment()) && (hasLockedAttachment(pAttachPt)) )
+		{
+			m_fHasLockedHUD = true;
+			break;
+		}
+	}
+
+	// Reset HUD visibility and wireframe options if at least one HUD attachment is locked
+	if (m_fHasLockedHUD)
+	{
+		set_use_wireframe(false);
+	}
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvAttachmentLocks::verifyAttachmentLocks()
+{
+	bool fSuccess = true;
+
+	// Verify attachment locks
+	rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.begin(), itCurrentObj;
+	while (itAttachObj != m_AttachObjRem.end())
+	{
+		itCurrentObj = itAttachObj++;
+
+		// If the attachment no longer exists (or is no longer attached) then we shouldn't be holding a lock to it
+		const LLViewerObject* pAttachObj = gObjectList.findObject(itCurrentObj->first);
+		if ( (!pAttachObj) || (!pAttachObj->isAttachment()) )
+		{
+			m_AttachObjRem.erase(itCurrentObj);
+			fSuccess = false;
+		}
+	}
+
+	return fSuccess;
+}
+
+// ============================================================================
+// RlvAttachmentLockWatchdog member functions
+//
+
+// Checked: 2010-09-23 (RLVa-1.2.1d) | Added: RLVa-1.2.1d
+bool RlvAttachmentLockWatchdog::RlvWearInfo::isAddLockedAttachPt(S32 idxAttachPt) const
+{
+	// If idxAttachPt has no entry in attachPts then the attachment point wasn't RLV_LOCK_ADD restricted at the time we were instantiated
+	// [See RlvAttachmentLockWatchdog::onWearAttachment()]
+	return (attachPts.find(idxAttachPt) != attachPts.end());
+}
+
+// Checked: 2010-09-23 (RLVa-1.2.1d) | Added: RLVa-1.2.1d
+void RlvAttachmentLockWatchdog::RlvWearInfo::dumpInstance() const
+{
+	const LLViewerInventoryItem* pItem = gInventory.getItem(idItem);
+	std::string strItemId = idItem.asString();
+
+	std::string strTemp = llformat("Wear %s '%s' (%s)", 
+		(RLV_WEAR_ADD == eWearAction) ? "add" : "replace", (pItem) ? pItem->getName().c_str() : "missing", strItemId.c_str());
+	RLV_INFOS << strTemp.c_str() << RLV_ENDL;
+
+	if (!attachPts.empty())
+	{
+		std::string strEmptyAttachPt;
+		for (std::map<S32, uuid_vec_t>::const_iterator itAttachPt = attachPts.begin(); itAttachPt != attachPts.end(); ++itAttachPt)
+		{
+			const LLViewerJointAttachment* pAttachPt =
+				get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL);
+			if (!itAttachPt->second.empty())
+			{
+				for (uuid_vec_t::const_iterator itAttach = itAttachPt->second.begin(); itAttach != itAttachPt->second.end(); ++itAttach)
+				{
+					pItem = gInventory.getItem(*itAttach);
+					strItemId = (*itAttach).asString();
+
+					strTemp = llformat("  -> %s : %s (%s)",
+						pAttachPt->getName().c_str(), (pItem) ? pItem->getName().c_str() : "missing", strItemId.c_str());
+					RLV_INFOS << strTemp.c_str() << RLV_ENDL;
+				}
+			}
+			else
+			{
+				if (!strEmptyAttachPt.empty())
+					strEmptyAttachPt += ", ";
+				strEmptyAttachPt += pAttachPt->getName();
+			}
+		}
+		if (!strEmptyAttachPt.empty())
+			RLV_INFOS << "  -> " << strEmptyAttachPt << " : empty" << RLV_ENDL;
+	}
+	else
+	{
+		RLV_INFOS << "  -> no attachment point information" << RLV_ENDL;
+	}
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::detach(const LLViewerObject* pAttachObj)
+{
+	if (pAttachObj)
+	{
+		gMessageSystem->newMessage("ObjectDetach");
+		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+		gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID());
+		if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) == m_PendingDetach.end())
+			m_PendingDetach.push_back(pAttachObj->getAttachmentItemID());
+
+		gMessageSystem->sendReliable(gAgent.getRegionHost() );
+	}
+}
+
+// Checked: 2011-06-13 (RLVa-1.3.1b) | Modified: RLVa-1.3.1b
+void RlvAttachmentLockWatchdog::detach(S32 idxAttachPt, const uuid_vec_t& idsAttachObjExcept)
+{
+	const LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(idxAttachPt);
+	if (!pAttachPt)
+		return;
+
+	std::vector<const LLViewerObject*> attachObjs;
+	for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+			itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+	{
+		const LLViewerObject* pAttachObj = *itAttachObj;
+		if (idsAttachObjExcept.end() == std::find(idsAttachObjExcept.begin(), idsAttachObjExcept.end(), pAttachObj->getID()))
+			attachObjs.push_back(pAttachObj);
+	}
+
+	if (!attachObjs.empty())
+	{
+		gMessageSystem->newMessage("ObjectDetach");
+		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+		
+		for (std::vector<const LLViewerObject*>::const_iterator itAttachObj = attachObjs.begin(); itAttachObj != attachObjs.end(); ++itAttachObj)
+		{
+			const LLViewerObject* pAttachObj = *itAttachObj;
+			gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+			gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID());
+			if (m_PendingDetach.end() == std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()))
+				m_PendingDetach.push_back(pAttachObj->getAttachmentItemID());
+		}
+
+		gMessageSystem->sendReliable(gAgent.getRegionHost());
+	}
+}
+
+// Checked: 2010-09-23 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d
+void RlvAttachmentLockWatchdog::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj);
+	const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null;
+	RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) );
+	if ( (!idxAttachPt) || (idAttachItem.isNull()) )
+		return;
+
+	// Check if the attachment point has a pending "reattach"
+	rlv_attach_map_t::iterator itAttach = m_PendingAttach.lower_bound(idxAttachPt), itAttachEnd = m_PendingAttach.upper_bound(idxAttachPt);
+	if (itAttach != itAttachEnd)
+	{
+		bool fPendingReattach = false;
+		for (; itAttach != itAttachEnd; ++itAttach)
+		{
+			if (idAttachItem == itAttach->second.idItem)
+			{
+				fPendingReattach = true;
+				RlvBehaviourNotifyHandler::onReattach(pAttachPt, true);
+				m_PendingAttach.erase(itAttach);
+				break;
+			}
+		}
+		if (!fPendingReattach)
+		{
+			detach(pAttachObj);
+			RlvBehaviourNotifyHandler::onAttach(pAttachPt, false);
+		}
+		return;
+	}
+
+	// Check if the attach was allowed at the time it was requested
+	rlv_wear_map_t::iterator itWear = m_PendingWear.find(idAttachItem); bool fAttachAllowed = true;
+	if (itWear != m_PendingWear.end())
+	{
+		// We'll need to return the attachment point to its previous state if it was non-attachable
+		if (itWear->second.isAddLockedAttachPt(idxAttachPt))
+		{
+			// Get the saved state of the attachment point (but do nothing if the item itself was already worn then)
+			std::map<S32, uuid_vec_t>::iterator itAttachPrev = itWear->second.attachPts.find(idxAttachPt);
+			RLV_ASSERT(itAttachPrev != itWear->second.attachPts.end());
+			if (std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), idAttachItem) == itAttachPrev->second.end())
+			{
+				// If it was empty we need to detach everything on the attachment point; if it wasn't we need to restore it to what it was
+				if (itAttachPrev->second.empty())
+				{
+					detach(idxAttachPt);
+				}
+				else
+				{
+					// Iterate over all the current attachments and force detach any that shouldn't be there
+					for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+							itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+					{
+						const LLViewerObject* pAttachObj = *itAttachObj;
+
+						uuid_vec_t::iterator itAttach = 
+							std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), pAttachObj->getAttachmentItemID());
+						if (itAttach == itAttachPrev->second.end())
+							detach(pAttachObj);
+						else
+							itAttachPrev->second.erase(itAttach);
+					}
+
+					// Whatever is left is something that needs to be reattached
+					for (uuid_vec_t::const_iterator itAttach = itAttachPrev->second.begin(); 
+							itAttach != itAttachPrev->second.end(); ++itAttach)
+					{
+						m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(*itAttach)));
+					}
+				}
+				fAttachAllowed = false;
+			}
+		}
+		else if (RLV_WEAR_REPLACE == itWear->second.eWearAction)
+		{
+			// Now that we know where this attaches to, check if we can actually perform a "replace"
+			uuid_vec_t idsAttachObjExcept;
+			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					((itAttachObj != pAttachPt->mAttachedObjects.end()) && (fAttachAllowed)); ++itAttachObj)
+			{
+				if ( (pAttachObj != *itAttachObj) && (gRlvAttachmentLocks.isLockedAttachment(*itAttachObj)) )
+				{
+					// Fail if we encounter a non-detachable attachment (unless we're only replacing detachable attachments)
+					if (gSavedSettings.getBOOL("RLVaWearReplaceUnlocked"))
+						idsAttachObjExcept.push_back((*itAttachObj)->getID());
+					else
+						fAttachAllowed = false;
+				}
+			}
+
+			if (fAttachAllowed)
+			{
+				idsAttachObjExcept.push_back(pAttachObj->getID());	// Replace == allowed: detach everything except the new attachment
+				detach(idxAttachPt, idsAttachObjExcept);			// or detach all *unlocked* attachments except the new attachment
+			}
+			else
+			{
+				detach(pAttachObj);									// Replace != allowed: detach the new attachment
+			}
+		}
+		m_PendingWear.erase(itWear); // No need to start the timer since it should be running already if '!m_PendingWear.empty()'
+	}
+	RlvBehaviourNotifyHandler::onAttach(pAttachPt, fAttachAllowed);
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt);
+	const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null;
+	RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) );
+	if ( (!idxAttachPt) || (idAttachItem.isNull()) )
+		return;
+
+	// If it's an attachment that's pending force-detach then we don't want to do anything (even if it's currently "remove locked")
+	rlv_detach_map_t::iterator itDetach = std::find(m_PendingDetach.begin(), m_PendingDetach.end(), idAttachItem);
+	if (itDetach != m_PendingDetach.end())
+	{
+		m_PendingDetach.erase(itDetach);
+		RlvBehaviourNotifyHandler::onDetach(pAttachPt, true);
+		return;
+	}
+
+	// If the attachment is currently "remove locked" then we should reattach it (unless it's already pending reattach)
+	bool fDetachAllowed = true;
+	if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj))
+	{
+		bool fPendingAttach = false;
+		for (rlv_attach_map_t::const_iterator itReattach = m_PendingAttach.lower_bound(idxAttachPt), 
+				itReattachEnd = m_PendingAttach.upper_bound(idxAttachPt); itReattach != itReattachEnd; ++itReattach)
+		{
+			if (itReattach->second.idItem == idAttachItem)
+			{
+				fPendingAttach = true;
+				break;
+			}
+		}
+
+		// TODO-RLVa: [RLVa-1.2.1] we should re-add the item to COF as well to make sure it'll reattach when the user relogs
+		//		-> check the call order in LLVOAvatarSelf::detachObject() since COF removal happens *after* we're called
+		if (!fPendingAttach)
+		{
+			m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(idAttachItem)));
+			startTimer();
+		}
+		fDetachAllowed = false;
+	}
+	RlvBehaviourNotifyHandler::onDetach(pAttachPt, fDetachAllowed);
+}
+
+// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b
+void RlvAttachmentLockWatchdog::onSavedAssetIntoInventory(const LLUUID& idItem)
+{
+	for (rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin(); itAttach != m_PendingAttach.end(); ++itAttach)
+	{
+		if ( (!itAttach->second.fAssetSaved) && (idItem == itAttach->second.idItem) )
+		{
+			LLAttachmentsMgr::instance().addAttachmentRequest(itAttach->second.idItem, itAttach->first, true, true);
+			itAttach->second.tsAttach = LLFrameTimer::getElapsedSeconds();
+		}
+	}
+}
+
+// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b
+BOOL RlvAttachmentLockWatchdog::onTimer()
+{
+	// RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS"
+	F64 tsCurrent = LLFrameTimer::getElapsedSeconds();
+
+	// Garbage collect (failed) wear requests older than 60 seconds
+	rlv_wear_map_t::iterator itWear = m_PendingWear.begin();
+	while (itWear != m_PendingWear.end())
+	{
+		if (itWear->second.tsWear + 60 < tsCurrent)
+			m_PendingWear.erase(itWear++);
+		else
+			++itWear;
+	}
+
+	// Walk over the pending reattach list
+	rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin();
+	while (itAttach != m_PendingAttach.end())
+	{
+		// Sanity check - make sure the item is still in the user's inventory
+		if (gInventory.getItem(itAttach->second.idItem) == NULL)
+		{
+			m_PendingAttach.erase(itAttach++);
+			continue;
+		}
+
+		// Force an attach if we haven't gotten a SavedAssetIntoInventory message after 15 seconds
+		// (or if it's been 30 seconds since we last tried to reattach the item)
+		bool fAttach = false;
+		if ( (!itAttach->second.fAssetSaved) && (itAttach->second.tsDetach + 15 < tsCurrent) )
+		{
+			itAttach->second.fAssetSaved = true;
+			fAttach = true;
+		}
+		else if ( (itAttach->second.fAssetSaved) && (itAttach->second.tsAttach + 30 < tsCurrent) )
+		{
+			fAttach = true;
+		}
+
+		if (fAttach)
+		{
+			LLAttachmentsMgr::instance().addAttachmentRequest(itAttach->second.idItem, itAttach->first, true, true);
+			itAttach->second.tsAttach = tsCurrent;
+		}
+
+		++itAttach;
+	}
+
+	return ( (m_PendingAttach.empty()) && (m_PendingDetach.empty()) && (m_PendingWear.empty()) );
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction)
+{
+	// We only need to keep track of user wears if there's actually anything locked
+	RLV_ASSERT(idItem.notNull());
+	if ( (idItem.isNull()) || (!isAgentAvatarValid()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+		return;
+
+	// If the attachment point this will end up being attached to is:
+	//   - unlocked    : nothing should happen (from RLVa's point of view)
+	//   - RLV_LOCK_ADD: the new attachment should get detached and the current one(s) reattached (unless it's currently empty)
+	//   - RLV_LOCK_REM:
+	//       o eWearAction == RLV_WEAR_ADD     : nothing should happen (from RLVa's point of view)
+	//       o eWearAction == RLV_WEAR_REPLACE : examine whether the new attachment can indeed replace/detach the old one
+	RlvWearInfo infoWear(idItem, eWearAction);
+	RLV_ASSERT( (RLV_WEAR_ADD == eWearAction) || (RLV_WEAR_REPLACE == eWearAction) ); // One of the two, but never both
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+		// We only need to know which attachments were present for RLV_LOCK_ADD locked attachment points (and not RLV_LOCK_REM locked ones)
+		if (gRlvAttachmentLocks.isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD))
+		{
+			uuid_vec_t attachObjs;
+			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+			{
+				const LLViewerObject* pAttachObj = *itAttachObj;
+				if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) != m_PendingDetach.end())
+					continue;	// Exclude attachments that are pending a force-detach
+				attachObjs.push_back(pAttachObj->getAttachmentItemID());
+			}
+			infoWear.attachPts.insert(std::pair<S32, uuid_vec_t>(itAttachPt->first, attachObjs));
+		}
+	}
+
+	m_PendingWear.insert(std::pair<LLUUID, RlvWearInfo>(idItem, infoWear));
+#ifdef RLV_DEBUG
+	infoWear.dumpInstance();
+#endif // RLV_RELEASE
+	startTimer();
+}
+
+// ============================================================================
+// RlvWearableLocks member functions
+//
+
+RlvWearableLocks gRlvWearableLocks;
+
+// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+void RlvWearableLocks::addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	// NOTE: m_WearableTypeXXX can contain duplicate <eType, idRlvObj> pairs (ie @remoutfit:shirt=n,remoutfit=n from the same object)
+	if (eLock & RLV_LOCK_REMOVE)
+		m_WearableTypeRem.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj));
+	if (eLock & RLV_LOCK_ADD)
+		m_WearableTypeAdd.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj));
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::canRemove(LLWearableType::EType eType) const
+{
+	// NOTE: we return TRUE if the wearable type has at least one wearable that can be removed by the user
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++)
+		if (!isLockedWearable(gAgentWearables.getViewerWearable(eType, idxWearable)))
+			return true;
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::hasLockedWearable(LLWearableType::EType eType) const
+{
+	// NOTE: we return TRUE if there is at least 1 non-removable wearable currently worn on this wearable type
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++)
+		if (isLockedWearable(gAgentWearables.getViewerWearable(eType, idxWearable)))
+			return true;
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::isLockedWearableExcept(const LLViewerWearable* pWearable, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedWearable(pWearable);
+
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	return (pWearable) && (isLockedWearableTypeExcept(pWearable->getType(), RLV_LOCK_REMOVE, idRlvObj));
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedWearableType(eType, eLock);
+
+	// Loop over every object that marked the specified wearable type eLock type locked and skip over anything owned by idRlvObj
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeRem.lower_bound(eType), 
+				endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (itWearableType->second != idRlvObj)
+				return true;
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), 
+				endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (itWearableType->second != idRlvObj)
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+void RlvWearableLocks::removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		RLV_ASSERT( m_WearableTypeRem.lower_bound(eType) != m_WearableTypeRem.upper_bound(eType) ); // The lock should always exist
+		for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeRem.lower_bound(eType), 
+				endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (idRlvObj == itWearableType->second)
+			{
+				m_WearableTypeRem.erase(itWearableType);
+				break;
+			}
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		RLV_ASSERT( m_WearableTypeAdd.lower_bound(eType) != m_WearableTypeAdd.upper_bound(eType) ); // The lock should always exist
+		for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), 
+				endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (idRlvObj == itWearableType->second)
+			{
+				m_WearableTypeAdd.erase(itWearableType);
+				break;
+			}
+		}
+	}
+}
+
+// ============================================================================
+// RlvFolderLocks member functions
+//
+
+class RlvLockedDescendentsCollector : public LLInventoryCollectFunctor
+{
+public:
+	RlvLockedDescendentsCollector(int eSourceTypeMask, RlvFolderLocks::ELockPermission ePermMask, ERlvLockMask eLockTypeMask) 
+		: m_eSourceTypeMask(eSourceTypeMask), m_ePermMask(ePermMask), m_eLockTypeMask(eLockTypeMask) {}
+	/*virtual*/ ~RlvLockedDescendentsCollector() {}
+	/*virtual*/ bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem)
+	{
+		return (pFolder) && (RlvFolderLocks::instance().isLockedFolderEntry(pFolder->getUUID(), m_eSourceTypeMask, m_ePermMask, m_eLockTypeMask));
+	}
+protected:
+	RlvFolderLocks::ELockPermission m_ePermMask;
+	int				m_eSourceTypeMask;
+	ERlvLockMask	m_eLockTypeMask;
+};
+
+// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+RlvFolderLocks::RlvFolderLocks()
+	: m_fLookupDirty(false), m_RootLockType(RLV_LOCK_NONE), m_cntLockAdd(0), m_cntLockRem(0)
+{
+	LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this));
+	RlvInventory::instance().addSharedRootIDChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this));
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+void RlvFolderLocks::addFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, 
+								   const LLUUID& idRlvObj, ERlvLockMask eLockType)
+{
+	// Sanity check - eLockType can be RLV_LOCK_ADD or RLV_LOCK_REMOVE but not both
+	RLV_ASSERT( (RLV_LOCK_ADD == eLockType) || (RLV_LOCK_REMOVE == eLockType) );
+
+	// NOTE: m_FolderXXX can contain duplicate folderlock_descr_t
+	m_FolderLocks.push_back(new folderlock_descr_t(idRlvObj, eLockType, lockSource, ePerm, eScope));
+
+	if (PERM_DENY == ePerm)
+	{
+		if (RLV_LOCK_REMOVE == eLockType)
+			m_cntLockRem++;
+		else if (RLV_LOCK_ADD == eLockType)
+			m_cntLockAdd++;
+	}
+
+	if (!m_AttachmentChangeConnection.connected())
+		m_AttachmentChangeConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this));
+	m_fLookupDirty = true;
+}
+
+// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+bool RlvFolderLocks::getLockedFolders(const folderlock_source_t& lockSource, LLInventoryModel::cat_array_t& lockFolders) const
+{
+	S32 cntFolders = lockFolders.size();
+	switch (lockSource.first)
+	{
+		case ST_ATTACHMENT:
+			{
+				RLV_ASSERT(typeid(LLUUID) == lockSource.second.type())
+				const LLViewerObject* pObj = gObjectList.findObject(boost::get<LLUUID>(lockSource.second));
+				if ( (pObj) && (pObj->isAttachment()) )
+				{
+					const LLViewerInventoryItem* pItem = gInventory.getItem(pObj->getAttachmentItemID());
+					if ( (pItem) && (RlvInventory::instance().isSharedFolder(pItem->getParentUUID())) )
+					{
+						LLViewerInventoryCategory* pItemFolder = gInventory.getCategory(pItem->getParentUUID());
+						if (pItemFolder)
+							lockFolders.push_back(pItemFolder);
+					}
+				}
+			}
+			break;
+		case ST_FOLDER:
+			{
+				RLV_ASSERT(typeid(LLUUID) == lockSource.second.type())
+				LLViewerInventoryCategory* pFolder = gInventory.getCategory(boost::get<LLUUID>(lockSource.second));
+				if (pFolder)
+					lockFolders.push_back(pFolder);
+			}
+			break;
+		case ST_ROOTFOLDER:
+			{
+				LLViewerInventoryCategory* pFolder = gInventory.getCategory(gInventory.getRootFolderID());
+				if (pFolder)
+					lockFolders.push_back(pFolder);
+			}
+			break;
+		case ST_SHAREDPATH:
+			{
+				RLV_ASSERT(typeid(std::string) == lockSource.second.type())
+				LLViewerInventoryCategory* pSharedFolder = RlvInventory::instance().getSharedFolder(boost::get<std::string>(lockSource.second));
+				if (pSharedFolder)
+					lockFolders.push_back(pSharedFolder);
+			}
+			break;
+		case ST_ATTACHMENTPOINT:
+		case ST_WEARABLETYPE:
+			{
+				RLV_ASSERT( ((ST_ATTACHMENTPOINT == lockSource.first) && (typeid(S32) == lockSource.second.type())) || 
+					        ((ST_WEARABLETYPE == lockSource.first) && (typeid(LLWearableType::EType) == lockSource.second.type())) );
+
+				uuid_vec_t idItems;
+				if (ST_ATTACHMENTPOINT == lockSource.first)
+					RlvCommandOptionGetPath::getItemIDs(RlvAttachPtLookup::getAttachPoint(boost::get<S32>(lockSource.second)), idItems);
+				else if (ST_WEARABLETYPE == lockSource.first)
+					RlvCommandOptionGetPath::getItemIDs(boost::get<LLWearableType::EType>(lockSource.second), idItems);
+
+				LLInventoryModel::cat_array_t itemFolders;
+				if (RlvInventory::instance().getPath(idItems, itemFolders))
+					lockFolders.insert(lockFolders.end(), itemFolders.begin(), itemFolders.end());
+			}
+			break;
+		default:
+			return false;
+	};
+	return cntFolders != lockFolders.size();
+}
+
+// Checked: 2011-11-26 (RLVa-1.5.4a) | Modified: RLVa-1.5.4a
+bool RlvFolderLocks::getLockedItems(const LLUUID& idFolder, LLInventoryModel::item_array_t& lockItems) const
+{
+	S32 cntItems = lockItems.size();
+
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	LLFindWearablesEx f(true, true);	// Collect all worn items
+	gInventory.collectDescendentsIf(idFolder, folders, items, FALSE, f);
+
+	// Generally several of the worn items will belong to the same folder so we'll cache the results of each lookup
+	std::map<LLUUID, bool> folderLookups; std::map<LLUUID, bool>::const_iterator itLookup;
+
+	bool fItemLocked = false;
+	for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++)
+	{
+		LLViewerInventoryItem* pItem = items.at(idxItem);
+		if (LLAssetType::AT_LINK == pItem->getActualType())
+			pItem = pItem->getLinkedItem();
+		if (!pItem)
+			continue;
+
+		// Check the actual item's parent folder
+		const LLUUID& idItemParent = RlvInventory::getFoldedParent(pItem->getParentUUID(), true);
+		if ((itLookup = folderLookups.find(idItemParent)) != folderLookups.end())
+		{
+			fItemLocked = itLookup->second;
+		}
+		else
+		{
+			fItemLocked = isLockedFolder(idItemParent, RLV_LOCK_REMOVE);
+			folderLookups.insert(std::pair<LLUUID, bool>(idItemParent, fItemLocked));
+		}
+
+		// Check the parent folders of any links to this item that exist under #RLV
+		if (!fItemLocked)
+		{
+			LLInventoryModel::item_array_t itemLinks;
+			LLInventoryModel::cat_array_t cats;
+			LLLinkedItemIDMatches f(pItem->getUUID());
+			gInventory.collectDescendentsIf(RlvInventory::instance().getSharedRootID(), cats, itemLinks, LLInventoryModel::EXCLUDE_TRASH, f);
+
+			for (LLInventoryModel::item_array_t::iterator itItemLink = itemLinks.begin(); 
+					(itItemLink < itemLinks.end()) && (!fItemLocked); ++itItemLink)
+			{
+				LLViewerInventoryItem* pItemLink = *itItemLink;
+
+				const LLUUID& idItemLinkParent = (pItemLink) ? RlvInventory::getFoldedParent(pItemLink->getParentUUID(), true) : LLUUID::null;
+				if ((itLookup = folderLookups.find(idItemLinkParent)) != folderLookups.end())
+				{
+					fItemLocked = itLookup->second;
+				}
+				else
+				{
+					fItemLocked = isLockedFolder(idItemLinkParent, RLV_LOCK_REMOVE);
+					folderLookups.insert(std::pair<LLUUID, bool>(idItemLinkParent, fItemLocked));
+				}
+			}
+		}
+
+		if (fItemLocked)
+			lockItems.push_back(pItem);
+	}
+
+	return cntItems != lockItems.size();
+}
+
+// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+bool RlvFolderLocks::hasLockedFolderDescendent(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, 
+											   ERlvLockMask eLockTypeMask, bool fCheckSelf) const
+{
+	if (!hasLockedFolder(eLockTypeMask))
+		return false;
+	if (m_fLookupDirty)
+		refreshLockedLookups();
+	if ( (fCheckSelf) && (isLockedFolderEntry(idFolder, eSourceTypeMask, ePermMask, RLV_LOCK_ANY)) )
+		return true;
+
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	RlvLockedDescendentsCollector f(eSourceTypeMask, ePermMask, eLockTypeMask);
+	gInventory.collectDescendentsIf(idFolder, folders, items, FALSE, f, false);
+	return !folders.empty();
+}
+
+// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+bool RlvFolderLocks::isLockedFolderEntry(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, ERlvLockMask eLockTypeMask) const
+{
+	for (folderlock_map_t::const_iterator itFolderLock = m_LockedFolderMap.lower_bound(idFolder), 
+			endFolderLock = m_LockedFolderMap.upper_bound(idFolder); itFolderLock != endFolderLock; ++itFolderLock)
+	{
+		const folderlock_descr_t* pLockDescr = itFolderLock->second;
+		if ( (pLockDescr->lockSource.first & eSourceTypeMask) && (pLockDescr->eLockPermission & ePermMask) && 
+			 (pLockDescr->eLockType & eLockTypeMask) )
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+bool RlvFolderLocks::isLockedFolder(LLUUID idFolder, ERlvLockMask eLockTypeMask, int eSourceTypeMask, folderlock_source_t* plockSource) const
+{
+	// Sanity check - if there are no folder locks then we don't have to actually do anything
+	if (!hasLockedFolder(eLockTypeMask))
+		return false;
+
+	// Folded folders will be locked if their "parent" is locked
+	idFolder = RlvInventory::getFoldedParent(idFolder, true);
+	if (idFolder.isNull())
+		return false;
+
+	if (m_fLookupDirty)
+		refreshLockedLookups();
+
+	// Walk up the folder tree and check if anything has 'idFolder' locked
+	std::list<LLUUID> idsRlvObjRem, idsRlvObjAdd; const LLUUID& idFolderRoot = gInventory.getRootFolderID(); LLUUID idFolderCur = idFolder;
+	while (idFolderRoot != idFolderCur)
+	{
+		// Iterate over any folder locks for 'idFolderCur'
+		for (folderlock_map_t::const_iterator itFolderLock = m_LockedFolderMap.lower_bound(idFolderCur), 
+				endFolderLock = m_LockedFolderMap.upper_bound(idFolderCur); itFolderLock != endFolderLock; ++itFolderLock)
+		{
+			const folderlock_descr_t* pLockDescr = itFolderLock->second;
+
+			// We can skip over the current lock if:
+			//   - the current lock type doesn't match eLockTypeMask
+			//   - it's a node lock and the current folder doesn't match
+			//   - we encountered a PERM_ALLOW lock from the current lock owner before which supercedes any subsequent locks
+			//   - the lock source type doesn't match the mask passed in eSourceTypeMask
+			ERlvLockMask eCurLockType = (ERlvLockMask)(pLockDescr->eLockType & eLockTypeMask);
+			std::list<LLUUID>* pidRlvObjList = (RLV_LOCK_REMOVE == eCurLockType) ? &idsRlvObjRem : &idsRlvObjAdd;
+			if ( (0 == eCurLockType) || ((SCOPE_NODE == pLockDescr->eLockScope) && (idFolder != idFolderCur)) ||
+				 (pidRlvObjList->end() != std::find(pidRlvObjList->begin(), pidRlvObjList->end(), pLockDescr->idRlvObj)) ||
+				 (0 == (pLockDescr->eLockType & eSourceTypeMask)) )
+			{
+				continue;
+			}
+
+			if (PERM_DENY == pLockDescr->eLockPermission)
+			{
+				if (plockSource)
+					*plockSource = pLockDescr->lockSource;
+				return true;									// Folder is explicitly denied, indicate locked folder to our caller
+			}
+			else if (PERM_ALLOW == pLockDescr->eLockPermission)
+			{
+				pidRlvObjList->push_back(pLockDescr->idRlvObj);	// Folder is explicitly allowed, save the owner so we can skip it from now on
+			}
+		}
+
+		// Move up to the folder tree
+		const LLViewerInventoryCategory* pParent = gInventory.getCategory(idFolderCur);
+		idFolderCur = (pParent) ? pParent->getParentUUID() : idFolderRoot;
+	}
+	// If we didn't encounter an explicit deny lock with no exception then the folder is locked if the entire inventory is locked down
+	return (m_RootLockType & eLockTypeMask) && (eSourceTypeMask & ST_ROOTFOLDER) && (idsRlvObjRem.empty()) && (idsRlvObjAdd.empty());
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0b) | Added: RLVa-1.3.0b
+void RlvFolderLocks::onNeedsLookupRefresh()
+{
+	// NOTE: when removeFolderLock() removes the last folder lock we still want to refresh everything so mind the conditional OR assignment
+	m_fLookupDirty |= !m_FolderLocks.empty();
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+void RlvFolderLocks::refreshLockedLookups() const
+{
+	//
+	// Refresh locked folders
+	//
+	m_RootLockType = RLV_LOCK_NONE;
+	m_LockedFolderMap.clear();
+	for (folderlock_list_t::const_iterator itFolderLock = m_FolderLocks.begin(); itFolderLock != m_FolderLocks.end(); ++itFolderLock)
+	{
+		const folderlock_descr_t* pLockDescr = *itFolderLock;
+
+		LLInventoryModel::cat_array_t lockedFolders; const LLUUID& idFolderRoot = gInventory.getRootFolderID();
+		if (getLockedFolders(pLockDescr->lockSource, lockedFolders))
+		{
+			for (S32 idxFolder = 0, cntFolder = lockedFolders.size(); idxFolder < cntFolder; idxFolder++)
+			{
+				const LLViewerInventoryCategory* pFolder = lockedFolders.at(idxFolder);
+				if (idFolderRoot != pFolder->getUUID())
+					m_LockedFolderMap.insert(std::pair<LLUUID, const folderlock_descr_t*>(pFolder->getUUID(), pLockDescr));
+				else if (SCOPE_SUBTREE == pLockDescr->eLockScope)
+					m_RootLockType |= (U32)pLockDescr->eLockType;
+			}
+		}
+	}
+	m_fLookupDirty = false;
+
+	//
+	// Refresh locked items (iterate over COF and filter out any items residing in a RLV_LOCK_REMOVE locked PERM_DENY folder)
+	//
+	m_LockedAttachmentRem.clear();
+	m_LockedWearableRem.clear();
+
+	LLInventoryModel::item_array_t lockedItems;
+	if (getLockedItems(LLAppearanceMgr::instance().getCOF(), lockedItems))
+	{
+		for (S32 idxItem = 0, cntItem = lockedItems.size(); idxItem < cntItem; idxItem++)
+		{
+			const LLViewerInventoryItem* pItem = lockedItems.at(idxItem);
+			switch (pItem->getType())
+			{
+				case LLAssetType::AT_BODYPART:
+				case LLAssetType::AT_CLOTHING:
+					m_LockedWearableRem.push_back(pItem->getLinkedUUID());
+					break;
+				case LLAssetType::AT_OBJECT:
+					m_LockedAttachmentRem.push_back(pItem->getLinkedUUID());
+					break;
+				default:
+					RLV_ASSERT(true);
+					break;
+			}
+		}
+	}
+
+	// Remove any duplicate items we may have picked up
+	std::sort(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end());
+	m_LockedAttachmentRem.erase(std::unique(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end()), m_LockedAttachmentRem.end());
+	std::sort(m_LockedWearableRem.begin(), m_LockedWearableRem.end());
+	m_LockedWearableRem.erase(std::unique(m_LockedWearableRem.begin(), m_LockedWearableRem.end()), m_LockedWearableRem.end());
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+void RlvFolderLocks::removeFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, 
+									  const LLUUID& idRlvObj, ERlvLockMask eLockType)
+{
+	// Sanity check - eLockType can be RLV_LOCK_ADD or RLV_LOCK_REMOVE but not both
+	RLV_ASSERT( (RLV_LOCK_ADD == eLockType) || (RLV_LOCK_REMOVE == eLockType) );
+
+	folderlock_descr_t lockDescr(idRlvObj, eLockType, lockSource, ePerm, eScope); RlvPredValuesEqual<folderlock_descr_t> f = { &lockDescr };
+	folderlock_list_t::iterator itFolderLock = std::find_if(m_FolderLocks.begin(), m_FolderLocks.end(), f);
+	RLV_ASSERT( m_FolderLocks.end() != itFolderLock  ); // The lock should always exist
+	if (m_FolderLocks.end() != itFolderLock)
+	{
+		delete *itFolderLock;
+		m_FolderLocks.erase(itFolderLock);
+
+		if (PERM_DENY == ePerm)
+		{
+			if (RLV_LOCK_REMOVE == eLockType)
+				m_cntLockRem--;
+			else if (RLV_LOCK_ADD == eLockType)
+				m_cntLockAdd--;
+		}
+		m_fLookupDirty = true;
+	}
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h
new file mode 100644
index 0000000000000000000000000000000000000000..61ab0acbb0a802b859dc57fd503b87cc3f5031fe
--- /dev/null
+++ b/indra/newview/rlvlocks.h
@@ -0,0 +1,711 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_LOCKS_H
+#define RLV_LOCKS_H
+
+#include "llagentwearables.h"
+#include "lleventtimer.h"
+#include "llvoavatarself.h"
+#include "llviewerwearable.h"
+
+#include "rlvdefines.h"
+#include "rlvcommon.h"
+
+// ============================================================================
+// RlvAttachPtLookup class declaration
+//
+
+class RlvAttachPtLookup
+{
+public:
+	static LLViewerJointAttachment* getAttachPoint(S32 idxAttachPt);
+	static LLViewerJointAttachment* getAttachPoint(const std::string& strText);
+	static LLViewerJointAttachment* getAttachPoint(const LLInventoryItem* pItem);
+
+	static S32 getAttachPointIndex(std::string strText);
+	static S32 getAttachPointIndex(const LLViewerObject* pAttachObj);
+	static S32 getAttachPointIndex(const LLViewerJointAttachment* pAttachPt);
+	static S32 getAttachPointIndex(const LLInventoryCategory* pFolder);
+	static S32 getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks = true);
+
+	static bool hasAttachPointName(const LLInventoryItem* pItem) { return (0 != getAttachPointIndex(pItem)); }
+private:
+	static S32 getAttachPointIndexLegacy(const LLInventoryCategory* pFolder);
+
+public:
+	static void initLookupTable();
+private:
+	static std::map<std::string, S32> m_AttachPtLookupMap;
+};
+
+// ============================================================================
+// RlvAttachmentLocks class declaration
+//
+
+// TODO-RLVa: [RLVa-1.2.1] Once everything is working for SL-2.0 thin out the member functions since a few of them are duplicates/unneeded
+class RlvAttachmentLocks
+{
+public:
+	RlvAttachmentLocks() : m_fHasLockedHUD(false) {}
+
+public:
+	// Adds an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment
+	void addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj);
+	// Adds an eLock type lock (held by idRlvObj) for the attachment point
+	void addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Returns TRUE if there is at least 1 non-detachable attachment currently attached to the attachment point
+	bool hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const;
+	// Returns TRUE if there is at least 1 eLock type locked attachment point (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE)
+	//   - RLV_LOCK_REMOVE: specific attachment locked *or* any attachment point locked (regardless of whether it currently has attachments)
+	bool hasLockedAttachmentPoint(ERlvLockMask eLock) const;
+	// Returns TRUE if there is at least 1 non-detachable HUD attachment
+	bool hasLockedHUD() const { return m_fHasLockedHUD; }
+
+	// Returns TRUE if the attachment is RLV_LOCK_REMOVE locked
+	bool isLockedAttachment(const LLViewerObject* pAttachObj) const;
+	// Returns TRUE if the attachment point is RLV_LOCK_REMOVE locked by anything other than idRlvObj
+	bool isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const;
+	// Returns TRUE if the attachment point is eLock type locked (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE)
+	bool isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const;
+	bool isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const;
+
+	// Removes an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment
+	void removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj);
+	// Removes an eLock type lock (held by idRlvObj) for the attachment point
+	void removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Refreshes locked HUD attachment state
+	void updateLockedHUD();
+	// Iterates over all current attachment and attachment point locks and verifies their status (returns TRUE if verification succeeded)
+	bool verifyAttachmentLocks();
+
+protected:
+	// Returns TRUE if the attachment point is eLock type locked by anything other than idRlvObj
+	bool isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const;
+
+	/*
+	 * canAttach/canDetach trivial helper functions (note that a more approriate name might be userCanAttach/userCanDetach)
+	 */
+public:
+	// Returns TRUE if there is at least one attachment point that can be attached to
+	bool         canAttach() const;
+	// Returns TRUE if the inventory item can be attached by the user (and optionally provides the attachment point - which may be NULL)
+	ERlvWearMask canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut = NULL) const;
+	// Returns TRUE if the attachment point can be attached to by the user
+	ERlvWearMask canAttach(const LLViewerJointAttachment* pAttachPt) const;
+
+	// Returns TRUE if the inventory item can be detached by the user
+	bool canDetach(const LLInventoryItem* pItem) const;
+	// Returns TRUE if the attachment point has at least one attachment that can be detached by the user
+	bool canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll = false) const;
+
+	/*
+	 * Member variables
+	 */
+public:
+	typedef std::multimap<LLUUID, LLUUID> rlv_attachobjlock_map_t;
+	typedef std::multimap<S32, LLUUID> rlv_attachptlock_map_t;
+	// Accessors for RlvFloaterLocks
+	const rlv_attachptlock_map_t& getAttachPtLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_AttachPtAdd : m_AttachPtRem; }
+	const rlv_attachobjlock_map_t& getAttachObjLocks() { return m_AttachObjRem; }
+private:
+	rlv_attachptlock_map_t	m_AttachPtAdd;		// Map of attachment points that can't be attached to (idxAttachPt -> idObj)
+	rlv_attachptlock_map_t	m_AttachPtRem;		// Map of attachment points whose attachments can't be detached (idxAttachPt -> idObj)
+	rlv_attachobjlock_map_t	m_AttachObjRem;		// Map of attachments that can't be detached (idAttachObj -> idObj)
+
+	bool m_fHasLockedHUD;
+};
+
+extern RlvAttachmentLocks gRlvAttachmentLocks;
+
+// ============================================================================
+// RlvAttachmentLockWatchdog - Self contained class that automagically takes care of enforcing attachment locks (ie reattach-on-detach)
+//
+
+// TODO-RLVa: [RLVa-1.2.1] This class really looks rather cluttered so look into cleaning it up/simplifying it a bit
+class RlvAttachmentLockWatchdog : public LLSingleton<RlvAttachmentLockWatchdog>
+{
+	friend class LLSingleton<RlvAttachmentLockWatchdog>;
+protected:
+	RlvAttachmentLockWatchdog() : m_pTimer(NULL) {}
+	~RlvAttachmentLockWatchdog() { delete m_pTimer; }
+
+	/*
+	 * Member functions
+	 */
+protected:
+	// NOTE: detach does *not* respect attachment locks so use with care
+	void detach(const LLViewerObject* pAttachObj);
+	void detach(S32 idxAttachPt) { uuid_vec_t idsAttachObjExcept; detach(idxAttachPt, idsAttachObjExcept); }
+	void detach(S32 idxAttachPt, const uuid_vec_t& idsAttachObjExcept);
+
+	void startTimer() { if (!m_pTimer) m_pTimer = new RlvAttachmentLockWatchdogTimer(this); }
+
+	/*
+	 * Event handlers
+	 */
+public:
+	void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	void onSavedAssetIntoInventory(const LLUUID& idItem);
+	BOOL onTimer();
+	void onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction);
+	void onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	typedef std::list<LLUUID> rlv_detach_map_t;
+	rlv_detach_map_t m_PendingDetach;
+
+	struct RlvReattachInfo
+	{
+		RlvReattachInfo(const LLUUID& itemid) : idItem(itemid), fAssetSaved(false), tsAttach(0) 
+			{ tsDetach = LLFrameTimer::getElapsedSeconds(); }
+
+		LLUUID idItem;
+		bool   fAssetSaved;
+		F64    tsDetach;
+		F64    tsAttach;
+	protected:
+		RlvReattachInfo();
+	};
+	typedef std::multimap<S32, RlvReattachInfo> rlv_attach_map_t;
+	rlv_attach_map_t m_PendingAttach;
+
+	struct RlvWearInfo
+	{
+		RlvWearInfo(const LLUUID& itemid, ERlvWearMask wearaction) : idItem(itemid), eWearAction(wearaction)
+			{ tsWear = LLFrameTimer::getElapsedSeconds(); }
+
+		bool isAddLockedAttachPt(S32 idxAttachPt) const;
+		void dumpInstance() const;
+
+		LLUUID       idItem;
+		ERlvWearMask eWearAction;
+		F64          tsWear;
+		std::map<S32, uuid_vec_t> attachPts;
+	protected:
+		RlvWearInfo();
+	};
+	typedef std::map<LLUUID, RlvWearInfo> rlv_wear_map_t;
+	rlv_wear_map_t m_PendingWear;
+
+	class RlvAttachmentLockWatchdogTimer : public LLEventTimer
+	{
+	public:
+		RlvAttachmentLockWatchdogTimer(RlvAttachmentLockWatchdog* pWatchdog) : LLEventTimer(10), m_pWatchdog(pWatchdog) {}
+		virtual ~RlvAttachmentLockWatchdogTimer() { m_pWatchdog->m_pTimer = NULL; }
+		virtual BOOL tick() { return m_pWatchdog->onTimer(); }
+		RlvAttachmentLockWatchdog* m_pWatchdog;
+	} *m_pTimer;
+};
+
+// ============================================================================
+// RlvWearableLocks class declaration - modelled on RlvAttachmentLocks (attach pt = wearable type - attachment = wearable)
+//
+
+class RlvWearableLocks
+{
+public:
+	// Adds an eLock type lock (held by idRlvObj) for the wearable type
+	void addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Returns TRUE if there is at least 1 non-removable wearable currently worn on this wearable type
+	bool hasLockedWearable(LLWearableType::EType eType) const;
+	// Returns TRUE if there is at least 1 eLock type locked wearable type (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE)
+	//   - RLV_LOCK_REMOVE: specific wearable locked *or* any wearable type locked (regardless of whether it currently has wearables)
+	bool hasLockedWearableType(ERlvLockMask eLock) const;
+
+	// Removes an eLock type lock (held by idRlvObj) for the wearable type
+	void removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Returns TRUE if the wearable is RLV_LOCK_REMOVE locked
+	bool isLockedWearable(const LLViewerWearable* pWearable) const;
+	// Returns TRUE if the wearable is RLV_LOCK_REMOVE locked by anything other than idRlvObj
+	bool isLockedWearableExcept(const LLViewerWearable* pWearable, const LLUUID& idRlvObj) const;
+
+	// NOTE: isLockedWearableType doesn't check if a worn wearable is a specific wearable lock so don't let these be called by the outside
+protected:
+	// Returns TRUE if the wearable type is eLock type locked
+	bool isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const;
+	// Returns TRUE if the wearable type is eLock type locked by anything other than idRlvObj
+	bool isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const;
+
+	/*
+	 * canWear/canRemove trivial helper functions (note that a more approriate name might be userCanWear/userCanRemove)
+	 */
+public:
+	// Returns whether the inventory item can be worn by the user
+	ERlvWearMask canWear(const LLViewerInventoryItem* pItem) const;
+	// Returns whether the wearable type can be worn to by the user
+	ERlvWearMask canWear(LLWearableType::EType eType) const;
+
+	// Returns TRUE if the inventory item can be removed by the user
+	bool canRemove(const LLInventoryItem* pItem) const;
+	// Returns TRUE if the wearable type has at least one wearable that can be removed by the user
+	bool canRemove(LLWearableType::EType eType) const;
+
+	/*
+	 * Member variables
+	 */
+public:
+	typedef std::multimap<LLWearableType::EType, LLUUID> rlv_wearabletypelock_map_t;
+	// Accessors for RlvFloaterLocks
+	const rlv_wearabletypelock_map_t& getWearableTypeLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_WearableTypeAdd : m_WearableTypeRem; }
+protected:
+	rlv_wearabletypelock_map_t m_WearableTypeAdd;
+	rlv_wearabletypelock_map_t m_WearableTypeRem;
+};
+
+extern RlvWearableLocks gRlvWearableLocks;
+
+// ============================================================================
+// RlvFolderLocks class declaration
+//
+
+class RlvFolderLocks : public LLSingleton<RlvFolderLocks>
+{
+	friend class RlvLockedDescendentsCollector;
+public:
+	RlvFolderLocks();
+
+	// Specifies the source of a folder lock
+	enum ELockSourceType
+	{ 
+		ST_ATTACHMENT = 0x01, ST_ATTACHMENTPOINT = 0x02, ST_FOLDER = 0x04, ST_ROOTFOLDER = 0x08,
+		ST_SHAREDPATH = 0x10, ST_WEARABLETYPE = 0x20, ST_NONE= 0x00, ST_MASK_ANY = 0xFF
+	};
+	typedef boost::variant<LLUUID, std::string, S32, LLWearableType::EType> lock_source_t;
+	typedef std::pair<ELockSourceType, lock_source_t> folderlock_source_t;
+	// Specifies options for the folder lock
+	enum ELockPermission { PERM_ALLOW = 0x1, PERM_DENY = 0x2, PERM_MASK_ANY = 0x3 };
+	enum ELockScope	{ SCOPE_NODE, SCOPE_SUBTREE } ;
+
+	struct folderlock_descr_t
+	{
+		LLUUID				idRlvObj;
+		ERlvLockMask		eLockType;
+		folderlock_source_t	lockSource;
+		ELockPermission		eLockPermission;
+		ELockScope			eLockScope;
+
+		folderlock_descr_t(const LLUUID& rlvObj, ERlvLockMask lockType, folderlock_source_t source, ELockPermission perm, ELockScope scope);
+		bool operator ==(const folderlock_descr_t& rhs) const;
+	};
+
+public:
+	// Adds an eLock type lock (held by idRlvObj) for the specified folder source (with ePerm and eScope lock options)
+	void addFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, const LLUUID& idRlvObj, ERlvLockMask eLockType);
+
+	// Returns TRUE if there is at least 1 non-detachable attachment as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock
+	bool hasLockedAttachment() const;
+	// Returns TRUE if there is at least 1 eLock type PERM_DENY locked folder (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE)
+	bool hasLockedFolder(ERlvLockMask eLockTypeMask) const;
+	// Returns TRUE if the folder has a descendent folder lock with the specified charateristics
+	bool hasLockedFolderDescendent(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, 
+	                               ERlvLockMask eLockTypeMask, bool fCheckSelf) const;
+	// Returns TRUE if there is at least 1 non-removable wearable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock
+	bool hasLockedWearable() const;
+	// Returns TRUE if the attachment (specified by item UUID) is non-detachable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock
+	bool isLockedAttachment(const LLUUID& idItem) const;
+	// Returns TRUE if the folder is locked as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock
+	bool isLockedFolder(LLUUID idFolder, ERlvLockMask eLock, int eSourceTypeMask = ST_MASK_ANY, folderlock_source_t* plockSource = NULL) const;
+	// Returns TRUE if the wearable (specified by item UUID) is non-removable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock
+	bool isLockedWearable(const LLUUID& idItem) const;
+
+	// Removes an eLock type lock (held by idRlvObj) for the specified folder source (with ePerm and eScope lock options)
+	void removeFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, const LLUUID& idRlvObj, ERlvLockMask eLockType);
+
+protected:
+	// Returns TRUE if the folder has an explicit folder lock entry with the specified charateristics
+	bool isLockedFolderEntry(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, ERlvLockMask eLockTypeMask) const;
+
+	/*
+	 * canXXX helper functions (note that a more approriate name might be userCanXXX)
+	 */
+public:
+	bool canMoveFolder(const LLUUID& idFolder, const LLUUID& idFolderDest) const;
+	bool canRemoveFolder(const LLUUID& idFolder) const;
+	bool canRenameFolder(const LLUUID& idFolder) const;
+	bool canMoveItem(const LLUUID& idItem, const LLUUID& idFolderDest) const;
+	bool canRemoveItem(const LLUUID& idItem) const;
+	bool canRenameItem(const LLUUID& idItem) const;
+
+	/*
+	 * Cached item/folder look-up helper functions
+	 */
+protected:
+	bool getLockedFolders(const folderlock_source_t& lockSource, LLInventoryModel::cat_array_t& lockFolders) const;
+	bool getLockedItems(const LLUUID& idFolder, LLInventoryModel::item_array_t& lockItems) const;
+	void onNeedsLookupRefresh();
+	void refreshLockedLookups() const;
+
+	/*
+	 * Member variables
+	 */
+public:
+	typedef std::list<const folderlock_descr_t*> folderlock_list_t;
+	// Accessors for RlvFloaterLocks
+	const folderlock_list_t& getFolderLocks() { return m_FolderLocks; }
+	const uuid_vec_t& getAttachmentLookups()  { return m_LockedAttachmentRem; }
+	const uuid_vec_t& getWearableLookups()    { return m_LockedWearableRem; }
+protected:
+	boost::signals2::connection m_AttachmentChangeConnection;
+
+	// Map of folder locks (idRlvObj -> lockDescr)
+	folderlock_list_t	m_FolderLocks;			// List of add and remove locked folder descriptions
+	S32					m_cntLockAdd;			// Number of RLV_LOCK_ADD locked folders in m_FolderLocks
+	S32					m_cntLockRem;			// Number of RLV_LOCK_REMOVE locked folders in m_FolderLocks
+
+	// Cached item look-up variables
+	typedef std::multimap<LLUUID, const folderlock_descr_t*> folderlock_map_t;
+	mutable bool             m_fLookupDirty;
+	mutable U32              m_RootLockType;
+	mutable uuid_vec_t       m_LockedAttachmentRem;
+	mutable folderlock_map_t m_LockedFolderMap;
+	mutable uuid_vec_t       m_LockedWearableRem;
+private:
+	friend class LLSingleton<RlvFolderLocks>;
+};
+
+// ============================================================================
+// RlvAttachPtLookup inlined member functions
+//
+
+// Checked: 2010-11-30 (RLVa-1.4.0b) | Added: RLVa-1.4.0b
+inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(S32 idxAttachPt)
+{
+	return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL) : NULL;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d
+inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const std::string& strText)
+{
+	return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(strText), (LLViewerJointAttachment*)NULL) : NULL;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b
+inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const LLInventoryItem* pItem)
+{
+	return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(pItem), (LLViewerJointAttachment*)NULL) : NULL;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline S32 RlvAttachPtLookup::getAttachPointIndex(std::string strText)
+{
+	LLStringUtil::toLower(strText);
+	RLV_ASSERT(m_AttachPtLookupMap.size() > 0);
+	std::map<std::string, S32>::const_iterator itAttachPt = m_AttachPtLookupMap.find(strText);
+	return (itAttachPt != m_AttachPtLookupMap.end()) ? itAttachPt->second : 0;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d
+inline S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerObject* pObj)
+{
+	return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0;
+}
+
+// ============================================================================
+// RlvAttachmentLocks inlined member functions
+//
+
+// Checked: 2011-05-22 (RLVa-1.3.1b) | Modified: RLVa-1.3.1b
+inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut /*=NULL*/) const
+{
+	// The specified item can be attached if:
+	//   - it doesn't specify an attachment point and there is at least one attachment point that can be attached to
+	//   - the attachment point it specifies can be attached to
+	LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(pItem);
+	if (ppAttachPtOut)
+		*ppAttachPtOut = pAttachPt;
+	return ((canAttach()) && (pItem) && (!RlvFolderLocks::instance().isLockedFolder(pItem->getParentUUID(), RLV_LOCK_ADD)))
+		? ((!pAttachPt) ? RLV_WEAR : canAttach(pAttachPt)) : RLV_WEAR_LOCKED;
+}
+
+// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLViewerJointAttachment* pAttachPt) const
+{
+	// Non-attachable attachment point  => RLV_WEAR_LOCKED
+	// One or more locked attachment(s) => RLV_WEAR_ADD
+	// Unlocked attachment(s)           => RLV_WEAR_ADD | RLV_WEAR_REPLACE
+	// Empty attachment point           => RLV_WEAR_ADD | RLV_WEAR_REPLACE
+	RLV_ASSERT(pAttachPt);	// TODO-RLVa: [RLVa-1.2.1] Maybe it's better to just return something similar like above?
+	return 
+		(ERlvWearMask)(((pAttachPt) && (!isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD))) 
+			? ((canDetach(pAttachPt, true)) ? RLV_WEAR_REPLACE : 0) | RLV_WEAR_ADD
+			: RLV_WEAR_LOCKED);
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0)
+inline bool RlvAttachmentLocks::canDetach(const LLInventoryItem* pItem) const
+{
+	const LLViewerObject* pAttachObj = 
+		((pItem) && (isAgentAvatarValid())) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL;
+	return (!pAttachObj) || (!isLockedAttachment(pAttachObj));
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b
+inline bool RlvAttachmentLocks::hasLockedAttachmentPoint(ERlvLockMask eLock) const
+{
+	// Remove locks are more common so check those first
+	return
+		((eLock & RLV_LOCK_REMOVE) && ((!m_AttachPtRem.empty()) || (!m_AttachObjRem.empty()) || (RlvFolderLocks::instance().hasLockedAttachment()))) || 
+		((eLock & RLV_LOCK_ADD) && (!m_AttachPtAdd.empty()) );
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b
+inline bool RlvAttachmentLocks::isLockedAttachment(const LLViewerObject* pAttachObj) const
+{
+	// If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem
+	RLV_ASSERT( (!pAttachObj) || (pAttachObj == pAttachObj->getRootEdit()) );
+
+	// Object is locked if:
+	//   - it's specifically marked as non-detachable (ie @detach=n)
+	//   - it's attached to an attachment point that is RLV_LOCK_REMOVE locked (ie @remattach:<attachpt>=n)
+	//   - it's part of a locked folder
+	return 
+		(pAttachObj) && (pAttachObj->isAttachment()) &&
+		( (m_AttachObjRem.find(pAttachObj->getID()) != m_AttachObjRem.end()) ||
+		  (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pAttachObj), RLV_LOCK_REMOVE)) ||
+		  ((!pAttachObj->isTempAttachment()) && (RlvFolderLocks::instance().isLockedAttachment(pAttachObj->getAttachmentItemID()))) );
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.0.5a
+inline bool RlvAttachmentLocks::isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const
+{
+	return
+		( (eLock & RLV_LOCK_REMOVE) && (m_AttachPtRem.find(idxAttachPt) != m_AttachPtRem.end()) ) ||
+		( (eLock & RLV_LOCK_ADD) && (m_AttachPtAdd.find(idxAttachPt) != m_AttachPtAdd.end()) );
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline bool RlvAttachmentLocks::isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const
+{
+	return (pAttachPt) && (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pAttachPt), eLock));
+}
+
+// ============================================================================
+// RlvWearableLocks inlined member functions
+//
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+inline bool RlvWearableLocks::canRemove(const LLInventoryItem* pItem) const
+{
+	// The specified item can be removed if its wearable can be removed
+	RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) );
+	const LLViewerWearable* pWearable = (pItem) ? gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID()) : NULL;
+	return (pWearable) && (!isLockedWearable(pWearable));
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+inline ERlvWearMask RlvWearableLocks::canWear(const LLViewerInventoryItem* pItem) const
+{
+	// The specified item can be worn if the wearable type it specifies can be worn on
+	RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) );
+	return ((pItem) && (!RlvFolderLocks::instance().isLockedFolder(pItem->getParentUUID(), RLV_LOCK_ADD))) 
+		? canWear(pItem->getWearableType()) : RLV_WEAR_LOCKED;
+}
+
+// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+inline ERlvWearMask RlvWearableLocks::canWear(LLWearableType::EType eType) const
+{
+	// The specified wearable type can be worn on if:
+	//   - the wearable type itself isn't RLV_LOCK_ADD locked => RLV_WEAR_ADD
+	//     (and there are less than the maximum amount currently worn)
+	//   - it doesn't have any non-removable wearables        => RLV_WEAR_REPLACE | RLV_WEAR_ADD = RLV_WEAR
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	return (!isLockedWearableType(eType, RLV_LOCK_ADD))
+	  ? ((!hasLockedWearable(eType)) 
+			? RLV_WEAR 
+			: (gAgentWearables.canAddWearable(eType)) ? RLV_WEAR_ADD : RLV_WEAR_LOCKED)
+	  : RLV_WEAR_LOCKED;
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+inline bool RlvWearableLocks::hasLockedWearableType(ERlvLockMask eLock) const
+{
+	// Remove locks are more common so check those first
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	return ( (eLock & RLV_LOCK_REMOVE) && (!m_WearableTypeRem.empty()) ) || ( (eLock & RLV_LOCK_ADD) && (!m_WearableTypeAdd.empty()) );
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.2.0a
+inline bool RlvWearableLocks::isLockedWearable(const LLViewerWearable* pWearable) const
+{
+	// Wearable is locked if:
+	//   - it's specifically marked as non-removable
+	//   - it's worn on a wearable type that is RLV_LOCK_REMOVE locked
+	//   - it's part of a locked folder
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	RLV_ASSERT(pWearable);
+	return 
+		(pWearable) &&
+		( (isLockedWearableType(pWearable->getType(), RLV_LOCK_REMOVE)) || (RlvFolderLocks::instance().isLockedWearable(pWearable->getItemID())) );
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+inline bool RlvWearableLocks::isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const
+{
+	return
+		( (eLock & RLV_LOCK_REMOVE) && (m_WearableTypeRem.find(eType) != m_WearableTypeRem.end()) ) ||
+		( (eLock & RLV_LOCK_ADD) && (m_WearableTypeAdd.find(eType) != m_WearableTypeAdd.end()) );
+}
+
+// ============================================================================
+// RlvAttachmentLockWatchdog inlined member functions
+//
+
+// Checked: 2010-08-07 (RLVa-1.2.0i) | Added: RLVa-1.2.0i
+inline void RlvAttachmentLockWatchdog::onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction)
+{
+	onWearAttachment(pItem->getLinkedUUID(), eWearAction);
+}
+
+// ============================================================================
+// RlvFolderLocks member functions
+//
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline RlvFolderLocks::folderlock_descr_t::folderlock_descr_t(const LLUUID& rlvObj, ERlvLockMask lockType, folderlock_source_t source, 
+															  ELockPermission perm, ELockScope scope)
+	: idRlvObj(rlvObj), eLockType(lockType), lockSource(source), eLockPermission(perm), eLockScope(scope)
+{
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline bool RlvFolderLocks::folderlock_descr_t::operator ==(const folderlock_descr_t& rhs) const
+{
+	return (idRlvObj == rhs.idRlvObj) && (eLockType == rhs.eLockType) && (lockSource == rhs.lockSource) && 
+		(eLockPermission == rhs.eLockPermission) && (eLockScope == rhs.eLockScope);
+}
+
+// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline bool RlvFolderLocks::canMoveFolder(const LLUUID& idFolder, const LLUUID& idFolderDest) const
+{
+	// Block moving the folder to destination if:
+	//   - the folder (or one of its descendents) is explicitly locked
+	//   - folder and destination are subject to different locks
+	//		-> Possible combinations:
+	//			* folder   locked + destination unlocked => block move
+	//			* folder unlocked + destination   locked => block move
+	//			* folder   locked + destination   locked => allow move only if both are subject to the same folder lock
+	//			* folder unlocked + destination unlocked => allow move (special case of above since both locks are equal when there is none)
+	//		=> so the above becomes (isLockedFolder(A) == isLockedFolder(B)) && (lockA == lockB)
+	folderlock_source_t lockSource(ST_NONE, 0), lockSourceDest(ST_NONE, 0);
+	return 
+		(!hasLockedFolderDescendent(idFolder, ST_MASK_ANY, PERM_MASK_ANY, RLV_LOCK_ANY, true)) &&
+		( (isLockedFolder(idFolder, RLV_LOCK_ANY, ST_MASK_ANY, &lockSource) == isLockedFolder(idFolderDest, RLV_LOCK_ANY, ST_MASK_ANY, &lockSourceDest)) && 
+		  (lockSource == lockSourceDest) );
+}
+
+// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline bool RlvFolderLocks::canRemoveFolder(const LLUUID& idFolder) const
+{
+	// Block removing a folder if:
+	//   - the folder (or one of its descendents) is explicitly locked
+	//   - the folder itself is locked (but disregard root folder locks)
+	return 
+		(!hasLockedFolderDescendent(idFolder, ST_MASK_ANY, PERM_MASK_ANY, RLV_LOCK_ANY, true)) && 
+		(!isLockedFolder(idFolder, RLV_LOCK_ANY, ST_MASK_ANY & ~ST_ROOTFOLDER));
+}
+
+// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline bool RlvFolderLocks::canRenameFolder(const LLUUID& idFolder) const
+{
+	// Block renaming a folder if:
+	//   - the folder (or one of its descendents) is explicitly locked by:
+	//		-> a "shared path" => renaming the folder would change the shared path and hence invalidate the lock
+	//		-> an attachment point -|
+	//		-> an attachment        |--> renaming the folder to a "dot" (=invisible) folder would invalidate the lock
+	//		-> a wearable type     -|
+	return !hasLockedFolderDescendent(idFolder, ST_SHAREDPATH | ST_ATTACHMENT | ST_ATTACHMENTPOINT | ST_WEARABLETYPE, PERM_MASK_ANY, RLV_LOCK_ANY, true);
+}
+
+// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline bool RlvFolderLocks::canMoveItem(const LLUUID& idItem, const LLUUID& idFolderDest) const
+{
+	// Block moving the folder to destination if:
+	//   - folder and destination are subject to different locks [see canMoveFolder() for more details]
+	const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); const LLUUID& idFolder = (pItem) ? pItem->getParentUUID() : LLUUID::null;
+	int maskSource = ST_MASK_ANY & ~ST_ROOTFOLDER; folderlock_source_t lockSource(ST_NONE, 0), lockSourceDest(ST_NONE, 0);
+	return 
+		(idFolder.notNull()) && 
+		(isLockedFolder(idFolder, RLV_LOCK_ANY, maskSource, &lockSource) == isLockedFolder(idFolderDest, RLV_LOCK_ANY, maskSource, &lockSourceDest)) && 
+		(lockSource == lockSourceDest);
+}
+
+// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline bool RlvFolderLocks::canRemoveItem(const LLUUID& idItem) const
+{
+	// Block removing items from locked folders (but disregard root folder locks)
+	const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); const LLUUID& idFolder = (pItem) ? pItem->getParentUUID() : LLUUID::null;
+	int maskSource = ST_MASK_ANY & ~ST_ROOTFOLDER;
+	return (idFolder.notNull()) && (!isLockedFolder(idFolder, RLV_LOCK_ANY, maskSource));
+}
+
+// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g
+inline bool RlvFolderLocks::canRenameItem(const LLUUID& idItem) const
+{
+	// Items can always be renamed, regardless of folder locks
+	return true;
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b
+inline bool RlvFolderLocks::hasLockedAttachment() const
+{
+	if (m_fLookupDirty)
+		refreshLockedLookups();
+	return !m_LockedAttachmentRem.empty();
+}
+
+// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g
+inline bool RlvFolderLocks::hasLockedFolder(ERlvLockMask eLock) const
+{
+	// Remove locks are more common so check those first
+	return ((eLock & RLV_LOCK_REMOVE) && (m_cntLockRem)) || ((eLock & RLV_LOCK_ADD) && (m_cntLockAdd));
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b
+inline bool RlvFolderLocks::hasLockedWearable() const
+{
+	if (m_fLookupDirty)
+		refreshLockedLookups();
+	return !m_LockedWearableRem.empty();
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b
+inline bool RlvFolderLocks::isLockedAttachment(const LLUUID& idItem) const
+{
+	if (m_fLookupDirty)
+		refreshLockedLookups();
+	return (std::find(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end(), idItem) != m_LockedAttachmentRem.end());
+}
+
+// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b
+inline bool RlvFolderLocks::isLockedWearable(const LLUUID& idItem) const
+{
+	if (m_fLookupDirty)
+		refreshLockedLookups();
+	return (std::find(m_LockedWearableRem.begin(), m_LockedWearableRem.end(), idItem) != m_LockedWearableRem.end());
+}
+
+// ============================================================================
+
+#endif // RLV_LOCKS_H
diff --git a/indra/newview/rlvui.cpp b/indra/newview/rlvui.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..01d01a061d785471be359dd2d0527f28c917a8b9
--- /dev/null
+++ b/indra/newview/rlvui.cpp
@@ -0,0 +1,441 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llavataractions.h"			// LLAvatarActions::profileVisible()
+#include "llfloatersidepanelcontainer.h"
+#include "llhudtext.h"					// LLHUDText::refreshAllObjectText()
+#include "llimview.h"					// LLIMMgr::computeSessionID()
+#include "llmoveview.h"					// Movement panel (contains "Stand" and "Stop Flying" buttons)
+#include "llnavigationbar.h"			// Navigation bar
+#include "llparcel.h"
+#include "llpaneltopinfobar.h"
+#include "llteleporthistory.h"
+#include "lltoolmgr.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llvoavatar.h"
+#include "roles_constants.h"			// Group "powers"
+
+#include "rlvui.h"
+#include "rlvhandler.h"
+#include "rlvextensions.h"
+
+// ============================================================================
+
+// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+RlvUIEnabler::RlvUIEnabler()
+{
+	// Connect us to the behaviour toggle signal
+	gRlvHandler.setBehaviourToggleCallback(boost::bind(&RlvUIEnabler::onBehaviourToggle, this, _1, _2));
+
+	// onRefreshHoverText()
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTALL, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTWORLD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTHUD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+
+	// onToggleMovement
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_FLY, boost::bind(&RlvUIEnabler::onToggleMovement, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_ALWAYSRUN, boost::bind(&RlvUIEnabler::onToggleMovement, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TEMPRUN, boost::bind(&RlvUIEnabler::onToggleMovement, this)));
+
+	// onToggleViewXXX
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWNOTE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWSCRIPT, boost::bind(&RlvUIEnabler::onToggleViewXXX, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWTEXTURE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this)));
+
+	// onToggleXXX
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onToggleShowLoc, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWMINIMAP, boost::bind(&RlvUIEnabler::onToggleShowMinimap, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWWORLDMAP, boost::bind(&RlvUIEnabler::onToggleShowWorldMap, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onToggleUnsit, this)));
+
+	// onToggleTp
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onToggleTp, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLM, boost::bind(&RlvUIEnabler::onToggleTp, this)));
+
+	// onUpdateLoginLastLocation
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this, _1)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this, _1)));
+}
+
+// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onBehaviourToggle(ERlvBehaviour eBhvr, ERlvParamType eType)
+{
+	bool fQuitting = LLApp::isQuitting();
+	for (behaviour_handler_map_t::const_iterator itHandler = m_Handlers.lower_bound(eBhvr), endHandler = m_Handlers.upper_bound(eBhvr);
+			itHandler != endHandler; ++itHandler)
+	{
+		itHandler->second(fQuitting);
+	}
+}
+
+// ============================================================================
+
+// Checked: 2010-03-02 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onRefreshHoverText()
+{
+	// Refresh all hover text each time any of the monitored behaviours get set or unset
+	LLHUDText::refreshAllObjectText();
+}
+
+// Checked: 2010-03-02 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
+void RlvUIEnabler::onToggleMovement()
+{
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) && (gAgent.getFlying()) )
+		gAgent.setFlying(FALSE);
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_ALWAYSRUN)) && (gAgent.getAlwaysRun()) )
+		gAgent.clearAlwaysRun();
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_TEMPRUN)) && (gAgent.getTempRun()) )
+		gAgent.clearTempRun();
+
+	// Force an update since the status only updates when the current parcel changes [see LLFloaterMove::postBuild()]
+	LLFloaterMove::sUpdateMovementStatus();
+}
+
+// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+void RlvUIEnabler::onToggleShowLoc()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+
+	if (LLNavigationBar::instanceExists())
+		LLNavigationBar::instance().refreshLocationCtrl();
+	if (LLPanelTopInfoBar::instanceExists())
+		LLPanelTopInfoBar::instance().update();
+
+	if (!fEnable)
+	{
+		// Hide the "About Land" floater if it's currently visible
+		if (LLFloaterReg::instanceVisible("about_land"))
+			LLFloaterReg::hideInstance("about_land");
+		// Hide the "Region / Estate" floater if it's currently visible
+		if (LLFloaterReg::instanceVisible("region_info"))
+			LLFloaterReg::hideInstance("region_info");
+		// Hide the "God Tools" floater if it's currently visible
+		if (LLFloaterReg::instanceVisible("god_tools"))
+			LLFloaterReg::hideInstance("god_tools");
+
+		//
+		// Manipulate the teleport history
+		//
+
+		// If the last entry in the persistent teleport history matches the current teleport history entry then we should remove it
+		LLTeleportHistory* pTpHistory = LLTeleportHistory::getInstance();
+		LLTeleportHistoryStorage* pTpHistoryStg = LLTeleportHistoryStorage::getInstance();
+		RLV_ASSERT( (pTpHistory) && (pTpHistoryStg) && (pTpHistory->getItems().size() > 0) && (pTpHistory->getCurrentItemIndex() >= 0) );
+		if ( (pTpHistory) && (pTpHistory->getItems().size() > 0) && (pTpHistory->getCurrentItemIndex() >= 0) &&
+			 (pTpHistoryStg) && (pTpHistory->getItems().size() > 0) )
+		{
+			const LLTeleportHistoryItem& tpItem = pTpHistory->getItems().back();
+			const LLTeleportHistoryPersistentItem& tpItemStg = pTpHistoryStg->getItems().back();
+			if (pTpHistoryStg->compareByTitleAndGlobalPos(tpItemStg, LLTeleportHistoryPersistentItem(tpItem.mTitle, tpItem.mGlobalPos)))
+			{
+				// TODO-RLVa: [RLVa-1.2.2] Is there a reason why LLTeleportHistoryStorage::removeItem() doesn't trigger history changed?
+				pTpHistoryStg->removeItem(pTpHistoryStg->getItems().size() - 1);
+				pTpHistoryStg->mHistoryChangedSignal(-1);
+			}
+		}
+
+		// Clear the current location in the teleport history
+		if (pTpHistory)
+			pTpHistory->updateCurrentLocation(gAgent.getPositionGlobal());
+	}
+	else
+	{
+		// Reset the current location in the teleport history (also takes care of adding it to the persistent teleport history)
+		LLTeleportHistory* pTpHistory = LLTeleportHistory::getInstance();
+		if ( (pTpHistory) && (NULL != gAgent.getRegion()) )
+			pTpHistory->updateCurrentLocation(gAgent.getPositionGlobal());
+	}
+
+	// Start or stop filtering the "About Land" and "Region / Estate" floaters
+	if ( (!fEnable) && (!m_ConnFloaterShowLoc.connected()) )
+	{
+		m_ConnFloaterShowLoc = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterShowLoc, this, _1, _2));
+		m_ConnPanelShowLoc = LLFloaterSidePanelContainer::setValidateCallback(boost::bind(&RlvUIEnabler::filterPanelShowLoc, this, _1, _2, _3));
+	}
+	else if ( (fEnable) && (m_ConnFloaterShowLoc.connected()) )
+	{
+		m_ConnFloaterShowLoc.disconnect();
+		m_ConnPanelShowLoc.disconnect();
+	}
+}
+
+// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleShowMinimap()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP);
+
+	// Start or stop filtering showing the mini-map floater
+	if (!fEnable)
+		addGenericFloaterFilter("mini_map");
+	else
+		removeGenericFloaterFilter("mini_map");
+
+	// Hide the mini-map floater if it's currently visible (or restore it if it was previously visible)
+	static bool fPrevVisibile = false;
+	if ( (!fEnable) && ((fPrevVisibile = LLFloaterReg::instanceVisible("mini_map"))) )
+		LLFloaterReg::hideInstance("mini_map");
+	else if ( (fEnable) && (fPrevVisibile) )
+		LLFloaterReg::showInstance("mini_map");
+
+	// Break/reestablish the visibility connection for the nearby people panel embedded minimap instance
+	LLPanel* pPeoplePanel = LLFloaterSidePanelContainer::getPanel("people", "panel_people");
+	LLPanel* pNetMapPanel = (pPeoplePanel) ? pPeoplePanel->findChild<LLPanel>("Net Map Panel", TRUE) : NULL;
+	RLV_ASSERT( (pPeoplePanel) && (pNetMapPanel) );
+	if (pNetMapPanel)
+	{
+		pNetMapPanel->setMakeVisibleControlVariable( (fEnable) ? gSavedSettings.getControl("NearbyListShowMap").get() : NULL);
+		// Reestablishing the visiblity connection will show the panel if needed so we only need to take care of hiding it when needed
+		if ( (!fEnable) && (pNetMapPanel->getVisible()) )
+			pNetMapPanel->setVisible(false);
+	}
+}
+
+// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleShowWorldMap()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP);
+
+	// Hide the world map if it's currently visible
+	if ( (!fEnable) && (LLFloaterReg::instanceVisible("world_map")) )
+		LLFloaterReg::hideInstance("world_map");
+
+	// Start or stop filtering opening the world map
+	if (!fEnable)
+		addGenericFloaterFilter("world_map");
+	else
+		removeGenericFloaterFilter("world_map");
+}
+
+// Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+void RlvUIEnabler::onToggleTp()
+{
+	// Disable the navigation bar "Home" button if both @tplm=n *and* @tploc=n restricted
+	LLButton* pNavBarHomeBtn = LLNavigationBar::getInstance()->findChild<LLButton>("home_btn");
+	RLV_ASSERT(pNavBarHomeBtn);
+	if (pNavBarHomeBtn)
+		pNavBarHomeBtn->setEnabled(!(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
+}
+
+// Checked: 2010-03-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleUnsit()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT);
+
+	LLPanelStandStopFlying* pPanelStand = LLPanelStandStopFlying::getInstance();
+	RLV_ASSERT(pPanelStand);
+	if (pPanelStand)
+	{
+		LLButton* pBtnStand = pPanelStand->findChild<LLButton>("stand_btn");
+		RLV_ASSERT(pBtnStand);
+		if (pBtnStand)
+			pBtnStand->setEnabled(fEnable);
+	}
+}
+
+// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleViewXXX()
+{
+	// If any of the three are still active then we keep filtering
+	bool fHasViewXXX = (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) ||
+		(gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE));
+
+	// Start or stop filtering opening the preview floaters
+	if ( (fHasViewXXX) && (!m_ConnFloaterViewXXX.connected()) )
+		m_ConnFloaterViewXXX = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterViewXXX, this, _1, _2));
+	else if ( (!fHasViewXXX) && (m_ConnFloaterViewXXX.connected()) )
+		m_ConnFloaterViewXXX.disconnect();
+}
+
+// Checked: 2010-04-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0c
+void RlvUIEnabler::onUpdateLoginLastLocation(bool fQuitting)
+{
+	if (!fQuitting)
+		RlvSettings::updateLoginLastLocation();
+}
+
+// ============================================================================
+
+// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName)
+{
+	m_FilteredFloaters.insert(strFloaterName);
+
+	if (!m_ConnFloaterGeneric.connected())
+		m_ConnFloaterGeneric = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterGeneric, this, _1, _2));
+}
+
+// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::removeGenericFloaterFilter(const std::string& strFloaterName)
+{
+	std::multiset<std::string>::iterator itFloater = m_FilteredFloaters.find(strFloaterName);
+	RLV_ASSERT_DBG(itFloater != m_FilteredFloaters.end());
+	m_FilteredFloaters.erase(itFloater);
+
+	RLV_ASSERT_DBG(m_ConnFloaterGeneric.connected());
+	if (m_FilteredFloaters.empty())
+		m_ConnFloaterGeneric.disconnect();
+}
+
+// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
+bool RlvUIEnabler::filterFloaterGeneric(const std::string& strName, const LLSD&)
+{
+	return m_FilteredFloaters.end() == m_FilteredFloaters.find(strName);
+}
+
+// Checked: 2010-04-22 (RLVa-1.4.5) | Added: RLVa-1.2.0
+bool RlvUIEnabler::filterFloaterShowLoc(const std::string& strName, const LLSD&)
+{
+	if ("about_land" == strName)
+		return canViewParcelProperties();
+	else if ("region_info" == strName)
+		return canViewRegionProperties();
+	else if ("god_tools" == strName)
+		return false;
+	return true;
+}
+
+// Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
+bool RlvUIEnabler::filterPanelShowLoc(const std::string& strFloater, const std::string&, const LLSD& sdKey)
+{
+	if ("places" == strFloater)
+	{
+		const std::string strType = sdKey["type"].asString();
+		if ("create_landmark" == strType)
+			return false;
+		else if ("agent" == strType)
+			return canViewParcelProperties();
+	}
+	return true;
+}
+
+// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+bool RlvUIEnabler::filterFloaterViewXXX(const std::string& strName, const LLSD&)
+{
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) && ("preview_notecard" == strName) )
+	{
+		RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD);
+		return false;
+	}
+	else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) && (("preview_script" == strName) || ("preview_scriptedit" == strName)) )
+	{
+		RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT);
+		return false;
+	}
+	else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)) && ("preview_texture" == strName) )
+	{
+		RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_TEXTURE);
+		return false;
+	}
+	return true;
+}
+
+// ============================================================================
+
+// Checked: 2012-02-09 (RLVa-1.4.5) | Modified: RLVa-1.4.5
+bool RlvUIEnabler::canViewParcelProperties()
+{
+	// We'll allow "About Land" as long as the user has the ability to return prims (through ownership or through group powers)
+	bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		// RELEASE-RLVa: [SL-3.2] Check that opening the "About Land" floater still sets focus to the current parcel is none is selected
+		const LLParcel* pParcel = NULL;
+		if (LLViewerParcelMgr::getInstance()->selectionEmpty())
+		{
+			pParcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+		}
+		else
+		{
+			LLParcelSelection* pParcelSel = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection();
+			if (pParcelSel->hasOthersSelected())
+				return false;
+			pParcel = pParcelSel->getParcel();
+		}
+
+		// Ideally we could just use LLViewerParcelMgr::isParcelOwnedByAgent(), but that has that sneaky exemption for "god-like"
+		if (pParcel)
+		{
+			const LLUUID& idOwner = pParcel->getOwnerID();
+			if ( (idOwner != gAgent.getID()) )
+			{
+				S32 count = gAgent.mGroups.size();
+				for (S32 i = 0; i < count; ++i)
+				{
+					if (gAgent.mGroups.at(i).mID == idOwner)
+					{
+						fShow = ((gAgent.mGroups.at(i).mPowers & GP_LAND_RETURN) > 0);
+						break;
+					}
+				}
+			}
+			else
+			{
+				fShow = true;
+			}
+		}
+	}
+	return fShow;
+}
+
+// Checked: 2010-04-20 (RLVa-1.4.5) | Modified: RLVa-1.2.0
+bool RlvUIEnabler::canViewRegionProperties()
+{
+	// We'll allow "Region / Estate" if the user is either the region owner or an estate manager
+	bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		// [See LLRegion::canManageEstate() but without the "god-like" exception]
+		const LLViewerRegion* pRegion = gAgent.getRegion();
+		if (pRegion)
+			fShow = (pRegion->isEstateManager()) || (pRegion->getOwner() == gAgent.getID());
+	}
+	return fShow;
+}
+
+// Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+bool RlvUIEnabler::hasOpenIM(const LLUUID& idAgent)
+{
+	LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent);
+	return (NULL != LLFloaterReg::findInstance("impanel", idSession));
+}
+
+// Checked: 2011-11-04 (RLVa-1.4.4a) | Modified: RLVa-1.4.4a
+bool RlvUIEnabler::hasOpenProfile(const LLUUID& idAgent)
+{
+	//   -> SL-2.1.0 added the ability to "share" inventory by dropping it on the avatar picker floater so we should check for that
+	//   -> we can drag/drop inventory onto calling cards but probably noone knows about it and it would be too involved to check for that
+	// TODO-RLVa: [RLVa-1.2.1] Check the avatar picker as well
+
+	// Check if the user has the specified agent's profile open
+	return LLAvatarActions::profileVisible(idAgent);
+}
+
+// Checked: 2010-09-11 (RLVa-1.2.1d) | Added: RLVa-1.2.1d
+bool RlvUIEnabler::isBuildEnabled()
+{
+	return (gAgent.canEditParcel()) && ((!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)));
+}
+
+bool RlvUIEnabler::isBuildEnabledOrActive()
+{
+	return LLToolMgr::instance().inEdit() || isBuildEnabled();
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvui.h b/indra/newview/rlvui.h
new file mode 100644
index 0000000000000000000000000000000000000000..841904a86096138640d8167bca7e2539637869b6
--- /dev/null
+++ b/indra/newview/rlvui.h
@@ -0,0 +1,98 @@
+/** 
+ *
+ * Copyright (c) 2009-2011, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_UI_H
+#define RLV_UI_H
+
+#include "llfloaterreg.h"
+#include "llsingleton.h"
+
+#include "rlvdefines.h"
+
+// ============================================================================
+// RlvUIEnabler - self-contained class that handles disabling or reenabling certain aspects of the viewer's UI
+//
+
+class RlvUIEnabler : public LLSingleton<RlvUIEnabler>
+{
+protected:
+	RlvUIEnabler();
+	friend class LLSingleton<RlvUIEnabler>;
+	friend class RlvHandler;
+
+	/*
+	 * Signal callbacks
+	 */
+public:
+	void onBehaviourToggle(ERlvBehaviour eBhvr, ERlvParamType eType);	// RlvHandler::rlv_behaviour_signal_t
+
+	/*
+	 * Behaviour handlers
+	 */
+protected:
+	void onRefreshHoverText();											// showloc, shownames, showhovertext(all|world|hud)
+	void onToggleMovement();											// fly, alwaysrun and temprun
+	void onToggleShowLoc();												// showloc
+	void onToggleShowMinimap();											// showminimap
+	void onToggleShowWorldMap();										// showworldmap
+	void onToggleTp();													// tploc and tplm
+	void onToggleUnsit();												// unsit
+	void onToggleViewXXX();												// viewnote, viewscript, viewtexture
+	void onUpdateLoginLastLocation(bool fQuitting);						// tploc and unsit
+
+ 	/*
+	 * Floater and sidebar validation callbacks
+	 */
+public:
+	void addGenericFloaterFilter(const std::string& strFloaterName);
+	void removeGenericFloaterFilter(const std::string& strFloaterName);
+
+protected:
+	bool filterFloaterGeneric(const std::string&, const LLSD&);
+	boost::signals2::connection m_ConnFloaterGeneric;
+	bool filterFloaterShowLoc(const std::string&, const LLSD& );
+	boost::signals2::connection m_ConnFloaterShowLoc;					// showloc
+	bool filterFloaterViewXXX(const std::string&, const LLSD&);
+	boost::signals2::connection m_ConnFloaterViewXXX;					// viewnote, viewscript, viewtexture
+
+	bool filterPanelShowLoc(const std::string&, const std::string&, const LLSD& );
+	boost::signals2::connection m_ConnPanelShowLoc;						// showloc
+
+	/*
+	 * Helper functions
+	 */
+public:
+	static bool canViewParcelProperties();								// showloc
+	static bool canViewRegionProperties();								// showloc
+	static bool hasOpenIM(const LLUUID& idAgent);						// shownames
+	static bool hasOpenProfile(const LLUUID& idAgent);					// shownames
+	static bool isBuildEnabled();										// edit and rez
+	static bool isBuildEnabledOrActive();								// edit and rez
+
+	/*
+	 * Member variables
+	 */
+protected:
+	typedef boost::function<void(bool)> behaviour_handler_t;
+	typedef std::multimap<ERlvBehaviour, behaviour_handler_t> behaviour_handler_map_t;
+	behaviour_handler_map_t m_Handlers;
+
+	std::multiset<std::string> m_FilteredFloaters;
+};
+
+// ============================================================================
+
+#endif // RLV_UI_H
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index d83a6071f6e1a8b75810a16fdbc4597208b91515..dc1697f33fc13ed6bb3bbbe64784450f0b66d038 100644
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -182,6 +182,30 @@
 		<menu_item_call label="INFO ÜBER [APP_NAME]" name="About Second Life"/>
 		<menu_item_call label="Nach Updates suchen" name="Check for Updates"/>
 	</menu>
+    
+    <menu label="RLVa" name="RLVa Main">
+      <menu label="Entwickler" name="Debug">
+        <menu_item_check label="RLVa Menü in der Leiste anzeigen" name="Show Top-level RLVa Menu" />
+        <menu_item_check label="Debug Nachrichten anzeigen" name="Show Debug Messages" />
+        <menu_item_check label="Hide Unset or Duplicate Messages" name="Hide Unset or Duplicate Messages" />
+        <menu_item_check label="Fehlermeldungen anzeigen" name="Show Assertion Failures" />
+        <menu_item_check label="Gesperrte Layer verstecken" name="Hide Locked Layers" />
+        <menu_item_check label="Gesperrte Teile verstecken" name="Hide Locked Attachments" />
+        <menu_item_check label="Enable Legacy Naming" name="Enable Legacy Naming" />
+        <menu_item_check label="Shared Wear einschalten" name="Enable Shared Wear" />
+        <menu_item_check label="Objekte beim anziehen umbenennen" name="Rename Shared Items on Wear" />
+        <menu_item_check label="Sperren..." name="Locks" />
+      </menu>
+
+      <menu_item_check label="OOC Chat erlauben" name="Allow OOC Chat" />
+      <menu_item_check label="Senden an #RLV verbieten" name="Forbid Give to #RLV" />
+      <menu_item_check label="Gefilterten Chat anzeigen" name="Show Filtered Chat" />
+      <menu_item_check label="Namensschilder anzeigen" name="Show Name Tags" />
+      <menu_item_check label="Anziehen ersetzt unverschlossenes" name="Wear Replaces Unlocked" />
+      <menu_item_check label="Einschränkungen..." name="Restrictions" />
+      <menu_item_check label="Nachrichten..." name="Strings" />
+    </menu>
+    
 	<menu label="Erweitert" name="Advanced">
 		<menu_item_call label="Textur neu laden" name="Rebake Texture"/>
 		<menu_item_call label="UI-Größe auf Standard setzen" name="Set UI Size to Default"/>
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index ec87b3684ed64cba38365d02cddd7ba755ae1cbb..660668390796746cd92177e5e58593b5136a23b4 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -10,6 +10,7 @@
  title="ABOUT [CAPITALIZED_APP_NAME]"
  width="470">
   
+RestrainedLove API: [RLV_VERSION]
   <tab_container
     follows="all" 
     top="25"
diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml
index b8893e11d90207b5430afd4630aadccc0f57fc44..ad66f37d3cb8b1ee6b96fe3dee63b9f3d9d58604 100644
--- a/indra/newview/skins/default/xui/en/floater_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_map.xml
@@ -14,9 +14,10 @@
  save_rect="true"
  save_visibility="true"
  width="200">
+    <!-- RLVa shows the anonymized name on the regular tooltip when @shownames=n restricted (rather than show the avatar inspector) --> 
     <floater.string
      name="ToolTipMsg">
-        [REGION](Double-click to open Map, shift-drag to pan)
+        [AGENT][REGION](Double-click to open Map, shift-drag to pan)
     </floater.string>
 	<floater.string
      name="AltToolTipMsg">
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml
new file mode 100644
index 0000000000000000000000000000000000000000..965b9172592aeb58b280d01b154e8370b6b0efd4
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+  open_positioning="cascading"
+  can_close="true"
+  can_minimize="true"
+  can_resize="true"
+  height="300"
+  min_height="300"
+  min_width="450"
+  name="rlv_behaviours"
+  save_rect="true"
+  save_visibility="false"
+  single_instance="true"
+  title="ACTIVE RLV RESTRICTIONS"
+  width="450">
+  <tab_container
+    follows="all"
+    layout="topleft"
+    left="8"
+    name="behaviour_tab"
+    height="266"
+    right="-8"
+    tab_height="23"
+    tab_min_width="120"
+    tab_position="top"
+    top="0" >
+    <panel
+      follows="all"  height="265"
+      label="RESTRICTIONS"
+      layout="topleft"
+      name="behaviour_panel"
+      top="0">
+      <scroll_list
+	     draw_border="false"
+	     draw_heading="true"
+	     draw_stripes="true"
+	     follows="all"
+	     height="266"
+	     layout="topleft"
+	     multi_select="false"
+	     name="behaviour_list"
+	     tool_tip="List of current RLVa restrictions."
+	     top_pad="0" >
+        <scroll_list.columns label="Restriction" name="behaviour" width="70" />
+        <scroll_list.columns label="Object Name" name="issuer" />
+      </scroll_list>
+    </panel>
+    <panel
+      follows="all"  height="265"
+      label="EXCEPTIONS"
+      layout="topleft"
+      name="exception_panel"
+      top="0"> 
+      <scroll_list
+	     draw_border="false"
+	     draw_heading="true"
+	     draw_stripes="true"
+	     follows="all"
+	     height="266"
+	     layout="topleft"
+	     multi_select="false"
+	     name="exception_list"
+	     tool_tip="List of current RLVa exceptions."
+	     top_pad="0" >
+        <scroll_list.columns label="Exception" name="behaviour" width="70" />
+        <scroll_list.columns label="Source" name="option" width="105" />
+        <scroll_list.columns label="Object Name" name="issuer" />
+      </scroll_list>
+    </panel>
+    <panel
+      follows="all"  height="265"
+      label="MODIFIERS"
+      layout="topleft"
+      name="modifier_panel"
+      top="0">
+      <scroll_list
+       draw_border="false"
+       draw_heading="true"
+       draw_stripes="true"
+       follows="all"
+       height="266"
+       layout="topleft"
+       multi_select="false"
+       name="modifier_list"
+       tool_tip="List of current RLVa modifiers."
+       top_pad="0" >
+        <scroll_list.columns label="Modifier" name="modifier" width="105" />
+        <scroll_list.columns label="Value" name="value" width="105" />
+        <scroll_list.columns label="Primary Object" name="primary" />
+      </scroll_list>
+    </panel>
+  </tab_container>
+  <panel
+   background_visible="false"
+   follows="left|right|bottom"
+   height="25"
+   label="bottom_panel"
+   layout="topleft"
+   name="bottom_panel"
+   top_pad="0">
+    <button
+     image_hover_unselected="Toolbar_Left_Over"
+     image_overlay="Copy"
+     image_overlay_alignment="left"
+     image_selected="Toolbar_Left_Selected"
+     image_unselected="Toolbar_Left_Off"
+     label="Copy to Clipboard"
+     left="0"
+     name="copy_btn"
+     top="1"
+     width="150" />
+    <icon
+     follows="left|right"
+     image_name="Toolbar_Right_Off"
+     left_pad="1"
+     name="dummy_icon"
+     top="1"
+     right="-1" />
+  </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_console.xml b/indra/newview/skins/default/xui/en/floater_rlv_console.xml
new file mode 100644
index 0000000000000000000000000000000000000000..30f2e1580032058d441ffe5ac1ca17146c37af84
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_rlv_console.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+  can_resize="true"
+  height="400"
+  layout="topleft"
+  min_height="300"
+  min_width="300"
+  name="rlv_console"
+  title="RLVa console"
+  width="600"
+  >
+    <text_editor
+     follows="all"
+     left="10"
+     length="1"
+     font="Monospace"
+     height="366"
+     ignore_tab="false"
+     layout="topleft"
+     max_length="65536"
+     name="console_output"
+     read_only="true"
+     track_end="true"
+     type="string"
+     width="576"
+     word_wrap="true"
+     >
+    </text_editor>
+    <line_editor
+     border_style="line"
+     border_thickness="1"
+     bottom_delta="20"
+     follows="left|right|bottom"
+     font="SansSerif"
+     height="19"
+     layout="topleft"
+     max_length="127"
+     name="console_input"
+     top_delta="0"
+     width="576"
+     >
+    </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_locks.xml b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d6665bcef2a6d5dfc4b585b5c84f220d31ae9386
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+  can_close="true"
+  can_minimize="true"
+  can_resize="true"
+  height="200"
+  min_height="200"
+  min_width="500"
+  name="rlvLocks"
+  save_rect="true"
+  save_visibility="false"
+  single_instance="true"
+  positioning="cascading"
+  reuse_instance="true"
+  title="ACTIVE RLV LOCKS"
+  width="500">
+  <panel
+    class="panel_rlvLocks"
+    filename="panel_rlv_locks.xml"
+    layout="topleft"
+    left="9" 
+    name="panel_rlvLocks"
+    right="-8"
+    top="0" />
+</floater>
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_strings.xml b/indra/newview/skins/default/xui/en/floater_rlv_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2b31f99fb4eab7e8cbc7a2339cc0516b77a2d4eb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_rlv_strings.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_minimize="false"
+ height="215"
+ layout="topleft"
+ legacy_header_height="18"
+ name="rlva_strings"
+ title="RLVa Strings"
+ width="340">
+    <combo_box
+     allow_text_entry="false"
+     follows="top|left"
+     height="22"
+     layout="topleft"
+     left="12"
+     max_chars="255"
+     name="string_list"
+     top="25"
+     width="316" />
+    <text_editor
+     enabled="false"
+     height="60"
+     layout="topleft"
+     left_delta="0"
+     name="string_descr"
+     top_pad="5"
+     width="317"
+     word_wrap="true" />
+    <text_editor
+     enabled="true"
+     height="60"
+     layout="topleft"
+     left_delta="0"
+     name="string_value"
+     top_pad="5"
+     width="316"
+     word_wrap="true" />
+    <panel
+      follows="top|left"
+      height="25"
+      layout="topleft"
+      left="10"
+      name="bottom_panel"
+      top="180"
+      right="-8">
+      <button
+	follows="top|left"
+	image_hover_unselected="Toolbar_Left_Over"
+	image_overlay="Refresh_Off"
+	image_overlay_alignment="left"
+	image_selected="Toolbar_Left_Selected"
+	image_unselected="Toolbar_Left_Off"
+	label="Reset to default"
+	layout="topleft"
+	left="0"
+	name="default_btn"
+	top="1"
+	width="140" >
+	<button.commit_callback
+	  function="ClickDefault" />
+      </button>
+      <icon
+	follows="left|right"
+	image_name="Toolbar_Right_Off"
+	left_pad="1"
+	name="dummy_icon"
+	top="1"
+	right="-1" />
+    </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
index 9e520b2d31b22c39e03acd5bf4986f2fc6a06047..ffba367061830bd2076e6bfc9d6e702c799a132c 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
@@ -9,6 +9,8 @@
         <menu_item_call.on_click
          function="ShowAgentProfile"
          parameter="hit object" />
+        <menu_item_call.on_enable
+         function="RLV.CanShowName" />
     </menu_item_call>
    <menu_item_call
      enabled="false"
@@ -24,6 +26,8 @@
      name="Send IM...">
         <menu_item_call.on_click
          function="Avatar.SendIM" />
+        <menu_item_call.on_enable
+         function="RLV.CanShowName" />
     </menu_item_call>
     <menu_item_call
      label="Call"
@@ -36,8 +40,10 @@
       <menu_item_call
          label="Invite to Group"
          name="Invite...">
-      <menu_item_call.on_click
+        <menu_item_call.on_click
          function="Avatar.InviteToGroup" />
+        <menu_item_call.on_enable
+         function="RLV.CanShowName" />
       </menu_item_call>
    <menu_item_separator />
     <menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
index fadacbf3cb79122f42ec226343fab8bd2b8d7f68..07f20b11dd220a236952c252684cf5e078dbcd94 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
@@ -9,6 +9,8 @@
         <menu_item_call.on_click
          function="ShowAgentProfile"
          parameter="hit object" />
+        <menu_item_call.on_enable
+         function="RLV.CanShowName" />
     </menu_item_call>
    <menu_item_call
      enabled="false"
@@ -24,6 +26,8 @@
      name="Send IM...">
         <menu_item_call.on_click
          function="Avatar.SendIM" />
+        <menu_item_call.on_enable
+         function="RLV.CanShowName" />
     </menu_item_call>
     <menu_item_call
      label="Call"
@@ -36,8 +40,10 @@
       <menu_item_call
          label="Invite to Group"
          name="Invite...">
-      <menu_item_call.on_click
+        <menu_item_call.on_click
          function="Avatar.InviteToGroup" />
+        <menu_item_call.on_enable
+         function="RLV.CanShowName" />
       </menu_item_call>
     
    <menu_item_separator />
@@ -101,6 +107,8 @@
      name="Pay...">
         <menu_item_call.on_click
          function="PayObject" />       
+        <menu_item_call.on_enable
+         function="EnablePayAvatar" />
     </menu_item_call>
 
    <menu_item_separator />
diff --git a/indra/newview/skins/default/xui/en/menu_land.xml b/indra/newview/skins/default/xui/en/menu_land.xml
index 2ad5cbbe951cd561d4b72ab58fa5afb16380842b..3a7f24fdf5bcd30725cd7fad0ff7a4e760886ea9 100644
--- a/indra/newview/skins/default/xui/en/menu_land.xml
+++ b/indra/newview/skins/default/xui/en/menu_land.xml
@@ -8,6 +8,9 @@
         <menu_item_call.on_click
          function="Floater.Show"
          parameter="about_land" />
+        <menu_item_call.on_enable
+         function="Floater.CanShow"
+         parameter="about_land" />
     </menu_item_call>
  <!--   <menu_item_call
      label="Go Here"
diff --git a/indra/newview/skins/default/xui/en/menu_place_add_button.xml b/indra/newview/skins/default/xui/en/menu_place_add_button.xml
index e3a39a1242748c8b73874fc851b73cdd77f1db4a..bdd4e230b949b0327f107364c1ab29eabd5aae83 100644
--- a/indra/newview/skins/default/xui/en/menu_place_add_button.xml
+++ b/indra/newview/skins/default/xui/en/menu_place_add_button.xml
@@ -23,5 +23,8 @@
         <on_click
          function="Places.LandmarksGear.Add.Action"
          parameter="add_landmark" />
+        <on_enable
+         function="Places.LandmarksGear.Enable"
+         parameter="add_landmark" />
     </menu_item_call>
 </menu>
diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml
index 1aeb166e01570aaccb4ead89d93c7a887e3a4cad..4d59ab06317bfc97007a222ff866d8a76d0aa63e 100644
--- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml
+++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml
@@ -13,6 +13,9 @@
         <on_click
          function="Places.LandmarksGear.Add.Action"
          parameter="add_landmark" />
+        <on_enable
+         function="Places.LandmarksGear.Enable"
+         parameter="add_landmark" />
     </menu_item_call>
     <menu_item_call
      label="Add Folder"
diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml
index ff5fdd3795322d5c3582f0b7ff7d73b3240c6d29..28c74a3d5d1813b75f8966bb9e51e2b9bfe0b95e 100644
--- a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml
+++ b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml
@@ -48,6 +48,9 @@
         <on_click
          function="Places.LandmarksGear.Add.Action"
          parameter="add_landmark" />
+        <on_enable
+         function="Places.LandmarksGear.Enable"
+         parameter="add_landmark" />
     </menu_item_call>
     <menu_item_call
      label="Add Folder"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index b189d1038fa7aade97566327c68992788db68e75..c1578129b711b8d26b22ec63368985945b72513f 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -492,6 +492,8 @@
          name="Place Profile">
             <menu_item_call.on_click
              function="World.PlaceProfile" />
+            <menu_item_call.on_enable
+             function="World.EnablePlaceProfile" />
         </menu_item_call>
         <menu_item_call
          label="About land"
@@ -499,6 +501,9 @@
             <menu_item_call.on_click
              function="Floater.Show"
              parameter="about_land" />
+            <menu_item_call.on_enable
+             function="Floater.CanShow"
+             parameter="about_land" />
         </menu_item_call>
         <menu_item_call
          label="Region / Estate"
@@ -506,6 +511,9 @@
             <menu_item_call.on_click
              function="Floater.Show"
              parameter="region_info" />
+            <menu_item_call.on_enable
+             function="Floater.CanShow"
+             parameter="region_info" />
         </menu_item_call>
         <menu_item_call
          label="My land holdings..."
@@ -638,6 +646,9 @@
                 <menu_item_check.on_check
                  function="World.EnableEnvSettings" 
                  parameter="sunrise" />
+                <menu_item_check.on_enable
+                 function="RLV.EnableIfNot"
+                 parameter="setenv" />
             </menu_item_check>
             <menu_item_check
              label="Midday"
@@ -649,6 +660,9 @@
                 <menu_item_check.on_check
                  function="World.EnableEnvSettings" 
                  parameter="noon" />
+                <menu_item_check.on_enable
+                 function="RLV.EnableIfNot"
+                 parameter="setenv" />
             </menu_item_check>
             <menu_item_check
              label="Sunset"
@@ -660,6 +674,9 @@
                 <menu_item_check.on_check
                  function="World.EnableEnvSettings" 
                  parameter="sunset" />
+                <menu_item_check.on_enable
+                 function="RLV.EnableIfNot"
+                 parameter="setenv" />
             </menu_item_check>
             <menu_item_check
              label="Midnight"
@@ -670,6 +687,9 @@
                 <menu_item_check.on_check
                  function="World.EnableEnvSettings" 
                  parameter="midnight" />
+                <menu_item_check.on_enable
+                 function="RLV.EnableIfNot"
+                 parameter="setenv" />
             </menu_item_check>
             <menu_item_separator/>
             <menu_item_check
@@ -681,6 +701,9 @@
                 <menu_item_check.on_check
                  function="World.EnableEnvSettings" 
                  parameter="region" />
+                <menu_item_check.on_enable
+                 function="RLV.EnableIfNot"
+                 parameter="setenv" />
             </menu_item_check>
         </menu>
 	    
@@ -697,6 +720,9 @@
 	     	 	<menu_item_call.on_click
 	     	 	 function="World.EnvSettings"
                  parameter="editor"/>
+          <menu_item_call.on_enable
+           function="RLV.EnableIfNot"
+           parameter="setenv" />
 	     	</menu_item_call>
 	     	
 	     	<menu_item_separator/>
@@ -710,6 +736,9 @@
 	     	 	 	<menu_item_call.on_click
 	     	 	 	function="World.EnvPreset"
 	     	 	 	parameter="new_water"/>
+            <menu_item_call.on_enable
+            function="RLV.EnableIfNot"
+            parameter="setenv" />
 	     	 	</menu_item_call>
 	     	 	<menu_item_call
 	     	 	 label="Edit preset..."
@@ -717,7 +746,10 @@
 	     	 	 	<menu_item_call.on_click
 	     	 	 	function="World.EnvPreset"
 	     	 	 	parameter="edit_water"/>
-	     	 	</menu_item_call>
+            <menu_item_call.on_enable
+            function="RLV.EnableIfNot"
+            parameter="setenv" />
+          </menu_item_call>
 	     	 	<menu_item_call
 	     	 	 label="Delete preset..."
 	     	 	 name="delete_water_preset">
@@ -739,14 +771,20 @@
 	     	 	 	<menu_item_call.on_click
 	     	 	 	function="World.EnvPreset"
 	     	 	 	parameter="new_sky"/>
-	     	 	</menu_item_call>
+            <menu_item_call.on_enable
+            function="RLV.EnableIfNot"
+            parameter="setenv" />
+          </menu_item_call>
 	     	 	<menu_item_call
 	     	 	 label="Edit preset..."
 	     	 	 name="edit_sky_preset">
 	     	 	 	<menu_item_call.on_click
 	     	 	 	function="World.EnvPreset"
 	     	 	 	parameter="edit_sky"/>
-	     	 	</menu_item_call>
+            <menu_item_call.on_enable
+            function="RLV.EnableIfNot"
+            parameter="setenv" />
+          </menu_item_call>
 	     	 	<menu_item_call
 	     	 	 label="Delete preset..."
 	     	 	 name="delete_sky_preset">
@@ -768,14 +806,20 @@
 	     	 	 	<menu_item_call.on_click
 	     	 	 	function="World.EnvPreset"
 	     	 	 	parameter="new_day_cycle"/>
-	     	 	</menu_item_call>
+            <menu_item_call.on_enable
+            function="RLV.EnableIfNot"
+            parameter="setenv" />
+          </menu_item_call>
 	     	 	<menu_item_call
 	     	 	 label="Edit preset..."
 	     	 	 name="edit_day_preset">
 	     	 	 	<menu_item_call.on_click
 	     	 	 	function="World.EnvPreset"
 	     	 	 	parameter="edit_day_cycle"/>
-	     	 	</menu_item_call>
+            <menu_item_call.on_enable
+            function="RLV.EnableIfNot"
+            parameter="setenv" />
+          </menu_item_call>
 	     	 	<menu_item_call
 	     	 	 label="Delete preset..."
 	     	 	 name="delete_day_preset">
@@ -1446,6 +1490,204 @@
            function="Advanced.CheckViewerUpdates"/>
         </menu_item_call>
     </menu>
+    <menu
+     create_jump_keys="true"
+     label="RLVa"
+     name="RLVa Main"
+     tear_off="true"
+     visible="true">
+      <menu
+       label="Develop"
+       name="Debug"
+       tear_off="true">
+        <menu_item_check
+         label="Show Top-level RLVa Menu"
+         name="Show Top-level RLVa Menu">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaTopLevelMenu" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaTopLevelMenu" />
+        </menu_item_check>
+      	<menu_item_separator/>
+      	<menu_item_check
+      	 label="Show Debug Messages"
+      	 name="Show Debug Messages">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RestrainedLoveDebug" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RestrainedLoveDebug" />
+      	</menu_item_check>
+      	<menu_item_check
+      	 label="Hide Unset or Duplicate Messages"
+      	 name="Hide Unset or Duplicate Messages">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaDebugHideUnsetDuplicate" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaDebugHideUnsetDuplicate" />
+      	</menu_item_check>
+      	<menu_item_check
+      	 label="Show Assertion Failures"
+      	 name="Show Assertion Failures">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaShowAssertionFailures" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaShowAssertionFailures" />
+      	</menu_item_check>
+      	<menu_item_separator/>
+        <menu_item_check
+         label="Hide Locked Layers"
+         name="Hide Locked Layers">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaHideLockedLayers" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaHideLockedLayers" />
+        </menu_item_check>
+        <menu_item_check
+         label="Hide Locked Attachments"
+         name="Hide Locked Attachments">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaHideLockedAttachments" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaHideLockedAttachments" />
+        </menu_item_check>
+        <menu_item_separator/>
+      	<menu_item_check
+      	 label="Enable Legacy Naming"
+      	 name="Enable Legacy Naming">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaEnableLegacyNaming" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaEnableLegacyNaming" />
+      	</menu_item_check>
+        <menu_item_check
+      	 label="Enable Shared Wear"
+      	 name="Enable Shared Wear">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaEnableSharedWear" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaEnableSharedWear" />
+        </menu_item_check>
+        <menu_item_check
+      	 label="Rename Shared Items on Wear"
+      	 name="Rename Shared Items on Wear">
+          <menu_item_check.on_check
+           function="CheckControl"
+           parameter="RLVaSharedInvAutoRename" />
+          <menu_item_check.on_click
+           function="ToggleControl"
+           parameter="RLVaSharedInvAutoRename" />
+      	</menu_item_check>
+      	<menu_item_separator/>
+      	<menu_item_check
+      	 label="Locks..."
+      	 name="Locks">
+          <menu_item_check.on_check
+           function="Floater.Visible"
+           parameter="rlv_locks" />
+          <menu_item_check.on_click
+           function="Floater.Toggle"
+           parameter="rlv_locks" />
+      	</menu_item_check>
+      </menu>
+      <menu_item_separator/>
+      <menu_item_check
+       label="Allow OOC Chat"
+       name="Allow OOC Chat">
+      	<menu_item_check.on_check
+      	 function="CheckControl"
+      	 parameter="RestrainedLoveCanOOC" />
+      	<menu_item_check.on_click
+      	 function="ToggleControl"
+      	 parameter="RestrainedLoveCanOOC" />
+      </menu_item_check>
+      <menu_item_check
+       label="Allow Temporary Attachments"
+       name="Allow Temporary Attachments">
+      	<menu_item_check.on_check
+      	 function="CheckControl"
+      	 parameter="RLVaEnableTemporaryAttachments" />
+      	<menu_item_check.on_click
+      	 function="ToggleControl"
+      	 parameter="RLVaEnableTemporaryAttachments" />
+      </menu_item_check>
+      <menu_item_check
+       label="Forbid Give to #RLV"
+       name="Forbid Give to #RLV">
+      	<menu_item_check.on_check
+      	 function="CheckControl"
+      	 parameter="RestrainedLoveForbidGiveToRLV" />
+      	<menu_item_check.on_click
+      	 function="ToggleControl"
+      	 parameter="RestrainedLoveForbidGiveToRLV" />
+      </menu_item_check>
+      <menu_item_check
+       label="Show Filtered Chat"
+       name="Show Filtered Chat">
+      	<menu_item_check.on_check
+      	 function="CheckControl"
+      	 parameter="RestrainedLoveShowEllipsis" />
+      	<menu_item_check.on_click
+      	 function="ToggleControl"
+      	 parameter="RestrainedLoveShowEllipsis" />
+      </menu_item_check>
+      <menu_item_check
+       label="Wear Replaces Unlocked"
+       name="Wear Replaces Unlocked">
+      	<menu_item_check.on_check
+      	 function="CheckControl"
+      	 parameter="RLVaWearReplaceUnlocked" />
+      	<menu_item_check.on_click
+      	 function="ToggleControl"
+      	 parameter="RLVaWearReplaceUnlocked" />
+      </menu_item_check>
+      <menu_item_separator />
+      <menu_item_check
+       label="Console..."
+       name="Console">
+        <menu_item_check.on_check
+      	 function="Floater.Visible"
+      	 parameter="rlv_console" />
+        <menu_item_check.on_click
+      	 function="Floater.Toggle"
+      	 parameter="rlv_console" />
+      </menu_item_check>
+      <menu_item_check
+       label="Restrictions..."
+       name="Restrictions">
+      	<menu_item_check.on_check
+      	 function="Floater.Visible"
+      	 parameter="rlv_behaviours" />
+      	<menu_item_check.on_click
+      	 function="Floater.Toggle"
+      	 parameter="rlv_behaviours" />
+      </menu_item_check>
+      <menu_item_check
+       label="Strings..."
+       name="Strings">
+        <menu_item_check.on_check
+         function="Floater.Visible"
+         parameter="rlv_strings" />
+        <menu_item_check.on_click
+         function="Floater.Toggle"
+         parameter="rlv_strings" />
+      </menu_item_check>
+    </menu>
     <menu
      create_jump_keys="true"
      label="Advanced"
@@ -1905,6 +2147,11 @@
                  parameter="flexible" />
             </menu_item_check>
         </menu>        
+        <menu
+         label="RLVa"
+         name="RLVa Embedded"
+         tear_off="true"
+         visible="true" />
         <menu_item_check
          label="Use Plugin Read Thread"
          name="Use Plugin Read Thread">
@@ -2061,7 +2308,18 @@
         </menu> <!--Shortcuts-->
 
         <menu_item_separator/>
-
+        <menu_item_check
+           label="RestrainedLove API"
+           name="RLV API">
+              <menu_item_check.on_check
+               function="CheckControl"
+               parameter="RestrainedLove" />
+              <menu_item_check.on_click
+               function="ToggleControl"
+               parameter="RestrainedLove" />
+              <menu_item_check.on_visible
+               function="RLV.MainToggleVisible" />
+        </menu_item_check>
         <menu_item_call
          label="Show Debug Settings"
          name="Debug Settings">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index b2425649a4d26df701e95f9c9df8ef4df46d2318..fe898ec9e44988e77dd46b016b49d3450746f340 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7256,6 +7256,7 @@ Your object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; has given you th
   <notification
    icon="notify.tga"
    name="UserGiveItem"
+   label="Inventory offer from [NAME_LABEL]"
    log_to_im ="true"
    type="offer"
    sound="UISndNewIncomingIMSession">
@@ -7313,6 +7314,7 @@ Your object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; has given you th
   <notification
    icon="notify.tga"
    name="TeleportOffered"
+   label="Teleport offer from [NAME_LABEL]"
    log_to_im="true"
    log_to_chat="false"
    type="offer"
@@ -7428,6 +7430,7 @@ Offer a teleport?
   <notification
    icon="notify.tga"
    name="OfferFriendship"
+   label="Friendship offer from [NAME_LABEL]"
    log_to_im="true"
    type="offer">
     <tag>friendship</tag>
@@ -7461,6 +7464,7 @@ Offer a teleport?
   <notification
    icon="notify.tga"
    name="OfferFriendshipNoMessage"
+   label="Friendship offer from [NAME_LABEL]"
    persist="true"
    type="notify">
     <tag>friendship</tag>
@@ -11009,6 +11013,13 @@ An internal error prevented us from properly updating your viewer.  The L$ balan
    <tag>fail</tag>
 Cannot create large prims that intersect other players.  Please re-try when other players have moved.
   </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="RLVChangeStrings"
+   type="alertmodal">
+Changes won't take effect until after you restart [APP_NAME].
+  </notification>
   
   <notification
    icon="alertmodal.tga"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 2cb06d6877c57bbc999f7568d08f5bc7bf7c7fb9..6508f5a35d9c63814e3ee69203c5713fa77c3f40 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -184,6 +184,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
              layout="topleft"
              min_dim="100"
              mouse_opaque="false"
+             name="Net Map Panel"
              user_resize="true"
              visibility_control="NearbyListShowMap"
              width="313">
diff --git a/indra/newview/skins/default/xui/en/panel_rlv_locks.xml b/indra/newview/skins/default/xui/en/panel_rlv_locks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..80373af1f4a3fd262ecd9ad5ddac0590c8be4ef7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_rlv_locks.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+  follows="all"
+  height="200"
+  label="ACTIVE RLV LOCKS"
+  layout="topleft"
+  name="panel_rlvLocks"
+  top="0"
+  width="500">
+  <scroll_list
+    draw_border="false"
+    draw_heading="true"
+    draw_stripes="true"
+    follows="all"
+    height="167"
+    layout="topleft"
+    multi_select="false"
+    name="lock_list"
+    top_pad="0" >
+    <scroll_list.columns label="Lock Type" name="lock_type" width="100" />
+    <scroll_list.columns label="Method" name="lock_addrem" width="60" />
+    <scroll_list.columns label="Target Object / Point" name="lock_target" />
+    <scroll_list.columns label="Lock Origin" name="lock_origin" width="150" />
+  </scroll_list>
+  <panel
+    background_visible="false"
+    follows="left|right|bottom"
+    height="25"
+    label="bottom_panel"
+    layout="topleft"
+    name="bottom_panel"
+    top_pad="0" >
+    <button
+      image_hover_unselected="Toolbar_Left_Over"
+      image_overlay="Refresh_Off"
+      image_overlay_alignment="left"
+      image_selected="Toolbar_Left_Selected"
+      image_unselected="Toolbar_Left_Off"
+      label="Refresh"
+      left="0"
+      name="refresh_btn"
+      top="1"
+      width="90" />
+    <icon
+      follows="left|right"
+      image_name="Toolbar_Right_Off"
+      left_pad="1"
+      name="dummy_icon"
+      top="1"
+      right="-1"/>
+  </panel>
+</panel>
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/rlva_strings.xml b/indra/newview/skins/default/xui/en/rlva_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..922173282b964fc3d1e82baddd7f08260cdb6c4c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/rlva_strings.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<llsd>
+<map>
+
+	<key>strings</key>
+	<map>
+		<!-- Primarily used when @showloc restricted -->
+		<key>hidden_generic</key>
+		<map>
+			<key>value</key>
+			<string>(Hidden)</string>
+		</map>
+		<key>hidden_parcel</key>
+		<map>
+			<key>value</key>
+			<string>(Hidden parcel)</string>
+		</map>
+		<key>hidden_region</key>
+		<map>
+			<key>value</key>
+			<string>(Hidden region)</string>
+		</map>
+
+		<!-- Received/sent IMs will be replaced by the matching string when @recvim/sendim restricted -->
+		<key>blocked_recvim</key>
+		<map>
+			<key>value</key>
+			<string>*** IM blocked by your viewer</string>
+			<key>description</key>
+			<string>Shown in place of the original message when an incoming IM is blocked</string>
+			<key>label</key>
+			<string>Blocked incoming IM message (local)</string>
+			<key>customizable</key>
+			<boolean>1</boolean>
+		</map>
+		<key>blocked_sendim</key>
+		<map>
+			<key>value</key>
+			<string>*** IM blocked by sender's viewer</string>
+			<key>description</key>
+			<string>Shown (and sent to the remote party) when an outgoing IM is blocked</string>
+			<key>label</key>
+			<string>Blocked outgoing IM message (local + remote)</string>
+			<key>customizable</key>
+			<boolean>1</boolean>
+		</map>
+
+		<!-- Shown as notifications -->
+		<key>blocked_autopilot</key>
+		<map>
+			<key>value</key>
+			<string>Unable to use the autopilot due to RLV restrictions</string>
+		</map>
+		<key>blocked_generic</key>
+		<map>
+			<key>value</key>
+			<string>Unable to perform action due to RLV restrictions</string>
+		</map>
+		<key>blocked_groupchange</key>
+		<map>
+			<key>value</key>
+			<string>Unable to change your active group due to an RLV restriction; switching back to [GROUP_SLURL]</string>
+		</map>
+		<key>blocked_nearby</key>
+		<map>
+			<key>value</key>
+			<string>Unable to see the presence of nearby avatars due to RLV restrictions</string>
+		</map>
+		<key>blocked_permattach</key>
+		<map>
+			<key>value</key>
+			<string>Attempt to attach '[OBJECT]' was denied due to RLV restrictions</string>
+		</map>
+		<key>blocked_permteleport</key>
+		<map>
+			<key>value</key>
+			<string>[OBJECT]' was denied permission to teleport you due to RLV restrictions</string>
+		</map>
+		<key>blocked_startim</key>
+		<map>
+			<key>value</key>
+			<string>Unable to start IM session with [RECIPIENT] due to RLV restrictions</string>
+		</map>
+		<key>blocked_startconf</key>
+		<map>
+			<key>value</key>
+			<string>Unable to start conference with [RECIPIENT] due to RLV restrictions</string>
+		</map>
+		<key>blocked_teleport</key>
+		<map>
+			<key>value</key>
+			<string>Unable to initiate teleport due to RLV restrictions</string>
+		</map>
+		<key>blocked_teleport_offer</key>
+		<map>
+			<key>value</key>
+			<string>Unable to offer teleport due to RLV restrictions</string>
+		</map>
+		<key>blocked_viewxxx</key>
+		<map>
+			<key>value</key>
+			<string>Unable to open [TYPE] due to RLV restrictions</string>
+		</map>
+		<key>blocked_wireframe</key>
+		<map>
+			<key>value</key>
+			<string>Unable to enable wireframe mode due to RLV restrictions</string>
+		</map>
+
+		<!-- Sent as "Busy" messages to the remote party -->
+		<key>blocked_recvim_remote</key>
+		<map>
+			<key>value</key>
+			<string>The Resident you messaged is currently prevented from reading your instant messages at the moment, please try again later.</string>
+			<key>description</key>
+			<string>Sent to the remote party when their IM was blocked</string>
+			<key>label</key>
+			<string>Blocked incoming IM message (remote)</string>
+			<key>customizable</key>
+			<boolean>1</boolean>
+		</map>
+		<key>blocked_tplurerequest_remote</key>
+		<map>
+			<key>value</key>
+			<string>The Resident is currently prevented from accepting. Please try again later.</string>
+			<key>description</key>
+			<string>Sent to the remote party when their teleport offer or request was blocked</string>
+			<key>label</key>
+			<string>Blocked teleport offer/request (remote)</string>
+			<key>customizable</key>
+			<boolean>1</boolean>
+		</map>
+	</map>
+
+	<!-- Generic names used to replace resident names when @shownames restricted -->
+	<key>anonyms</key>
+	<array>
+		<string>A resident</string>
+		<string>This resident</string>
+		<string>That resident</string>
+		<string>An individual</string>
+		<string>This individual</string>
+		<string>That individual</string>
+		<string>A person</string>
+		<string>This person</string>
+		<string>That person</string>
+		<string>A stranger</string>
+		<string>This stranger</string>
+		<string>That stranger</string>
+		<string>A being</string>
+		<string>This being</string>
+		<string>That being</string>
+		<string>An agent</string>
+		<string>This agent</string>
+		<string>That agent</string>
+		<string>A soul</string>
+		<string>This soul</string>
+		<string>That soul</string>
+		<string>Somebody</string>
+		<string>Some people</string>
+		<string>Someone</string>
+		<string>Mysterious one</string>
+		<string>An unknown being</string>
+		<string>Unidentified one</string>
+		<string>An unknown person</string>
+	</array>
+
+</map>
+</llsd>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 8988c3e0289916ed7f98758ae0ce5cb4ff66b0a5..c217014eefdbefe3e1a57b3df4a5ccd1e7067dac 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -32,6 +32,11 @@ You are at [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_L
 SLURL: &lt;nolink&gt;[SLURL]&lt;/nolink&gt;
 (global coordinates [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])
 [SERVER_VERSION]
+[SERVER_RELEASE_NOTES_URL]
+	</string>
+	<string name="AboutPositionRLVShowLoc">
+You are in [REGION]
+[SERVER_VERSION]
 [SERVER_RELEASE_NOTES_URL]
 	</string>
 	<!-- *NOTE: Do not translate text like GPU, Graphics Card, etc -
@@ -48,6 +53,7 @@ Graphics Card: [GRAPHICS_CARD]
 	<string name="AboutLibs">
 OpenGL Version: [OPENGL_VERSION]
 
+RestrainedLove API: [RLV_VERSION]
 J2C Decoder Version: [J2C_VERSION]
 Audio Driver Version: [AUDIO_DRIVER_VERSION]
 LLCEFLib/CEF Version: [LLCEFLIB_VERSION]
@@ -3570,6 +3576,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
   <string name="inventory_item_offered-im">
     Inventory item offered
   </string>
+  <string name="inventory_item_offered_rlv">
+    Inventory item offered to [NAME]
+  </string>
   <string name="share_alert">
     Drag items from inventory here
   </string>
@@ -4091,6 +4100,12 @@ Try enclosing path to the editor with double quotes.
   <!-- Spell check settings floater -->
   <string name="UserDictionary">[User]</string>
   
+  <!-- RLVa -->
+  <string name="RLVaPendingRestart"> (pending restart)</string>
+  <string name="RLVaToggleMessage">RestrainedLove Support will be %s after you restart</string>
+  <string name="RLVaToggleEnabled">enabled</string>
+  <string name="RLVaToggleDisabled">disabled</string>
+   
   <!-- Experience Tools strings -->
   <string name="experience_tools_experience">Experience</string>
   <string name="ExperienceNameNull">(no experience)</string>
diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp
index 4694f657b61031699ef13a45fa91ed23eb09015b..a6883f6e37406375da9a278a693288f91e230b05 100644
--- a/indra/newview/tests/llslurl_test.cpp
+++ b/indra/newview/tests/llslurl_test.cpp
@@ -54,6 +54,34 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
 	return std::string();
 }
 
+// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
+// Stub implementation to get the test to compile properly
+#include "../rlvhandler.h"
+
+const std::string& RlvStrings::getString(const std::string& strStringName)
+{
+	static const std::string strMissing = "(Missing RLVa string)";
+	return strMissing;
+}
+
+bool RlvUtil::isNearbyRegion(const std::string& strRegion)
+{
+	return false;
+}
+
+RlvHandler::RlvHandler() : m_pGCTimer(NULL), m_pWLSnapshot(NULL)
+{
+	// Array auto-initialization to 0 is non-standard? (Compiler warning in VC-8.0)
+	memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT);
+}
+
+RlvHandler::~RlvHandler()
+{
+}
+
+RlvHandler gRlvHandler;
+// [/RLVa:KB]
+
 //----------------------------------------------------------------------------
 // Mock objects for the dependencies of the code we're testing
 
diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat
index 96687226a8d3d243cdb268707a4eecefbb1d33e1..ecb6e357b41d507036fbcaa755be92d4fd8a9269 100644
--- a/indra/viewer_components/updater/scripts/windows/update_install.bat
+++ b/indra/viewer_components/updater/scripts/windows/update_install.bat
@@ -1,3 +1,3 @@
-start /WAIT %1 /SKIP_DIALOGS
-IF ERRORLEVEL 1 ECHO %3 > %2
-DEL %1
+start /WAIT %1 /SKIP_DIALOGS
+IF ERRORLEVEL 1 ECHO %3 > %2
+DEL %1