From 7e90fd6e7f770213af9d586206479c8cf8ee5bbd Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Sun, 8 Oct 2023 02:13:33 -0400
Subject: [PATCH] Add derendering feature based on code from Catznip

---
 indra/llui/llscrolllistcell.cpp               |  18 +
 indra/llui/llscrolllistcell.h                 |  24 +
 indra/llui/llscrolllistcolumn.cpp             |   8 +-
 indra/llui/llscrolllistcolumn.h               |   9 +
 indra/llui/llscrolllistctrl.cpp               |  94 ++-
 indra/llui/llscrolllistctrl.h                 |  21 +
 indra/llui/llscrolllistitem.h                 |   8 +
 indra/newview/CMakeLists.txt                  |   4 +
 indra/newview/llagenthandler.cpp              |   6 +-
 indra/newview/llchathistory.cpp               |   6 +-
 indra/newview/llderenderlist.cpp              | 431 ++++++++++
 indra/newview/llderenderlist.h                | 191 +++++
 indra/newview/llfloaterblocked.cpp            | 791 ++++++++++++++++++
 indra/newview/llfloaterblocked.h              | 245 ++++++
 indra/newview/llfloaterbump.cpp               |   6 +-
 indra/newview/llfloaterperformance.cpp        |   2 +-
 indra/newview/llfloaterpreference.cpp         |   9 +-
 indra/newview/llfloatersidepanelcontainer.cpp |  12 +
 indra/newview/llinspectremoteobject.cpp       |   6 +-
 indra/newview/llnamelistctrl.cpp              |  10 +
 indra/newview/llnamelistctrl.h                |   6 +-
 indra/newview/llpanelblockedlist.cpp          |   4 +
 indra/newview/llpanelblockedlist.h            |   2 +
 indra/newview/llpanelpeople.cpp               |  26 +-
 indra/newview/llpanelprofile.cpp              |   2 +-
 indra/newview/llselectmgr.cpp                 |   9 +-
 indra/newview/llselectmgr.h                   |   4 +-
 indra/newview/llviewerfloaterreg.cpp          |   6 +
 indra/newview/llviewermenu.cpp                |  58 +-
 indra/newview/llviewermessage.cpp             |   9 +-
 indra/newview/llviewerobjectlist.cpp          |  33 +
 indra/newview/llviewerregion.cpp              |  11 +-
 indra/newview/llvocache.cpp                   |   2 +-
 indra/newview/llvocache.h                     |   9 +-
 .../skins/default/xui/en/floater_blocked.xml  |  60 ++
 .../default/xui/en/menu_attachment_other.xml  |   4 +-
 .../default/xui/en/menu_avatar_other.xml      |   4 +-
 .../skins/default/xui/en/menu_object.xml      |  20 +
 .../skins/default/xui/en/menu_viewer.xml      |   8 +-
 .../xui/en/panel_block_avatar_rendering.xml   | 106 +++
 .../default/xui/en/panel_block_derender.xml   |  65 ++
 .../skins/default/xui/en/panel_block_list.xml | 124 +++
 .../skins/default/xui/en/panel_people.xml     |   4 +-
 43 files changed, 2424 insertions(+), 53 deletions(-)
 create mode 100644 indra/newview/llderenderlist.cpp
 create mode 100644 indra/newview/llderenderlist.h
 create mode 100644 indra/newview/llfloaterblocked.cpp
 create mode 100644 indra/newview/llfloaterblocked.h
 create mode 100644 indra/newview/skins/default/xui/en/floater_blocked.xml
 create mode 100644 indra/newview/skins/default/xui/en/panel_block_avatar_rendering.xml
 create mode 100644 indra/newview/skins/default/xui/en/panel_block_derender.xml
 create mode 100644 indra/newview/skins/default/xui/en/panel_block_list.xml

diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 2d3f87881fc..264d9eaf0df 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -78,6 +78,9 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
 
 LLScrollListCell::LLScrollListCell(const LLScrollListCell::Params& p)
 :	mWidth(p.width), 
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	mColumnName(p.column),
+// [/SL:KB]
 	mToolTip(p.tool_tip)
 {}
 
@@ -449,6 +452,14 @@ LLScrollListCheck::LLScrollListCheck(const LLScrollListCell::Params& p)
 {
 	LLCheckBoxCtrl::Params checkbox_p;
 	checkbox_p.name("checkbox");
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	if (p.commit_callback.isProvided())
+	{
+		if (!mCommitSignal)
+			mCommitSignal = new commit_signal_t();
+		mCommitSignal->connect(p.commit_callback());
+	}
+// [/SL:KB]
 	checkbox_p.rect = LLRect(0, p.width, p.width, 0);
 	checkbox_p.enabled(p.enabled);
 	checkbox_p.initial_value(p.value());
@@ -473,6 +484,9 @@ LLScrollListCheck::LLScrollListCheck(const LLScrollListCell::Params& p)
 
 LLScrollListCheck::~LLScrollListCheck()
 {
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	delete mCommitSignal;
+// [/SL:KB]
 	delete mCheckBox;
 	mCheckBox = NULL;
 }
@@ -508,6 +522,10 @@ void LLScrollListCheck::setValue(const LLSD& value)
 void LLScrollListCheck::onCommit()
 {
 	mCheckBox->onCommit();
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	if (mCommitSignal)
+		(*mCommitSignal)(this);
+// [/SL:KB]
 }
 
 /*virtual*/
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 0a7aaaf6ee5..9964cc9454e 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -36,6 +36,9 @@
 #include "llgltexture.h"
 
 #include "lllineeditor.h"
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+#include "lluictrl.h"
+// [/SL:KB]
 
 class LLCheckBoxCtrl;
 class LLSD;
@@ -52,6 +55,11 @@ class LLUIImage;
 class LLScrollListCell
 {
 public:
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	typedef boost::function<void(LLScrollListCell* cell)> commit_callback_t;
+	typedef boost::signals2::signal<void(LLScrollListCell* cell)> commit_signal_t;
+// [/SL:KB]
+
 	struct Params : public LLInitParam::Block<Params>
 	{
 		Optional<std::string>		type,
@@ -61,6 +69,10 @@ class LLScrollListCell
 		Optional<bool>				enabled,
 									visible;
 
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+		Optional<commit_callback_t> commit_callback;
+// [/SL:KB]
+
 		Optional<void*>				userdata;
 		Optional<LLSD>				value; // state of checkbox, icon id/name, date
 		Optional<LLSD>				alt_value;
@@ -79,6 +91,9 @@ class LLScrollListCell
 			width("width"),
 			enabled("enabled", true),
 			visible("visible", true),
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+			commit_callback("commit_callback"),
+// [/SL:KB]
 			value("value"),
 			alt_value("alt_value", ""),
 			label("label"),
@@ -106,6 +121,9 @@ class LLScrollListCell
 	virtual const LLSD		getAltValue() const;
 	virtual void			setValue(const LLSD& value) { }
 	virtual void			setAltValue(const LLSD& value) { }
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	virtual const std::string &getColumnName() const { return mColumnName; }
+// [/SL:KB]
 	virtual const std::string &getToolTip() const { return mToolTip; }
 	virtual void			setToolTip(const std::string &str) { mToolTip = str; }
 	virtual BOOL			getVisible() const { return TRUE; }
@@ -121,6 +139,9 @@ class LLScrollListCell
 
 private:
 	S32 mWidth;
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	std::string mColumnName;
+// [/SL:KB]
 	std::string mToolTip;
 };
 
@@ -250,6 +271,9 @@ class LLScrollListCheck : public LLScrollListCell
 
 private:
 	LLCheckBoxCtrl* mCheckBox;
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	commit_signal_t* mCommitSignal = nullptr;
+// [/SL:KB]
 };
 
 class LLScrollListDate : public LLScrollListText
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index bddf1b074b4..dc89a761308 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -109,7 +109,10 @@ BOOL LLScrollColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
 
 void LLScrollColumnHeader::onClick(const LLSD& data)
 {
-	if (mColumn)
+//	if (mColumn)
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	if ( (mColumn) && (mColumn->mCanSort) )
+// [/SL:KB]
 	{
 		LLScrollListCtrl::onClickColumn(mColumn);
 	}
@@ -313,6 +316,9 @@ LLScrollListColumn::LLScrollListColumn(const Params& p, LLScrollListCtrl* parent
 	mDynamicWidth(p.width.dynamic_width),
 	mRelWidth(p.width.relative_width),
 	mFontAlignment(p.halign),
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	mCanSort(p.can_sort),
+// [/SL:KB]
 	mSortingColumn(p.sort_column)
 {
 	if (p.sort_ascending.isProvided())
diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h
index cc29db0b702..098f3e5ffbd 100644
--- a/indra/llui/llscrolllistcolumn.h
+++ b/indra/llui/llscrolllistcolumn.h
@@ -91,6 +91,9 @@ class LLScrollListColumn
 	{
 		Optional<std::string>				name,
 											tool_tip;
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+		Optional<bool>						can_sort;
+// [/SL:KB]
 		Optional<std::string>				sort_column;
 		Optional<ESortDirection, SortNames>	sort_direction;
 		Optional<bool>						sort_ascending;
@@ -129,6 +132,9 @@ class LLScrollListColumn
 		Params()
 		:	name("name"),
 			tool_tip("tool_tip"),
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+			can_sort("can_sort", true),
+// [/SL:KB]
 			sort_column("sort_column"),
 			sort_direction("sort_direction"),
 			sort_ascending("sort_ascending", true),
@@ -154,6 +160,9 @@ class LLScrollListColumn
 	// If it ever gets any smarter than that, these should all become private
 	// with protected or public accessor methods added as needed. -MG
 	std::string				mName;
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	bool					mCanSort;
+// [/SL:KB]
 	std::string				mSortingColumn;
 	ESortDirection			mSortDirection;
 	LLUIString				mLabel;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index bd84e486c96..a76a000b767 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -151,6 +151,9 @@ LLScrollListCtrl::Params::Params()
 	mouse_wheel_opaque("mouse_wheel_opaque", false),
 	commit_on_keyboard_movement("commit_on_keyboard_movement", true),
 	commit_on_selection_change("commit_on_selection_change", false),
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	select_on_focus("select_on_focus", true),
+// [/SL:KB]
 	heading_height("heading_height"),
 	page_lines("page_lines", 0),
 	background_visible("background_visible"),
@@ -182,6 +185,12 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
 	mAllowKeyboardMovement(true),
 	mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
 	mCommitOnSelectionChange(p.commit_on_selection_change),
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.3
+	mCommitOnDelete(false),
+// [/SL:KB]
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	mSelectOnFocus(p.select_on_focus),
+// [/SL:KB]
 	mSelectionChanged(false),
 	mSelectionType(p.selection_type),
 	mNeedsScroll(false),
@@ -427,6 +436,13 @@ void LLScrollListCtrl::clearRows()
 	mLastSelected = NULL;
 	updateLayout();
 	mDirty = false; 
+
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.3
+	if (mCommitOnDelete)
+	{
+		onCommit();
+	}
+// [/SL:KB]
 }
 
 
@@ -1032,7 +1048,38 @@ void LLScrollListCtrl::deleteSingleItem(S32 target_index)
 	delete itemp;
 	mItemList.erase(mItemList.begin() + target_index);
 	dirtyColumns();
+
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.3
+	if (mCommitOnDelete)
+	{
+		onCommit();
+	}
+// [/SL:KB]
+}
+
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.5
+void LLScrollListCtrl::deleteSingleItem(LLScrollListItem* itemp)
+{
+	item_list::iterator itItem = std::find(mItemList.begin(), mItemList.end(), itemp);
+	if (mItemList.end() == itItem)
+	{
+		return;
+	}
+
+	if (mLastSelected == itemp)
+	{
+		mLastSelected = nullptr;
+	}
+	delete itemp;
+	mItemList.erase(itItem);
+	dirtyColumns();
+
+	if (mCommitOnDelete)
+	{
+		onCommit();
+	}
 }
+// [/SL:KB]
 
 //FIXME: refactor item deletion
 void LLScrollListCtrl::deleteItems(const LLSD& sd)
@@ -1057,6 +1104,13 @@ void LLScrollListCtrl::deleteItems(const LLSD& sd)
 	}
 
 	dirtyColumns();
+
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.3
+	if (mCommitOnDelete)
+	{
+		onCommit();
+	}
+// [/SL:KB]
 }
 
 void LLScrollListCtrl::deleteSelectedItems()
@@ -1077,6 +1131,13 @@ void LLScrollListCtrl::deleteSelectedItems()
 	}
 	mLastSelected = NULL;
 	dirtyColumns();
+
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.3
+	if (mCommitOnDelete)
+	{
+		onCommit();
+	}
+// [/SL:KB]
 }
 
 void LLScrollListCtrl::clearHighlightedItems()
@@ -3091,6 +3152,9 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params
 			params.tool_tip = column_params.tool_tip;
 			params.tab_stop = false;
 			params.visible = mDisplayColumnHeaders;
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+			params.font_halign = column_params.halign;
+// [/SL:KB]
 
 			if(column_params.header.image.isProvided())
 			{
@@ -3158,6 +3222,13 @@ const std::string& LLScrollListCtrl::getSortColumnName()
 		return LLStringUtil::null;
 }
 
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.5
+S32 LLScrollListCtrl::getSortColumnIndex() const
+{
+	return (!mSortColumns.empty()) ? mSortColumns.back().first : -1;
+}
+// [/SL:KB]
+
 BOOL LLScrollListCtrl::hasSortOrder() const
 {
 	return !mSortColumns.empty();
@@ -3233,6 +3304,17 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition
 	return addRow(item_params, pos);
 }
 
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, const LLScrollListItem::commit_signal_t::slot_type& cb, EAddPosition pos)
+{
+	LLScrollListItem::Params item_params;
+	LLParamSDParser parser;
+	parser.readSD(element, item_params);
+	item_params.commit_callback = cb;
+	return addRow(item_params, pos);
+}
+// [/SL:KB]
+
 LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
@@ -3288,6 +3370,13 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
 			cell_p.width = columnp->getWidth();
 		}
 
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+		if (item_p.commit_callback.isProvided())
+		{
+			cell_p.commit_callback = boost::bind(item_p.commit_callback(), item_p.value(), _1);
+		}
+// [/SL:KB]
+
 		LLScrollListCell* cell = LLScrollListCell::create(cell_p);
 
 		if (cell)
@@ -3417,7 +3506,10 @@ BOOL LLScrollListCtrl::operateOnAll(EOperation op)
 void LLScrollListCtrl::setFocus(BOOL b)
 {
 	// for tabbing into pristine scroll lists (Finder)
-	if (!getFirstSelected())
+//	if (!getFirstSelected())
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	if ( (mSelectOnFocus) && (!getFirstSelected()) )
+// [/SL:KB]
 	{
 		selectFirstItem();
 		//onCommit(); // SJB: selectFirstItem() will call onCommit() if appropriate
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index bef7bc72ef4..07b7cea4165 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -110,6 +110,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 		Optional<bool>	multi_select,
 						commit_on_keyboard_movement,
 						commit_on_selection_change,
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+						select_on_focus,
+// [/SL:KB]
 						mouse_wheel_opaque;
 
 		Optional<ESelectionType, SelectionTypeNames> selection_type;
@@ -185,6 +188,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	// "columns" => [ "column" => column name, "value" => value, "type" => type, "font" => font, "font-style" => style ], "id" => uuid
 	// Creates missing columns automatically.
 	virtual LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	virtual LLScrollListItem* addElement(const LLSD& element, const LLScrollListItem::commit_signal_t::slot_type& cb, EAddPosition pos = ADD_BOTTOM);
+// [/SL:KB]
 	virtual LLScrollListItem* addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& value, EAddPosition pos = ADD_BOTTOM);
 	virtual LLScrollListItem* addRow(const LLScrollListItem::Params& value, EAddPosition pos = ADD_BOTTOM);
 	// Simple add element. Takes a single array of:
@@ -229,6 +235,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	BOOL			selectItemAt(S32 x, S32 y, MASK mask);
 	
 	void			deleteSingleItem( S32 index );
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.5
+	void			deleteSingleItem(LLScrollListItem* itemp);
+// [/SL:KB]
 	void			deleteItems(const LLSD& sd);
 	void 			deleteSelectedItems();
 	void			deselectAllItems(BOOL no_commit_on_change = FALSE);	// by default, go ahead and commit on selection change
@@ -316,6 +325,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	S32  getRowPadding() const					{ return mColumnPadding; }
 	void setCommitOnKeyboardMovement(BOOL b)	{ mCommitOnKeyboardMovement = b; }
 	void setCommitOnSelectionChange(BOOL b)		{ mCommitOnSelectionChange = b; }
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.3
+	void setCommitOnDelete(BOOL b)				{ mCommitOnDelete = b; }
+// [/SL:KB]
 	void setAllowKeyboardMovement(BOOL b)		{ mAllowKeyboardMovement = b; }
 
 	void			setMaxSelectable(U32 max_selected) { mMaxSelectable = max_selected; }
@@ -410,6 +422,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }
 
 	const std::string&     getSortColumnName();
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.5
+	S32				getSortColumnIndex() const;
+// [/SL:KB]
 	BOOL			getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
 	BOOL			hasSortOrder() const;
 	void			clearSortOrder();
@@ -495,6 +510,12 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	bool			mAllowKeyboardMovement;
 	bool			mCommitOnKeyboardMovement;
 	bool			mCommitOnSelectionChange;
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-3.3
+	bool			mCommitOnDelete;
+// [/SL:KB]
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	bool			mSelectOnFocus = true;
+// [/SL:KB]
 	bool			mSelectionChanged;
 	ESelectionType	mSelectionType;
 	bool			mNeedsScroll;
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index a3398305b17..60f45963400 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -50,9 +50,17 @@ class LLScrollListItem
 {
 	friend class LLScrollListCtrl;
 public:
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	typedef boost::function<void(const LLSD& value, LLScrollListCell* cell)> commit_callback_t;
+	typedef boost::signals2::signal<void(const LLSD& value, LLScrollListCell* cell)> commit_signal_t;
+// [/SL:KB]
+
 	struct Params : public LLInitParam::Block<Params>
 	{
 		Optional<bool>		enabled;
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+		Optional<commit_callback_t> commit_callback;
+// [/SL:KB]
 		Optional<void*>		userdata;
 		Optional<LLSD>		value;
 		Optional<LLSD>		alt_value;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0d4b8e1f30d..cef9ed018c5 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -177,6 +177,7 @@ set(viewer_SOURCE_FILES
     lldebugview.cpp
     lldeferredsounds.cpp
     lldelayedgestureerror.cpp
+    llderenderlist.cpp
     lldirpicker.cpp
     lldonotdisturbnotificationstorage.cpp
     lldndbutton.cpp
@@ -229,6 +230,7 @@ set(viewer_SOURCE_FILES
     llfloaterbanduration.cpp
     llfloaterbeacons.cpp
     llfloaterbigpreview.cpp
+    llfloaterblocked.cpp
     llfloaterbuildoptions.cpp
     llfloaterbulkpermission.cpp
     llfloaterbump.cpp
@@ -902,6 +904,7 @@ set(viewer_HEADER_FILES
     lldebugview.h
     lldeferredsounds.h
     lldelayedgestureerror.h
+    llderenderlist.h
     lldirpicker.h
     lldonotdisturbnotificationstorage.h
     lldndbutton.h
@@ -954,6 +957,7 @@ set(viewer_HEADER_FILES
     llfloaterbanduration.h
     llfloaterbeacons.h
     llfloaterbigpreview.h
+    llfloaterblocked.h
     llfloaterbuildoptions.h
     llfloaterbulkpermission.h
     llfloaterbump.h
diff --git a/indra/newview/llagenthandler.cpp b/indra/newview/llagenthandler.cpp
index 736595b4882..f2b46e0e906 100644
--- a/indra/newview/llagenthandler.cpp
+++ b/indra/newview/llagenthandler.cpp
@@ -32,7 +32,8 @@
 #include "llfloaterreporter.h"
 #include "llmutelist.h"
 #include "llnotificationsutil.h"
-#include "llpanelblockedlist.h"
+//#include "llpanelblockedlist.h"
+#include "llfloaterblocked.h"
 
 class LLAgentHandler : public LLCommandHandler
 {
@@ -148,7 +149,8 @@ class LLAgentHandler : public LLCommandHandler
 				const std::string object_name = LLURI::unescape(params[2].asString());
 				LLMute mute(avatar_id, object_name, LLMute::OBJECT);
 				LLMuteList::getInstance()->add(mute);
-				LLPanelBlockedList::showPanelAndSelect(mute.mID);
+				LLFloaterBlocked::showMuteAndSelect(mute.mID);
+				//LLPanelBlockedList::showPanelAndSelect(mute.mID);
 			}
 			return true;
 		}
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 816984b296d..dbc5bcb178d 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -65,6 +65,7 @@
 #include "lluiconstants.h"
 #include "llstring.h"
 #include "llurlaction.h"
+#include "llfloaterblocked.h"
 // [SL:KB] - Patch: Chat-Alerts | Checked: 2012-07-10 (Catznip-3.3)
 #include "llaudioengine.h"
 #include "lltextparser.h"
@@ -190,8 +191,9 @@ class LLChatHistoryHeader: public LLPanel
 		{
 			LLMuteList::getInstance()->add(LLMute(getAvatarId(), mFrom, LLMute::OBJECT));
 
-			LLFloaterSidePanelContainer::showPanel("people", "panel_people",
-				LLSD().with("people_panel_tab_name", "blocked_panel").with("blocked_to_select", getAvatarId()));
+			LLFloaterBlocked::showMuteAndSelect(getAvatarId());
+			//LLFloaterSidePanelContainer::showPanel("people", "panel_people",
+			//	LLSD().with("people_panel_tab_name", "blocked_panel").with("blocked_to_select", getAvatarId()));
 		}
 		else if (level == "unblock")
 		{
diff --git a/indra/newview/llderenderlist.cpp b/indra/newview/llderenderlist.cpp
new file mode 100644
index 00000000000..78f28c481d6
--- /dev/null
+++ b/indra/newview/llderenderlist.cpp
@@ -0,0 +1,431 @@
+/** 
+ *
+ * Copyright (c) 2011-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 "llderenderlist.h"
+#include "llsdserialize.h"
+#include "llselectmgr.h"
+#include "lltrans.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llvocache.h"
+#include "llvoavatarself.h"
+#include "llworld.h"
+#include "pipeline.h"
+
+// ============================================================================
+// LLDerenderEntry
+//
+
+LLDerenderEntry::LLDerenderEntry(EEntryType eType, bool fPersists)
+	: m_eType(eType), m_nFlags(FLAG_NONE)
+{
+	if (fPersists)
+		m_nFlags |= FLAG_PERSIST;
+}
+
+LLDerenderEntry::LLDerenderEntry(EEntryType eType, const LLSD& sdData)
+	: m_eType(TYPE_NONE)
+{
+	// Sanity check
+	if ( (sdData.has("entry_type")) && (eType != sdData["entry_type"].asInteger()) )
+	{
+		LL_WARNS("Derender") << "Attempting to parse derender entry with reported type of " << sdData["entry_type"].asInteger() << " as type " << eType << LL_ENDL;
+		return;
+	}
+	m_eType = eType;
+
+	// Pre-flags legacy support
+	m_nFlags = (sdData.has("entry_flags")) ? sdData["entry_flags"].asInteger() : FLAG_PERSIST;
+
+	// Legacy support for object_id
+	m_idEntry = (sdData.has("entry_id")) ? sdData["entry_id"].asUUID() : sdData["object_id"].asUUID();
+
+	// Legacy support for object_name
+	m_strEntryName = (sdData.has("entry_name")) ? sdData["entry_name"].asString(): sdData["object_name"].asString();
+	if (m_strEntryName.empty())
+		m_strEntryName = LLTrans::getString("Unknown");
+}
+
+std::unique_ptr<LLDerenderEntry> LLDerenderEntry::fromLLSD(const LLSD& sdData)
+{
+	EEntryType eType = (sdData.has("entry_type")) ? (EEntryType)sdData["entry_type"].asInteger() : TYPE_OBJECT;
+	switch (eType)
+	{
+		case TYPE_OBJECT:
+			return std::make_unique<LLDerenderObject>(sdData);
+		case TYPE_AVATAR:
+			return std::make_unique<LLDerenderAvatar>(sdData);
+		default:
+			return nullptr;
+	}
+}
+
+LLSD LLDerenderEntry::toLLSD() const
+{
+	LLSD sdData;
+
+	sdData["entry_type"] = m_eType;
+	sdData["entry_flags"] = m_nFlags;
+	sdData["entry_name"] = m_strEntryName;
+	sdData["entry_id"] = m_idEntry;
+
+	return sdData;
+}
+
+// ============================================================================
+// LLDerenderObject
+//
+
+LLDerenderObject::LLDerenderObject(const LLSelectNode* pNode, bool fPersist)
+	: LLDerenderEntry(TYPE_OBJECT, fPersist), idRegion(0), idRootLocal(0)
+{
+	//
+	// Fill in all object related information
+	//
+	const LLViewerObject* pObj = (pNode) ? pNode->getObject() : nullptr;
+	if (!pObj)
+		return;
+
+	m_idEntry = pObj->getID();
+	m_strEntryName = ((pNode->mValid) && (!pNode->mName.empty())) ? pNode->mName : LLTrans::getString("Unknown");
+
+	idRootLocal = pObj->getLocalID();
+	for (LLViewerObject::const_child_list_t::const_iterator itChild = pObj->getChildren().begin(), endChild = pObj->getChildren().end(); itChild != endChild; ++itChild)
+		idsChildLocal.push_back((*itChild)->getLocalID());
+
+	//
+	// Fill in all region related information
+	//
+	if (const LLViewerRegion* pRegion = pObj->getRegion())
+	{
+		idRegion = pRegion->getHandle();
+		posRegion = pObj->getPositionRegion();
+		strRegionName = pRegion->getName();
+	}
+	if (strRegionName.empty())
+	{
+		strRegionName = LLTrans::getString("Unknown");
+	}
+}
+
+LLDerenderObject::LLDerenderObject(const LLSD& sdData)
+	: LLDerenderEntry(TYPE_OBJECT, sdData), idRegion(0), idRootLocal(0)
+{
+	if (sdData.has("region_pos"))
+		posRegion.setValue(sdData["region_pos"]);
+	strRegionName = (sdData.has("region_name")) ? sdData["region_name"].asString() : LLTrans::getString("Unknown");
+}
+
+LLSD LLDerenderObject::toLLSD() const
+{
+	LLSD sdData = LLDerenderEntry::toLLSD();
+
+	sdData["region_name"] = strRegionName;
+	sdData["region_pos"] = posRegion.getValue();
+
+	return sdData;
+}
+
+// ============================================================================
+// LLDerenderList
+//
+
+LLDerenderList::change_signal_t LLDerenderList::s_ChangeSignal;
+std::string LLDerenderList::s_PersistFilename = "derender_list.llsd";
+
+LLDerenderList::LLDerenderList()
+{
+	load();
+}
+
+LLDerenderList::~LLDerenderList()
+{
+}
+
+void LLDerenderList::load()
+{
+	llifstream fileDerender(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, s_PersistFilename));
+	if (!fileDerender.is_open())
+	{
+		LL_WARNS() << "Can't open derender list file \"" << s_PersistFilename << "\" for reading" << LL_ENDL;
+		return;
+	}
+
+	m_Entries.clear();
+
+	LLSD inSD;
+	S32 ret = LLSDSerialize::fromNotation(inSD, fileDerender, LLSDSerialize::SIZE_UNLIMITED);
+	fileDerender.close();
+	if (ret == LLSDParser::PARSE_FAILURE || !inSD.isArray())
+	{
+		return;
+	}
+
+	for (const LLSD& sdEntry : inSD.array())
+	{
+		auto pEntry = LLDerenderEntry::fromLLSD(sdEntry);
+		if (pEntry->isValid())
+			m_Entries.push_back(std::move(pEntry));
+	}
+}
+
+void LLDerenderList::save() const
+{
+	llofstream fileDerender(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, s_PersistFilename));
+	if (!fileDerender.is_open())
+	{
+		LL_WARNS() << "Can't open derender list file \"" << s_PersistFilename << "\" for writing" << LL_ENDL;
+		return;
+	}
+
+	LLSD outSD;
+	for (const auto& pEntry : m_Entries)
+	{
+		if (pEntry->isPersistent())
+			outSD.append(pEntry->toLLSD());
+	}
+
+	LLSDSerialize::toNotation(outSD, fileDerender);
+
+	fileDerender.close();
+}
+
+// ============================================================================
+// Entry helper functions
+//
+
+LLDerenderList::entry_list_t::iterator LLDerenderList::findEntry(LLDerenderEntry::EEntryType eType, const LLUUID& idEntry)
+{
+	return std::find_if(m_Entries.begin(), m_Entries.end(), [eType, &idEntry](const auto& e) { return (eType == e->getType()) && (idEntry == e->getID()); });
+}
+
+LLDerenderList::entry_list_t::iterator LLDerenderList::findObjectEntry(U64 idRegion, const LLUUID& idObject, U32 idRootLocal)
+{
+	// NOTE: 'idRootLocal' will be 0 for the root prim itself and is the only time we need to compare against 'idObject'
+	return std::find_if(m_Entries.begin(), m_Entries.end(), 
+						[&idRegion, &idObject, &idRootLocal](const std::unique_ptr<LLDerenderEntry>& e)
+						{ return (LLDerenderEntry::TYPE_OBJECT == e->getType()) && 
+						         ( ((idRootLocal) && (idRegion == ((LLDerenderObject*)e.get())->idRegion) && (idRootLocal == ((LLDerenderObject*)e.get())->idRootLocal)) || (idObject == e->getID()) ); });
+}
+
+void LLDerenderList::removeObject(LLDerenderEntry::EEntryType eType, const LLUUID& idObject)
+{
+	uuid_vec_t idsObject;
+	idsObject.push_back(idObject);
+	removeObjects(eType, idsObject);
+}
+
+void LLDerenderList::removeObjects(LLDerenderEntry::EEntryType eType, const uuid_vec_t& idsObject)
+{
+	bool fSave = false;
+	std::map<LLViewerRegion*, std::list<U32>> idRegionObjectMap; // TYPE_OBJECT
+
+	for (const auto& idObject : idsObject)
+	{
+		entry_list_t::iterator itEntry = findEntry(eType, idObject);
+		if (m_Entries.end() == itEntry)
+			continue;
+
+		const auto& pEntry = *itEntry;
+		switch (eType)
+		{
+			case LLDerenderEntry::TYPE_OBJECT:
+				{
+					LLDerenderObject* pObjEntry = static_cast<LLDerenderObject*>(pEntry.get());
+					if (0 == pObjEntry->idRegion)
+						continue;
+
+					if (LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(pObjEntry->idRegion))
+					{
+						std::list<U32>& idsLocal = idRegionObjectMap[pRegion];
+						if (pObjEntry->idRootLocal)
+							idsLocal.push_back(pObjEntry->idRootLocal);
+						idsLocal.splice(idsLocal.end(), pObjEntry->idsChildLocal);
+					}
+				}
+				break;
+		}
+		fSave |= pEntry->isPersistent();
+
+		m_Entries.erase(itEntry);
+	}
+
+	// TYPE_OBJECT
+	for (const auto& data_pair : idRegionObjectMap)
+	{
+		LLViewerRegion* pRegion = data_pair.first;
+		for (U32 local_id : data_pair.second)
+			pRegion->addCacheMissFull(local_id);
+		pRegion->requestCacheMisses();
+	}
+
+	if (fSave)
+		save();
+	s_ChangeSignal();
+}
+
+// ============================================================================
+// Object handling functions
+//
+
+bool LLDerenderList::addSelection(bool fPersist, std::vector<LLUUID>* pIdList)
+{
+	if (pIdList)
+	{
+		pIdList->clear();
+	}
+
+	LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+
+	LLObjectSelection::root_iterator itObj = hSel->root_begin();
+	while (hSel->root_end() != itObj)
+	{
+		const LLSelectNode* pNode = *itObj++;
+		if (!canAdd(pNode->getObject()))
+			continue;
+
+		auto uniqueEntry = std::make_unique<LLDerenderObject>(pNode, fPersist);
+		if (!uniqueEntry || (isDerendered(uniqueEntry->getID())) || (gAgentID == uniqueEntry->getID()) )
+			continue;
+
+		auto pEntry = uniqueEntry.get();
+		m_Entries.push_back(std::move(uniqueEntry));
+		
+		if (pIdList)
+		{
+			pIdList->push_back(pEntry->getID());
+		}
+
+		LLViewerObject* pObj = pNode->getObject();
+		if (pObj)
+		{
+			// Display green bubble on kill [see process_kill_object()]
+			if (gShowObjectUpdates)
+				gPipeline.addDebugBlip(pObj->getPositionAgent(), LLColor4(0.f, 1.f, 0.f, 1.f));
+			// Keep the order of these the same as process_kill_object()
+			LLViewerRegion* pObjRegion = pObj->getRegion(); U32 idObjLocal = pObj->getLocalID();
+			gObjectList.killObject(pObj);
+			if ( (LLViewerRegion::sVOCacheCullingEnabled) && (pObjRegion) )
+				pObjRegion->killCacheEntry(idObjLocal);
+			LLSelectMgr::getInstance()->removeObjectFromSelections(pEntry->getID());
+		}
+	}
+
+	if (fPersist)
+		save();
+	s_ChangeSignal();
+	return (!pIdList) || (!pIdList->empty());
+}
+
+bool LLDerenderList::canAdd(const LLViewerObject* pObj)
+{
+	// Allow derendering if:
+	return 
+		//   - the object isn't a child prim
+		(pObj) && (pObj->getRootEdit() == pObj) &&
+		//   - the object isn't currently sat on by the user
+		( (isAgentAvatarValid()) && (!pObj->isChild(gAgentAvatarp)) ) &&
+		//   - the object isn't an attachment
+		(!pObj->isAttachment());
+}
+
+bool LLDerenderList::canAddSelection() 
+{
+	struct CanDerender : public LLSelectedObjectFunctor
+	{
+		/*virtual*/ bool apply(LLViewerObject* pObj) { return LLDerenderList::canAdd(pObj); }
+	} f;
+	LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+	return (hSel.notNull()) && (0 != hSel->getRootObjectCount()) && (hSel->applyToRootObjects(&f, false));
+}
+
+LLDerenderObject* LLDerenderList::getObjectEntry(const LLUUID& idObject) /*const*/
+{
+	LLDerenderList::entry_list_t::iterator itEntry = findEntry(LLDerenderEntry::TYPE_OBJECT, idObject);
+	return (m_Entries.end() != itEntry) ? (LLDerenderObject*)itEntry->get() : NULL;
+}
+
+LLDerenderObject* LLDerenderList::getObjectEntry(U64 idRegion, const LLUUID& idObject, U32 idRootLocal) /*const*/
+{
+	LLDerenderList::entry_list_t::const_iterator itEntry = findObjectEntry(idRegion, idObject, idRootLocal);
+	return (m_Entries.end() != itEntry) ? (LLDerenderObject*)itEntry->get() : NULL;
+}
+
+bool LLDerenderList::processObjectUpdate(U64 idRegion, const LLUUID& idObject, const LLVOCacheEntry* pCacheEntry)
+{
+	// Used by OUT_FULL_CACHED
+	if (!pCacheEntry->isChild())
+	{
+		// We know it's a root prim so we can skip looking up its parent
+		LLDerenderObject* pObjEntry = getObjectEntry(idObject);
+		if (!pObjEntry)
+		{
+			return false;	// Not a derendered object
+		}
+
+		// Update root prim information
+		pObjEntry->idRegion = idRegion;
+		pObjEntry->idRootLocal = pCacheEntry->getLocalID();
+
+		// We can use the object cache entry to give us all child prims IDs
+		pObjEntry->idsChildLocal.clear();
+		for (LLVOCacheEntry::vocache_entry_set_t::const_iterator itChild = pCacheEntry->getChildrenBegin(), endChild = pCacheEntry->getChildrenEnd(); itChild != endChild; ++itChild)
+			pObjEntry->idsChildLocal.push_back((*itChild)->getLocalID());
+
+		return true;
+	}
+	
+	// Child prim so perform normal processing
+	return processObjectUpdate(idRegion, idObject, pCacheEntry->getLocalID(), pCacheEntry->getDP()->getBuffer());
+}
+
+bool LLDerenderList::processObjectUpdate(U64 idRegion, const LLUUID& idObject, U32 idObjectLocal, U32 idRootLocal)
+{
+	// Used by OUT_FULL
+	LLDerenderObject* pObjEntry = (0 == idRootLocal) ? getObjectEntry(idObject) : getObjectEntry(idRegion, idObject, idRootLocal);
+	if (pObjEntry)
+	{
+		if (0 != idRootLocal)
+		{
+			// We're updating a child prim
+			if (pObjEntry->idsChildLocal.end() == std::find(pObjEntry->idsChildLocal.begin(), pObjEntry->idsChildLocal.end(), idObjectLocal))
+				pObjEntry->idsChildLocal.push_back(idObjectLocal);
+		}
+		else
+		{
+			// We're updating the root prim
+			pObjEntry->idRegion = idRegion;
+			pObjEntry->idRootLocal = idObjectLocal;
+		}
+		return true;
+	}
+	return false;
+}
+
+bool LLDerenderList::processObjectUpdate(U64 idRegion, const LLUUID& idObject, U32 idObjectLocal, const U8* pBuffer)
+{
+	// Used by OUT_FULL_COMPRESSED
+	U32 idRootLocal = 0, nMask = 0;
+	htolememcpy(&nMask, pBuffer + 64, MVT_U32, 4);			// "SpecialCode"
+	if (nMask & 0x20)
+		htolememcpy(&idRootLocal, pBuffer + 84, MVT_U32, 4);	// "ParentID"
+	return processObjectUpdate(idRegion, idObject, idObjectLocal, idRootLocal);
+}
+
+// ============================================================================
diff --git a/indra/newview/llderenderlist.h b/indra/newview/llderenderlist.h
new file mode 100644
index 00000000000..3a307d3c2b4
--- /dev/null
+++ b/indra/newview/llderenderlist.h
@@ -0,0 +1,191 @@
+/** 
+ *
+ * Copyright (c) 2011-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 LL_DERENDERLIST_H
+#define LL_DERENDERLIST_H
+
+#include "llsingleton.h"
+#include "lluuid.h"
+
+// ============================================================================
+// Forward declarations
+//
+
+class LLSelectNode;
+class LLVOCacheEntry;
+class LLViewerObject;
+
+// ============================================================================
+// LLDerenderEntry
+//
+
+class LLDerenderEntry
+{
+	/*
+	 * Type declarations
+	 */
+public:
+	enum EEntryType
+	{
+		TYPE_OBJECT = 0,
+		TYPE_AVATAR,
+		TYPE_ALL,
+		TYPE_NONE
+	};
+
+	enum
+	{
+		FLAG_NONE    = 0x00,
+		FLAG_PERSIST = 0x01
+	};
+
+	/*
+	 * Constructors
+	 */
+protected:
+	LLDerenderEntry(EEntryType eType, bool fPersists);
+	LLDerenderEntry(EEntryType eType, const LLSD& sdData);
+public:
+	virtual ~LLDerenderEntry() {}
+
+	/*
+	 * Member functions
+	 */
+public:
+	std::string   getName() const { return m_strEntryName; }
+	const LLUUID& getID() const   { return m_idEntry; }
+	EEntryType    getType() const { return m_eType; }
+	bool          isPersistent() const { return m_nFlags & FLAG_PERSIST; }
+	bool          isValid() const { return (m_eType != TYPE_NONE) && (m_idEntry.notNull()); }
+
+	static std::unique_ptr<LLDerenderEntry> fromLLSD(const LLSD& sdData);
+	virtual LLSD            toLLSD() const;
+
+	/*
+	 * Member variables
+	 */
+protected:
+	EEntryType  m_eType;
+	S32         m_nFlags;
+	LLUUID      m_idEntry;
+	std::string m_strEntryName;
+};
+
+// ============================================================================
+// LLDerenderObject
+//
+
+class LLDerenderObject : public LLDerenderEntry
+{
+	/*
+	 * Constructors
+	 */
+public:
+	LLDerenderObject(const LLSelectNode* pNode, bool fPersist);
+	LLDerenderObject(const LLSD& sdData);
+
+	/*
+	 * Base class overrides
+	 */
+public:
+	/*virtual*/ LLSD toLLSD() const;
+
+	/*
+	 * Member variables
+	 */
+public:
+	std::string    strRegionName;		// Region name
+	LLVector3      posRegion;			// Position of the object on the region
+	U64            idRegion;			// Region handle
+	U32            idRootLocal;			// Local object ID of the root (region-specific)
+	std::list<U32> idsChildLocal;		// Local object ID of all child prims
+};
+
+// ============================================================================
+// LLDerenderAvatar
+//
+
+class LLDerenderAvatar : public LLDerenderEntry
+{
+public:
+	LLDerenderAvatar(bool fPersists)
+		: LLDerenderEntry(TYPE_AVATAR, fPersists)
+	{
+	}
+	LLDerenderAvatar(const LLSD& sdData)
+		: LLDerenderEntry(TYPE_AVATAR, sdData)
+	{
+	}
+};
+
+// ============================================================================
+// LLDerenderList
+//
+
+class LLDerenderList : public LLSingleton<LLDerenderList>
+{
+	LLSINGLETON(LLDerenderList);
+protected:
+	/*virtual*/ ~LLDerenderList();
+
+	void load();
+	void save() const;
+
+	/*
+	 * Entry helper functions
+	 */
+public:
+	using entry_list_t = std::list<std::unique_ptr<LLDerenderEntry>>;
+
+	const entry_list_t& getEntries() const { return m_Entries; }
+	void removeObject(LLDerenderEntry::EEntryType eType, const LLUUID& idObject);
+	void removeObjects(LLDerenderEntry::EEntryType eType, const uuid_vec_t& idsObject);
+protected:
+	entry_list_t::iterator findEntry(LLDerenderEntry::EEntryType eType, const LLUUID& idEntry);
+	entry_list_t::iterator findObjectEntry(U64 idRegion, const LLUUID& idObject, U32 idRootLocal);
+
+	/*
+	 * Object helper functions
+	 */
+public:
+	bool              addSelection(bool fPersist, std::vector<LLUUID>* pIdList = NULL);
+	static bool       canAdd(const LLViewerObject* pObj);
+	static bool       canAddSelection();
+	bool              processObjectUpdate(U64 idRegion, const LLUUID& idObject, const LLVOCacheEntry* pEntry);
+	bool              processObjectUpdate(U64 idRegion, const LLUUID& idObject, U32 idObjectLocal, U32 idRootLocal);
+	bool              processObjectUpdate(U64 idRegion, const LLUUID& idObject, U32 idObjectLocal, const U8* pBuffer);
+protected:
+	LLDerenderObject* getObjectEntry(const LLUUID& idObject) /*const*/;
+	LLDerenderObject* getObjectEntry(U64 idRegion, const LLUUID& idObject, U32 idRootLocal) /*const*/;
+	bool              isDerendered(const LLUUID& idObject) /*const*/                                { return getObjectEntry(idObject) != NULL; }
+	bool              isDerendered(U64 idRegion, const LLUUID& idObject, U32 idRootLocal) /*const*/ { return getObjectEntry(idRegion, idObject, idRootLocal) != NULL; }
+
+	/*
+	 * Static member functions
+	 */
+public:
+	typedef boost::signals2::signal<void()> change_signal_t;
+	static boost::signals2::connection setChangeCallback(const change_signal_t::slot_type& cb) { return s_ChangeSignal.connect(cb); }
+
+protected:
+	entry_list_t m_Entries;
+
+	static change_signal_t	s_ChangeSignal;
+	static std::string		s_PersistFilename;
+};
+
+// ============================================================================
+
+#endif // LL_DERENDERLIST_H
diff --git a/indra/newview/llfloaterblocked.cpp b/indra/newview/llfloaterblocked.cpp
new file mode 100644
index 00000000000..4b06b385014
--- /dev/null
+++ b/indra/newview/llfloaterblocked.cpp
@@ -0,0 +1,791 @@
+/**
+ *
+ * Copyright (c) 2012-2017, 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 "llavatarname.h"
+#include "llavatarnamecache.h"
+#include "llcallbacklist.h"
+#include "llderenderlist.h"
+#include "llfiltereditor.h"
+#include "llfloateravatarpicker.h"
+#include "llfloaterblocked.h"
+#include "llfloaterreg.h"
+#include "lllistcontextmenu.h"
+#include "llmenugl.h"
+#include "llnamelistctrl.h"
+#include "llnotificationsutil.h"
+#include "llpanelblockedlist.h"
+#include "llscrolllistctrl.h"
+#include "lltabcontainer.h"
+#include "lltrans.h"
+#include "llviewercontrol.h"
+#include "llviewermenu.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatar.h"
+
+#include <boost/algorithm/string.hpp>
+
+// ============================================================================
+// Constants
+//
+
+const std::string BLOCKED_PARAM_NAME  = "blocked_to_select";
+const std::string DERENDER_PARAM_NAME = "derender_to_select";
+const std::string EXCEPTION_PARAM_NAME = "exception_to_select";
+const std::string BLOCKED_TAB_NAME = "mute_tab";
+const std::string DERENDER_TAB_NAME = "derender_tab";
+const std::string EXCEPTION_TAB_NAME = "avatar_rendering_tab";
+
+// ============================================================================
+// LLPanelBlockList
+//
+
+static LLPanelInjector<LLPanelBlockList> t_panel_blocked_list("panel_block_list");
+
+LLPanelBlockList::LLPanelBlockList()
+	: LLPanel()
+{
+	mCommitCallbackRegistrar.add("Block.AddAvatar", boost::bind(&LLPanelBlockList::onAddAvatar, this, _1));
+	mCommitCallbackRegistrar.add("Block.AddByName",	boost::bind(&LLPanelBlockList::onAddByName));
+	mCommitCallbackRegistrar.add("Block.Remove", boost::bind(&LLPanelBlockList::onRemoveSelection, this));
+}
+
+LLPanelBlockList::~LLPanelBlockList()
+{
+	LLMuteList::getInstance()->removeObserver(this);
+}
+
+// virtual
+BOOL LLPanelBlockList::postBuild()
+{
+	setVisibleCallback(boost::bind(&LLPanelBlockList::removePicker, this));
+
+	m_pBlockList = findChild<LLScrollListCtrl>("block_list");
+	m_pBlockList->setCommitOnDelete(true);
+	m_pBlockList->setCommitOnSelectionChange(true);
+	m_pBlockList->setCommitCallback(boost::bind(&LLPanelBlockList::onSelectionChange, this));
+
+	// Restore last sort order
+	if (U32 nSortValue = gSavedSettings.getU32("BlockMuteSortOrder"))
+		m_pBlockList->sortByColumnIndex(nSortValue >> 4, nSortValue & 0xF);
+	m_pBlockList->setSortChangedCallback(boost::bind(&LLPanelBlockList::onColumnSortChange, this));
+
+	m_pTrashBtn = findChild<LLButton>("block_trash_btn");
+
+	LLMuteList::getInstance()->addObserver(this);
+
+	return TRUE;
+}
+
+// virtual
+void LLPanelBlockList::onOpen(const LLSD& sdParam)
+{
+	refresh();
+
+	if ( (sdParam.has(BLOCKED_PARAM_NAME)) && (sdParam[BLOCKED_PARAM_NAME].asUUID().notNull()) )
+	{
+		LLMute muteEntry(sdParam[BLOCKED_PARAM_NAME].asUUID());
+		selectEntry(muteEntry);
+	}
+}
+
+void LLPanelBlockList::refresh()
+{
+	const LLSD& sdSel = m_pBlockList->getSelectedValue();
+
+	LLSD sdGenericRow; LLSD& sdGenericColumns = sdGenericRow["columns"];
+	sdGenericColumns[0]["column"] = "item_name"; sdGenericColumns[0]["type"] = "text";
+	sdGenericColumns[1]["column"] = "item_type"; sdGenericColumns[1]["type"] = "text";
+
+	LLSD sdAgentRow(sdGenericRow); LLSD& sdAgentColumns = sdAgentRow["columns"];
+	sdAgentColumns[2]["column"] = "item_text"; sdAgentColumns[2]["type"] = "checkbox";
+	sdAgentColumns[3]["column"] = "item_voice"; sdAgentColumns[3]["type"] = "checkbox";
+	sdAgentColumns[4]["column"] = "item_particles"; sdAgentColumns[4]["type"] = "checkbox";
+	sdAgentColumns[5]["column"] = "item_sounds"; sdAgentColumns[5]["type"] = "checkbox";
+
+	m_pBlockList->deleteAllItems();
+	const std::vector<LLMute> muteEntries = LLMuteList::getInstance()->getMutes();
+	for (const LLMute& muteEntry : muteEntries)
+	{
+		if ( (!m_strFilter.empty()) && (!boost::icontains(muteEntry.mName, m_strFilter)) )
+			continue;
+
+		switch (muteEntry.mType)
+		{
+			case LLMute::AGENT:
+				{
+					sdAgentRow["value"] = LLSD().with("id", muteEntry.mID).with("name", muteEntry.mName);
+					sdAgentColumns[0]["value"] = muteEntry.mName;
+					sdAgentColumns[1]["value"] = muteEntry.getDisplayType();
+					sdAgentColumns[2]["value"] = (muteEntry.mFlags & LLMute::flagTextChat) == 0;
+					sdAgentColumns[3]["value"] = (muteEntry.mFlags & LLMute::flagVoiceChat) == 0;
+					sdAgentColumns[4]["value"] = (muteEntry.mFlags & LLMute::flagParticles) == 0;
+					sdAgentColumns[5]["value"] = (muteEntry.mFlags & LLMute::flagObjectSounds) == 0;
+					m_pBlockList->addElement(sdAgentRow, boost::bind(&LLPanelBlockList::onToggleMuteFlag, this, _1, _2), ADD_BOTTOM);
+				}
+				break;
+			default:
+				{
+					sdGenericRow["value"] = LLSD().with("id", muteEntry.mID).with("name", muteEntry.mName);
+					sdGenericColumns[0]["value"] = muteEntry.mName;
+					sdGenericColumns[1]["value"] = muteEntry.getDisplayType();
+					m_pBlockList->addElement(sdGenericRow, ADD_BOTTOM);
+				}
+				break;
+		}
+	}
+	selectEntry(sdSel);
+}
+
+void LLPanelBlockList::removePicker()
+{
+	if (m_hPicker.get())
+	{
+		m_hPicker.get()->closeFloater();
+	}
+}
+
+void LLPanelBlockList::selectEntry(const LLMute& muteEntry)
+{
+	const std::vector<LLScrollListItem*> muteItems = m_pBlockList->getAllData();
+	for (auto itItem = muteItems.begin(); itItem != muteItems.end(); ++itItem)
+	{
+		const LLSD& sdValue = (*itItem)->getValue();
+		if ( (muteEntry.mID == sdValue["id"].asUUID()) && ((muteEntry.mName.empty()) ||(muteEntry.mName == sdValue["name"].asString())) )
+		{
+			S32 idxItem = itItem - muteItems.begin();
+			if (idxItem != m_pBlockList->getFirstSelectedIndex())
+			{
+				m_pBlockList->deselectAllItems();
+				m_pBlockList->selectNthItem(idxItem);
+				break;
+			}
+		}
+	}
+}
+
+void LLPanelBlockList::setFilterString(const std::string& strFilter)
+{
+	m_strFilter = strFilter;
+	refresh();
+}
+
+void LLPanelBlockList::updateButtons()
+{
+	bool fHasSelection = (nullptr != m_pBlockList->getFirstSelected());
+	m_pTrashBtn->setEnabled(fHasSelection);
+}
+
+void LLPanelBlockList::onChange()
+{
+	if (m_fRefreshOnChange)
+	{
+		refresh();
+	}
+}
+
+void LLPanelBlockList::onAddAvatar(LLUICtrl* pCtrl)
+{
+	if (!m_hPicker.isDead())
+	{
+		m_hPicker.get()->setVisibleAndFrontmost(true);
+		return;
+	}
+
+	if (LLFloater* pRootFloater = gFloaterView->getParentFloater(pCtrl))
+	{
+		LLFloaterAvatarPicker* pPicker = LLFloaterAvatarPicker::show(
+			boost::bind(&LLPanelBlockList::onAddAvatarCallback, _1, _2),
+			false /*allow_multiple*/, true /*close_on_select*/, false /*skip_agent*/, pRootFloater->getName(), pCtrl);
+		pRootFloater->addDependentFloater(pPicker);
+		m_hPicker = pPicker->getHandle();
+	}
+}
+
+// static
+void LLPanelBlockList::onAddAvatarCallback(const uuid_vec_t& idAgents, const std::vector<LLAvatarName>& avAgents)
+{
+	if ( (idAgents.empty()) || (avAgents.empty()) )
+	{
+		return;
+	}
+
+	LLMute mute(idAgents[0], avAgents[0].getLegacyName(), LLMute::AGENT);
+	if (LLMuteList::getInstance()->add(mute))
+	{
+		LLFloaterBlocked::showMuteAndSelect(mute.mID);
+	}
+}
+
+// static
+void LLPanelBlockList::onAddByName()
+{
+	LLFloaterGetBlockedObjectName::show(&LLPanelBlockList::onAddByNameCallback);
+}
+
+// static
+void LLPanelBlockList::onAddByNameCallback(const std::string& strBlockName)
+{
+	if (strBlockName.empty())
+	{
+		return;
+	}
+
+	LLMute mute(LLUUID::null, strBlockName, LLMute::BY_NAME);
+	if (!LLMuteList::getInstance()->add(mute))
+	{
+		LLNotificationsUtil::add("MuteByNameFailed");
+	}
+}
+
+void LLPanelBlockList::onRemoveSelection()
+{
+	m_fRefreshOnChange = false;
+
+	std::vector<LLScrollListItem*> selItems = m_pBlockList->getAllSelected();
+	for (std::vector<LLScrollListItem*>::iterator itItem = selItems.begin(); itItem != selItems.end(); ++itItem)
+	{
+		LLScrollListItem* pSelItem = *itItem; const LLSD sdValue = pSelItem->getValue();
+
+		LLMute selMute(sdValue["id"].asUUID(), sdValue["name"].asString());
+		if (LLMuteList::getInstance()->remove(selMute))
+		{
+			m_pBlockList->deleteSingleItem(pSelItem);
+		}
+	}
+
+	m_fRefreshOnChange = true;
+}
+
+void LLPanelBlockList::onColumnSortChange()
+{
+	U32 nSortValue = 0;
+
+	S32 idxColumn = m_pBlockList->getSortColumnIndex();
+	if (-1 != idxColumn)
+	{
+		nSortValue = idxColumn << 4 | ((m_pBlockList->getSortAscending()) ? 1 : 0);
+	}
+
+	gSavedSettings.setU32("BlockMuteSortOrder", nSortValue);
+}
+
+void LLPanelBlockList::onIdleRefresh(LLHandle<LLPanel> hPanel)
+{
+	if (!hPanel.isDead())
+	{
+		((LLPanelBlockList*)hPanel.get())->refresh();
+	}
+}
+
+void LLPanelBlockList::onSelectionChange()
+{
+	updateButtons();
+}
+
+void LLPanelBlockList::onToggleMuteFlag(const LLSD& sdValue, const LLScrollListCell* pCell)
+{
+	if (!pCell)
+		return;
+
+	LLMute muteEntry(sdValue["id"].asUUID(), sdValue["name"].asString(), LLMute::AGENT); U32 muteFlag = 0;
+
+	const std::string& strColumnName = pCell->getColumnName();
+	if ("item_text" == strColumnName)
+		muteFlag = LLMute::flagTextChat;
+	else if ("item_voice" == strColumnName)
+		muteFlag = LLMute::flagVoiceChat;
+	else if ("item_particles" == strColumnName)
+		muteFlag = LLMute::flagParticles;
+	else if ("item_sounds" == strColumnName)
+		muteFlag = LLMute::flagObjectSounds;
+
+	if (muteFlag)
+	{
+		m_fRefreshOnChange = false;
+		if (pCell->getValue().asBoolean())
+			LLMuteList::getInstance()->add(muteEntry, muteFlag);
+		else
+			LLMuteList::getInstance()->remove(muteEntry, muteFlag);
+		m_fRefreshOnChange = true;
+
+		selectEntry(muteEntry);
+
+		// Refreshing now will invalidate an iterator upstream so do it on the next idle tick
+		doOnIdleOneTime(boost::bind(&LLPanelBlockList::onIdleRefresh, getHandle()));
+	}
+}
+
+// ============================================================================
+// LLPanelDerenderList
+//
+
+static LLPanelInjector<LLPanelDerenderList> t_panel_derender_list("panel_derender_list");
+
+LLPanelDerenderList::LLPanelDerenderList()
+	: LLPanel()
+	, m_pDerenderList(NULL)
+{
+}
+
+LLPanelDerenderList::~LLPanelDerenderList()
+{
+	m_DerenderChangeConn.disconnect();
+}
+
+BOOL LLPanelDerenderList::postBuild()
+{
+	m_pDerenderList = findChild<LLScrollListCtrl>("derender_list");
+	m_pDerenderList->setCommitCallback(boost::bind(&LLPanelDerenderList::onSelectionChange, this));
+	m_pDerenderList->setCommitOnDelete(true);
+	m_pDerenderList->setCommitOnSelectionChange(true);
+
+	// Restore last sort order
+	U32 nSortValue = gSavedSettings.getU32("BlockDerenderSortOrder");
+	if (nSortValue)
+	{
+		m_pDerenderList->sortByColumnIndex(nSortValue >> 4, nSortValue & 0xF);
+	}
+	m_pDerenderList->setSortChangedCallback(boost::bind(&LLPanelDerenderList::onColumnSortChange, this));
+
+	m_DerenderChangeConn = LLDerenderList::setChangeCallback(boost::bind(&LLPanelDerenderList::refresh, this));
+	findChild<LLUICtrl>("derender_trash_btn")->setCommitCallback(boost::bind(&LLPanelDerenderList::onSelectionRemove, this));
+
+	return TRUE;
+}
+
+void LLPanelDerenderList::onOpen(const LLSD& sdParam)
+{
+	refresh();
+
+	if ( (sdParam.has(DERENDER_PARAM_NAME)) && (sdParam[DERENDER_PARAM_NAME].asUUID().notNull()) )
+	{
+		m_pDerenderList->selectByID(sdParam[DERENDER_PARAM_NAME].asUUID());
+	}
+}
+
+void LLPanelDerenderList::onColumnSortChange()
+{
+	U32 nSortValue = 0;
+	
+	S32 idxColumn = m_pDerenderList->getSortColumnIndex();
+	if (-1 != idxColumn)
+	{
+		nSortValue = idxColumn << 4 | ((m_pDerenderList->getSortAscending()) ? 1 : 0);
+	}
+
+	gSavedSettings.setU32("BlockDerenderSortOrder", nSortValue);
+}
+
+void LLPanelDerenderList::onSelectionChange()
+{
+	bool hasSelected = (NULL != m_pDerenderList->getFirstSelected());
+	getChildView("derender_trash_btn")->setEnabled(hasSelected);
+}
+
+void LLPanelDerenderList::onSelectionRemove()
+{
+	std::vector<LLScrollListItem*> selItems = m_pDerenderList->getAllSelected(); uuid_vec_t idsObject;
+//	std::for_each(selItems.begin(), selItems.end(), [&idsObject](const LLScrollListItem* i) { idsObject.push_back(i->getValue().asUUID()); });
+	for (std::vector<LLScrollListItem*>::iterator itItem = selItems.begin(); itItem != selItems.end(); ++itItem)
+	{
+		idsObject.push_back((*itItem)->getValue().asUUID());
+	}
+
+	LLDerenderList::instance().removeObjects(LLDerenderEntry::TYPE_OBJECT, idsObject);
+}
+
+void LLPanelDerenderList::refresh()
+{
+	m_pDerenderList->clearRows();
+	if (LLDerenderList::instanceExists())
+	{
+		LLSD sdRow;	LLSD& sdColumns = sdRow["columns"];
+		sdColumns[0]["column"] = "object_name";   sdColumns[0]["type"] = "text";
+		sdColumns[1]["column"] = "location";      sdColumns[1]["type"] = "text";
+		sdColumns[2]["column"] = "derender_type"; sdColumns[2]["type"] = "text";
+
+		for (const auto& pEntry : LLDerenderList::instance().getEntries())
+		{
+			sdRow["value"] = pEntry->getID();
+			sdColumns[0]["value"] = pEntry->getName();
+			if (LLDerenderEntry::TYPE_OBJECT == pEntry->getType())
+			{
+				auto pObjEntry = static_cast<LLDerenderObject*>(pEntry.get());
+				sdColumns[1]["value"] = fmt::format(FMT_STRING("{} <{}, {}, {}>"), pObjEntry->strRegionName, ll_round(pObjEntry->posRegion.mV[VX]), ll_round(pObjEntry->posRegion.mV[VY]), ll_round(pObjEntry->posRegion.mV[VZ]));
+			}
+			sdColumns[2]["value"] = (pEntry->isPersistent()) ? "Permanent" : "Temporary";
+
+			m_pDerenderList->addElement(sdRow, ADD_BOTTOM);
+		}
+	}
+}
+
+// ============================================================================
+// LLPanelAvatarRendering - Menu helper class
+//
+
+class LLPanelAvatarRenderingContextMenu : public LLListContextMenu
+{
+public:
+	LLPanelAvatarRenderingContextMenu(LLPanelAvatarRendering* pAvRenderingPanel)
+		: m_pAvRenderingPanel(pAvRenderingPanel)
+	{
+	}
+
+protected:
+	LLContextMenu* createMenu() override
+	{
+		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+		registrar.add("Settings.SetRendering", boost::bind(&LLPanelAvatarRendering::onSetException, m_pAvRenderingPanel, mUUIDs.front(), _2));
+
+		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+		enable_registrar.add("Settings.IsSelected", boost::bind(&LLPanelAvatarRendering::onHasException, m_pAvRenderingPanel, mUUIDs.front(), _2));
+
+		LLContextMenu* pMenu = createFromFile("menu_avatar_rendering_settings.xml");
+		return pMenu;
+	}
+
+protected:
+	LLPanelAvatarRendering* m_pAvRenderingPanel;
+};
+
+// ============================================================================
+// LLPanelAvatarRendering - Helper functions
+//
+
+static std::string createTimestamp(S32 datetime)
+{
+	std::string timeStr = "[" + LLTrans::getString("TimeMonth") + "]/[" + LLTrans::getString("TimeDay") + "]/[" + LLTrans::getString("TimeYear") + "]";
+	LLStringUtil::format(timeStr, LLSD().with("datetime", datetime));
+	return timeStr;
+}
+
+static LLVOAvatar* findAvatar(const LLUUID& idAgent)
+{
+	LLViewerObject* pAvObj = gObjectList.findObject(idAgent);
+	while ( (pAvObj) && (pAvObj->isAttachment()) )
+		pAvObj = (LLViewerObject*)pAvObj->getParent();
+
+	if ((pAvObj) && (pAvObj->isAvatar()) )
+		return (LLVOAvatar*)pAvObj;
+	return nullptr;
+}
+
+static void setAvatarRenderSetting(const LLUUID& idAgent, LLVOAvatar::VisualMuteSettings eSetting)
+{
+	if (LLVOAvatar* pAvatar = findAvatar(idAgent))
+		pAvatar->setVisualMuteSettings(LLVOAvatar::VisualMuteSettings(eSetting));
+	else
+		LLRenderMuteList::getInstance()->saveVisualMuteSetting(idAgent, eSetting);
+}
+
+// ============================================================================
+// LLPanelAvatarRendering - Configure avatar complexity excpetions
+//
+
+static LLPanelInjector<LLPanelAvatarRendering> t_panel_block_avatar_rendering("panel_block_avatar_rendering");
+
+LLPanelAvatarRendering::LLPanelAvatarRendering()
+	: LLPanel()
+{
+	mCommitCallbackRegistrar.add("Rendering.AddException", boost::bind(&LLPanelAvatarRendering::onAddException, this, _1, _2));
+	mCommitCallbackRegistrar.add("Rendering.RemoveException", boost::bind(&LLPanelAvatarRendering::onRemoveException, this));
+}
+
+LLPanelAvatarRendering::~LLPanelAvatarRendering()
+{
+	delete m_pContextMenu;
+	LLRenderMuteList::getInstance()->removeObserver(this);
+}
+
+// virtual
+BOOL LLPanelAvatarRendering::postBuild()
+{
+	setVisibleCallback(boost::bind(&LLPanelAvatarRendering::removePicker, this));
+
+	m_pExceptionList = findChild<LLNameListCtrl>("exception_list");
+	m_pExceptionList->setCommitOnDelete(true);
+	m_pExceptionList->setCommitOnSelectionChange(true);
+	m_pExceptionList->setCommitCallback(boost::bind(&LLPanelAvatarRendering::onSelectionChange, this));
+	m_pExceptionList->setRightMouseDownCallback(boost::bind(&LLPanelAvatarRendering::onExceptionMenu, this, _2, _3));
+
+	// Restore last sort order
+	if (U32 nSortValue = gSavedSettings.getU32("BlockRenderingSortOrder"))
+		m_pExceptionList->sortByColumnIndex(nSortValue >> 4, nSortValue & 0xF);
+	m_pExceptionList->setSortChangedCallback(boost::bind(&LLPanelAvatarRendering::onColumnSortChange, this));
+
+	m_pTrashBtn = findChild<LLButton>("rendering_exception_trash_btn");
+
+	LLRenderMuteList::getInstance()->addObserver(this);
+	m_pContextMenu = new LLPanelAvatarRenderingContextMenu(this);
+
+	return TRUE;
+}
+
+// virtual
+void LLPanelAvatarRendering::onOpen(const LLSD& sdParam)
+{
+	refresh();
+
+	if ((sdParam.has(EXCEPTION_PARAM_NAME)) && (sdParam[EXCEPTION_PARAM_NAME].asUUID().notNull()))
+	{
+		m_pExceptionList->selectByID(sdParam[EXCEPTION_PARAM_NAME].asUUID());
+	}
+}
+
+void LLPanelAvatarRendering::refresh()
+{
+	const LLUUID idSel = m_pExceptionList->getSelectedValue().asUUID();
+
+	m_pExceptionList->deleteAllItems();
+
+	LLAvatarName avName; LLNameListCtrl::NameItem paramItem;
+	for (const auto& kvEntry : LLRenderMuteList::getInstance()->sVisuallyMuteSettingsMap)
+	{
+		if ( (!LLAvatarNameCache::get(kvEntry.first, &avName)) || ((!m_strFilter.empty()) && (!boost::icontains(avName.getCompleteName(), m_strFilter))) )
+			continue;
+
+		paramItem.value = kvEntry.first;
+		paramItem.columns.add().value(avName.getCompleteName()).column("name");
+		paramItem.columns.add().value(getString(kvEntry.second == 1 ? "av_never_render" : "av_always_render")).column("setting");
+		paramItem.columns.add().value(createTimestamp(LLRenderMuteList::getInstance()->getVisualMuteDate(kvEntry.first))).column("timestamp");
+		m_pExceptionList->addNameItemRow(paramItem);
+	}
+
+	if (idSel.notNull())
+	{
+		m_pExceptionList->selectByID(idSel);
+	}
+}
+
+void LLPanelAvatarRendering::removePicker()
+{
+	if (m_hPicker.get())
+	{
+		m_hPicker.get()->closeFloater();
+	}
+}
+
+void LLPanelAvatarRendering::setFilterString(const std::string& strFilter)
+{
+	m_strFilter = strFilter;
+	refresh();
+}
+
+void LLPanelAvatarRendering::updateButtons()
+{
+	bool fHasSelection = (nullptr != m_pExceptionList->getFirstSelected());
+	m_pTrashBtn->setEnabled(fHasSelection);
+}
+
+void LLPanelAvatarRendering::onChange()
+{
+	if (m_fRefreshOnChange)
+	{
+		refresh();
+	}
+}
+
+void LLPanelAvatarRendering::onAddException(LLUICtrl* pCtrl, const LLSD& sdParam)
+{
+	const std::string strParam = sdParam.asString();
+
+	LLVOAvatar::VisualMuteSettings eSetting = (LLVOAvatar::VisualMuteSettings)0;
+	if ("never" == strParam)
+		eSetting = LLVOAvatar::AV_DO_NOT_RENDER;
+	else if ("always" == strParam)
+		eSetting = LLVOAvatar::AV_ALWAYS_RENDER;
+
+	if (LLFloater* pRootFloater = gFloaterView->getParentFloater(pCtrl))
+	{
+		removePicker();
+
+		LLFloaterAvatarPicker* pPicker = LLFloaterAvatarPicker::show(
+			boost::bind(&LLPanelAvatarRendering::onAddExceptionCb, _1, eSetting),
+			false /*allow_multiple*/, true /*close_on_select*/, false /*skip_agent*/, pRootFloater->getName(), pCtrl);
+		pRootFloater->addDependentFloater(pPicker);
+		m_hPicker = pPicker->getHandle();
+	}
+}
+
+void LLPanelAvatarRendering::onAddExceptionCb(const uuid_vec_t& idAgents, S32 nSetting)
+{
+	if (idAgents.empty())
+		return;
+
+	for (const LLUUID& idAgent : idAgents)
+	{
+		setAvatarRenderSetting(idAgent, (LLVOAvatar::VisualMuteSettings)nSetting);
+	}
+
+	LLFloaterBlocked::showRenderExceptionAndSelect(idAgents[0]);
+}
+
+bool LLPanelAvatarRendering::onHasException(const LLUUID& idAgent, const LLSD& sdParamn)
+{
+	const std::string strParam = sdParamn.asString();
+
+	LLVOAvatar::VisualMuteSettings eSetting = (LLVOAvatar::VisualMuteSettings)LLRenderMuteList::getInstance()->getSavedVisualMuteSetting(idAgent);
+	if ("default" == strParam)
+		return (eSetting == LLVOAvatar::AV_RENDER_NORMALLY);
+	else if ("non_default" == strParam)
+		return (eSetting != LLVOAvatar::AV_RENDER_NORMALLY);
+	else if ("never" == strParam)
+		return (eSetting == LLVOAvatar::AV_DO_NOT_RENDER);
+	else if ("always" == strParam)
+		return (eSetting == LLVOAvatar::AV_ALWAYS_RENDER);
+	return false;
+}
+
+void LLPanelAvatarRendering::onExceptionMenu(S32 x, S32 y)
+{
+	m_pExceptionList->selectItemAt(x, y, MASK_NONE);
+
+	uuid_vec_t selected_uuids;
+	if (m_pExceptionList->getCurrentID().notNull())
+	{
+		selected_uuids.push_back(m_pExceptionList->getCurrentID());
+		m_pContextMenu->show(m_pExceptionList, selected_uuids, x, y);
+	}
+}
+
+void LLPanelAvatarRendering::onRemoveException()
+{
+	m_fRefreshOnChange = false;
+
+	const std::vector<LLScrollListItem*> selItems = m_pExceptionList->getAllSelected();
+	for (auto* pSelItem : selItems)
+	{
+		const LLSD sdValue = pSelItem->getValue();
+		if (sdValue.isUUID())
+		{
+			setAvatarRenderSetting(sdValue.asUUID(), LLVOAvatar::AV_RENDER_NORMALLY);
+			m_pExceptionList->deleteSingleItem(pSelItem);
+		}
+	}
+
+	m_fRefreshOnChange = true;
+}
+
+void LLPanelAvatarRendering::onSetException(const LLUUID& idAgent, const LLSD& sdParamn)
+{
+	const std::string strParam = sdParamn.asString();
+
+	LLVOAvatar::VisualMuteSettings nSetting = (LLVOAvatar::VisualMuteSettings)0;
+	if ("default" == strParam)
+		nSetting = LLVOAvatar::AV_RENDER_NORMALLY;
+	else if ("never" == strParam)
+		nSetting = LLVOAvatar::AV_DO_NOT_RENDER;
+	else if ("always" == strParam)
+		nSetting = LLVOAvatar::AV_ALWAYS_RENDER;
+
+	setAvatarRenderSetting(idAgent, nSetting);
+}
+
+void LLPanelAvatarRendering::onColumnSortChange()
+{
+	U32 nSortValue = 0;
+
+	S32 idxColumn = m_pExceptionList->getSortColumnIndex();
+	if (-1 != idxColumn)
+	{
+		nSortValue = idxColumn << 4 | ((m_pExceptionList->getSortAscending()) ? 1 : 0);
+	}
+
+	gSavedSettings.setU32("BlockRenderingSortOrder", nSortValue);
+}
+
+void LLPanelAvatarRendering::onSelectionChange()
+{
+	updateButtons();
+}
+
+// ============================================================================
+// LLFloaterBlocked
+//
+
+LLFloaterBlocked::LLFloaterBlocked(const LLSD& sdKey)
+	: LLFloater(sdKey)
+{
+}
+
+LLFloaterBlocked::~LLFloaterBlocked()
+{
+}
+
+BOOL LLFloaterBlocked::postBuild()
+{
+	m_pFilterEditor = findChild<LLFilterEditor>("blocked_filter");
+	m_pFilterEditor->setCommitCallback(boost::bind(&LLFloaterBlocked::onFilterEdit, this, _2));
+
+	m_pBlockedTabs = findChild<LLTabContainer>("blocked_tabs");
+	m_pBlockedTabs->setCommitCallback(boost::bind(&LLFloaterBlocked::onTabSelect, this, _2));
+
+	return TRUE;
+}
+
+void LLFloaterBlocked::onOpen(const LLSD& sdParam)
+{
+	if (sdParam.has(BLOCKED_PARAM_NAME))
+		m_pBlockedTabs->selectTabByName(BLOCKED_TAB_NAME);
+	else if (sdParam.has(DERENDER_PARAM_NAME))
+		m_pBlockedTabs->selectTabByName(DERENDER_TAB_NAME);
+	if (sdParam.has(EXCEPTION_PARAM_NAME))
+		m_pBlockedTabs->selectTabByName(EXCEPTION_TAB_NAME);
+	else if ( (sdParam.isString()) && (m_pBlockedTabs->hasChild(sdParam.asString())) )
+		m_pBlockedTabs->selectTabByName(sdParam.asString());
+	else
+		m_pBlockedTabs->getCurrentPanel()->onOpen(sdParam);
+	mKey.clear();
+}
+
+void LLFloaterBlocked::onFilterEdit(const std::string& strFilter)
+{
+	if (LLPanelBlockBase* pCurPanel = dynamic_cast<LLPanelBlockBase*>(m_pBlockedTabs->getCurrentPanel()))
+	{
+		pCurPanel->setFilterString(strFilter);
+	}
+}
+
+void LLFloaterBlocked::onTabSelect(const LLSD& sdParam)
+{
+	LLPanel* pActivePanel = m_pBlockedTabs->getPanelByName(sdParam.asString());
+	if (pActivePanel)
+	{
+		if (LLPanelBlockBase* pActivePanelBase = dynamic_cast<LLPanelBlockBase*>(pActivePanel))
+			m_pFilterEditor->setText(pActivePanelBase->getFilterString());
+		pActivePanel->onOpen(mKey);
+	}
+}
+
+void LLFloaterBlocked::showMuteAndSelect(const LLUUID& idMute)
+{
+	LLFloaterReg::showInstance("blocked", LLSD().with(BLOCKED_PARAM_NAME, idMute));
+}
+
+void LLFloaterBlocked::showDerenderAndSelect(const LLUUID& idEntry)
+{
+	LLFloaterReg::showInstance("blocked", LLSD().with(DERENDER_PARAM_NAME, idEntry));
+}
+
+void LLFloaterBlocked::showRenderExceptionAndSelect(const LLUUID& idEntry)
+{
+	LLFloaterReg::showInstance("blocked", LLSD().with(EXCEPTION_PARAM_NAME, idEntry));
+}
+
+// ============================================================================
diff --git a/indra/newview/llfloaterblocked.h b/indra/newview/llfloaterblocked.h
new file mode 100644
index 00000000000..23cc04bb347
--- /dev/null
+++ b/indra/newview/llfloaterblocked.h
@@ -0,0 +1,245 @@
+/**
+ *
+ * Copyright (c) 2012-2017, 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.
+ *
+ */
+
+#pragma once
+
+#include "llavatarname.h"
+#include "llfloater.h"
+#include "llmutelist.h"
+
+class LLFilterEditor;
+class LLListContextMenu;
+class LLNameListCtrl;
+class LLScrollListCell;
+class LLScrollListCtrl;
+class LLTabContainer;
+
+// ============================================================================
+// Constants
+//
+
+extern const std::string BLOCKED_PARAM_NAME;
+extern const std::string DERENDER_PARAM_NAME;
+extern const std::string EXCEPTION_PARAM_NAME;
+extern const std::string BLOCKED_TAB_NAME;
+extern const std::string DERENDER_TAB_NAME;
+extern const std::string EXCEPTION_TAB_NAME;
+
+// ============================================================================
+// LLPanelBlockBase
+//
+
+class LLPanelBlockBase
+{
+public:
+	virtual const std::string& getFilterString() const = 0;
+	virtual void               setFilterString(const std::string& strFilter) = 0;
+};
+
+// ============================================================================
+// LLPanelBlockList
+//
+
+class LLPanelBlockList : public LLPanel, public LLMuteListObserver, public LLPanelBlockBase
+{
+public:
+	LLPanelBlockList();
+	~LLPanelBlockList();
+
+	/*
+	 * LLPanel overrides
+	 */
+public:
+	BOOL postBuild() override;
+	void onOpen(const LLSD& sdParam) override;
+
+	/*
+	 * Member functions
+	 */
+public:
+	const std::string& getFilterString() const override { return m_strFilter; }
+	void setFilterString(const std::string& strFilter) override;
+protected:
+	void refresh();
+	void removePicker();
+	void selectEntry(const LLSD& sdValue) { LLMute muteEntry(sdValue["id"].asUUID(), sdValue["name"].asString()); selectEntry(muteEntry); }
+	void selectEntry(const LLMute& muteEntry);
+	void updateButtons();
+
+	/*
+	 * Event handlers
+	 */
+public:
+	       void onChange() override;
+protected:
+	       void onAddAvatar(LLUICtrl* pCtrl);
+	static void onAddAvatarCallback(const uuid_vec_t& idAgents, const std::vector<LLAvatarName>& avAgents);
+	static void onAddByName();
+	static void onAddByNameCallback(const std::string& strBlockName);
+		   void onRemoveSelection();
+		   void onColumnSortChange();
+	static void onIdleRefresh(LLHandle<LLPanel> hPanel);
+		   void onSelectionChange();
+		   void onToggleMuteFlag(const LLSD& sdValue, const LLScrollListCell* pCell);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	bool                m_fRefreshOnChange = true;
+	std::string         m_strFilter;
+	LLScrollListCtrl*   m_pBlockList = nullptr;
+	LLButton*           m_pTrashBtn = nullptr;
+	LLHandle<LLFloater> m_hPicker;
+};
+
+// ============================================================================
+// LLPanelDerenderList
+//
+
+class LLPanelDerenderList : public LLPanel
+{
+public:
+	LLPanelDerenderList();
+	~LLPanelDerenderList();
+
+	/*
+	 * LLPanel overrides
+	 */
+public:
+	BOOL postBuild() override;
+	void onOpen(const LLSD& sdParam) override;
+
+	/*
+	 * Member functions
+	 */
+protected:
+	void refresh();
+
+	/*
+	 * Event handlers
+	 */
+protected:
+	void onColumnSortChange();
+	void onSelectionChange();
+	void onSelectionRemove();
+
+	/*
+	 * Member variables
+	 */
+protected:
+	LLScrollListCtrl*           m_pDerenderList;
+	boost::signals2::connection m_DerenderChangeConn;
+};
+
+// ============================================================================
+// LLPanelAvatarRendering - Configure avatar complexity excpetions
+//
+
+class LLPanelAvatarRendering : public LLPanel, public LLMuteListObserver, public LLPanelBlockBase
+{
+	friend class LLPanelAvatarRenderingContextMenu;
+public:
+	LLPanelAvatarRendering();
+	~LLPanelAvatarRendering();
+
+	/*
+	 * LLPanel overrides
+	 */
+public:
+	BOOL postBuild() override;
+	void onOpen(const LLSD& sdParam) override;
+
+	/*
+	 * Member functions
+	 */
+public:
+	const std::string& getFilterString() const override { return m_strFilter; }
+	void setFilterString(const std::string& strFilter) override;
+protected:
+	void refresh();
+	void removePicker();
+	void updateButtons();
+
+	/*
+	 * Event handlers
+	 */
+public:
+	void onChange() override;
+protected:
+	void onAddException(LLUICtrl* pCtrl, const LLSD& sdParam);
+	static void onAddExceptionCb(const uuid_vec_t& idAgents, S32 nSetting);
+	bool onHasException(const LLUUID& idAgent, const LLSD& sdParamn);
+	void onExceptionMenu(S32 x, S32 y);
+	void onRemoveException();
+	void onSetException(const LLUUID& idAgent, const LLSD& sdParamn);
+
+	void onColumnSortChange();
+	void onSelectionChange();
+
+	/*
+	 * Member variables
+	 */
+protected:
+	bool                m_fRefreshOnChange = true;
+	std::string         m_strFilter;
+	LLNameListCtrl*     m_pExceptionList = nullptr;
+	LLButton*           m_pTrashBtn = nullptr;
+	LLListContextMenu*  m_pContextMenu = nullptr;
+	LLHandle<LLFloater> m_hPicker;
+};
+
+// ============================================================================
+// LLFloaterBlocked
+//
+
+class LLFloaterBlocked : public LLFloater
+{
+public:
+	LLFloaterBlocked(const LLSD& sdKey);
+	~LLFloaterBlocked();
+
+	/*
+	 * LLFloater overrides
+	 */
+public:
+	BOOL postBuild() override;
+	void onOpen(const LLSD& sdParam) override;
+
+	/*
+	 * Event handlers
+	 */
+protected:
+	void onFilterEdit(const std::string& strFilter);
+	void onTabSelect(const LLSD& sdParam);
+
+	/*
+	 * Member functions
+	 */
+public:
+	static void showMuteAndSelect(const LLUUID& idMute);
+	static void showDerenderAndSelect(const LLUUID& idEntry);
+	static void showRenderExceptionAndSelect(const LLUUID& idEntry);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	LLFilterEditor* m_pFilterEditor = nullptr;
+	LLTabContainer* m_pBlockedTabs = nullptr;
+};
+
+// ============================================================================
diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp
index f9c9ad91215..b096dba0773 100644
--- a/indra/newview/llfloaterbump.cpp
+++ b/indra/newview/llfloaterbump.cpp
@@ -36,7 +36,8 @@
 #include "llfloaterreg.h"
 #include "llfloaterreporter.h"
 #include "llmutelist.h"
-#include "llpanelblockedlist.h"
+#include "llfloaterblocked.h"
+//#include "llpanelblockedlist.h"
 #include "llscrolllistctrl.h"
 #include "lltrans.h"
 #include "lluictrlfactory.h"
@@ -245,7 +246,8 @@ void LLFloaterBump::muteAvatar()
 	else
 	{
 		LLMuteList::getInstance()->add(mute);
-		LLPanelBlockedList::showPanelAndSelect(mute.mID);
+		LLFloaterBlocked::showMuteAndSelect(mute.mID);
+		//LLPanelBlockedList::showPanelAndSelect(mute.mID);
 	}
 }
 
diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp
index 74ecdb4a4b9..57f030da78c 100644
--- a/indra/newview/llfloaterperformance.cpp
+++ b/indra/newview/llfloaterperformance.cpp
@@ -564,7 +564,7 @@ void LLFloaterPerformance::onClickHideAvatars()
 
 void LLFloaterPerformance::onClickExceptions()
 {
-    LLFloaterReg::showInstance("avatar_render_settings");
+    LLFloaterReg::showInstance("blocked", LLSD("avatar_rendering_tab"));
 }
 
 void LLFloaterPerformance::updateMaxRenderTime()
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 39ecf87aa54..46dc4e961e7 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2081,8 +2081,11 @@ void LLFloaterPreference::onChangeAnimationFolder()
 // but the UI for this will still be enabled
 void LLFloaterPreference::onClickBlockList()
 {
-	LLFloaterSidePanelContainer::showPanel("people", "panel_people",
-		LLSD().with("people_panel_tab_name", "blocked_panel"));
+// [SL:KB] - Patch: World-Derender | Checked: Catznip-3.2
+	LLFloaterReg::showInstance("blocked");
+// [/SL:KB]
+//	LLFloaterSidePanelContainer::showPanel("people", "panel_people",
+//		LLSD().with("people_panel_tab_name", "blocked_panel"));
 }
 
 void LLFloaterPreference::onClickProxySettings()
@@ -2107,7 +2110,7 @@ void LLFloaterPreference::onClickSpellChecker()
 
 void LLFloaterPreference::onClickRenderExceptions()
 {
-    LLFloaterReg::showInstance("avatar_render_settings");
+    LLFloaterReg::showInstance("blocked", LLSD("avatar_rendering_tab"));
 }
 
 void LLFloaterPreference::onClickAutoAdjustments()
diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp
index 038bd331c1f..f75554bb934 100644
--- a/indra/newview/llfloatersidepanelcontainer.cpp
+++ b/indra/newview/llfloatersidepanelcontainer.cpp
@@ -175,6 +175,18 @@ void LLFloaterSidePanelContainer::showPanel(std::string_view floater_name, const
 
 void LLFloaterSidePanelContainer::showPanel(std::string_view floater_name, std::string_view panel_name, const LLSD& key)
 {
+// [SL:KB] - Patch: World-Derender | Checked: Catznip-3.2
+	// Hack in case we forget a reference somewhere
+	if ( (!panel_name.empty()) && ("panel_people" == panel_name) && (key.has("people_panel_tab_name")) && ("blocked_panel" == key["people_panel_tab_name"].asString()) )
+	{
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		LL_ERRS() << "Request to open the blocked floater through the sidepanel!" << LL_ENDL;
+#endif // LL_RELEASE_FOR_DOWNLOAD
+		LLFloaterReg::showInstance("blocked", key);
+		return;
+	}
+// [/SL:KB]
+
 	LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name);
 //	if (floaterp)
 // [RLVa:KB] - Checked: 2013-04-16 (RLVa-1.4.8)
diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp
index da3ed9ebbfd..3f5b19eacd4 100644
--- a/indra/newview/llinspectremoteobject.cpp
+++ b/indra/newview/llinspectremoteobject.cpp
@@ -29,7 +29,8 @@
 #include "llinspectremoteobject.h"
 #include "llinspect.h"
 #include "llmutelist.h"
-#include "llpanelblockedlist.h"
+#include "llfloaterblocked.h"
+//#include "llpanelblockedlist.h"
 #include "llslurl.h"
 #include "lltrans.h"
 #include "llui.h"
@@ -138,7 +139,8 @@ void LLInspectRemoteObject::onClickBlock()
 {
 	LLMute mute(mObjectID, mName, LLMute::OBJECT);
 	LLMuteList::getInstance()->add(mute);
-	LLPanelBlockedList::showPanelAndSelect(mute.mID);
+	LLFloaterBlocked::showMuteAndSelect(mute.mID);
+	//LLPanelBlockedList::showPanelAndSelect(mute.mID);
 	closeFloater();
 }
 
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 23c49a80de2..f1052dc1952 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -333,6 +333,16 @@ LLScrollListItem* LLNameListCtrl::addElement(const LLSD& element, EAddPosition p
 	return addNameItemRow(item_params, pos);
 }
 
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+LLScrollListItem* LLNameListCtrl::addElement(const LLSD& element, const LLScrollListItem::commit_signal_t::slot_type& cb, EAddPosition pos)
+{
+	LLNameListCtrl::NameItem item_params;
+	LLParamSDParser parser;
+	parser.readSD(element, item_params);
+	item_params.commit_callback = cb;
+	return addNameItemRow(item_params, pos);
+}
+// [/SL:KB]
 
 LLScrollListItem* LLNameListCtrl::addNameItemRow(
 	const LLNameListCtrl::NameItem& name_item,
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 4a4bd4ba09f..fd8e62224a0 100644
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -147,7 +147,11 @@ class LLNameListCtrl
 					 BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null, const std::string& prefix = LLStringUtil::null);
 	LLScrollListItem* addNameItem(NameItem& item, EAddPosition pos = ADD_BOTTOM);
 
-	/*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
+//	/*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
+// [SL:KB] - Patch: Control-ScrollList | Checked: Catznip-5.2
+	LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = nullptr) override;
+	LLScrollListItem* addElement(const LLSD& element, const LLScrollListItem::commit_signal_t::slot_type& cb, EAddPosition pos = ADD_BOTTOM) override;
+// [/SL:KB]
 	LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, const std::string& suffix = LLStringUtil::null,
 																							const std::string& prefix = LLStringUtil::null);
 
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index e6aff67734e..f2a82112fc2 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -48,6 +48,8 @@
 #include "llsidetraypanelcontainer.h"
 #include "llviewercontrol.h"
 
+#if 0
+
 static LLPanelInjector<LLPanelBlockedList> t_panel_blocked_list("panel_block_list_sidetray");
 
 //
@@ -256,6 +258,8 @@ void LLPanelBlockedList::callbackBlockByName(const std::string& text)
 	}
 }
 
+#endif
+
 //////////////////////////////////////////////////////////////////////////
 //			LLFloaterGetBlockedObjectName
 //////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h
index 8339cf16b3a..8ec05e04c70 100644
--- a/indra/newview/llpanelblockedlist.h
+++ b/indra/newview/llpanelblockedlist.h
@@ -36,6 +36,7 @@ class LLBlockList;
 class LLMenuButton;
 class LLButton;
 
+#if 0
 class LLPanelBlockedList : public LLPanel
 {
 public:
@@ -86,6 +87,7 @@ class LLPanelBlockedList : public LLPanel
 	LLButton*	 mUnblockBtn = nullptr;
     LLHandle<LLFloater> mPicker;
 };
+#endif
 
 //-----------------------------------------------------------------------------
 // LLFloaterGetBlockedObjectName()
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 597b44755b1..eebf8d9ae2b 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -88,7 +88,7 @@ static const std::string NEARBY_TAB_NAME	= "nearby_panel";
 static const std::string FRIENDS_TAB_NAME	= "friends_panel";
 static const std::string GROUP_TAB_NAME		= "groups_panel";
 static const std::string RECENT_TAB_NAME	= "recent_panel";
-static const std::string BLOCKED_TAB_NAME	= "blocked_panel"; // blocked avatars
+//static const std::string BLOCKED_TAB_NAME	= "blocked_panel"; // blocked avatars
 static const std::string COLLAPSED_BY_USER  = "collapsed_by_user";
 
 /** Comparator for comparing avatar items by last interaction date */
@@ -982,8 +982,8 @@ LLUUID LLPanelPeople::getCurrentItemID() const
 	if (cur_tab == GROUP_TAB_NAME)
 		return mGroupList->getSelectedUUID();
 
-	if (cur_tab == BLOCKED_TAB_NAME)
-		return LLUUID::null; // FIXME?
+	//if (cur_tab == BLOCKED_TAB_NAME)
+	//	return LLUUID::null; // FIXME?
 
 	llassert(0 && "unknown tab selected");
 	return LLUUID::null;
@@ -1005,8 +1005,8 @@ void LLPanelPeople::getCurrentItemIDs(uuid_vec_t& selected_uuids) const
 		mRecentList->getSelectedUUIDs(selected_uuids);
 	else if (cur_tab == GROUP_TAB_NAME)
 		mGroupList->getSelectedUUIDs(selected_uuids);
-	else if (cur_tab == BLOCKED_TAB_NAME)
-		selected_uuids.clear(); // FIXME?
+	//else if (cur_tab == BLOCKED_TAB_NAME)
+	//	selected_uuids.clear(); // FIXME?
 	else
 		llassert(0 && "unknown tab selected");
 
@@ -1582,14 +1582,14 @@ void	LLPanelPeople::onOpen(const LLSD& key)
 	if (!tab_name.empty())
 	{
 		mTabContainer->selectTabByName(tab_name);
-		if(tab_name == BLOCKED_TAB_NAME)
-		{
-			LLPanel* blocked_tab = mTabContainer->getCurrentPanel()->findChild<LLPanel>("panel_block_list_sidetray");
-			if(blocked_tab)
-			{
-				blocked_tab->onOpen(key);
-			}
-		}
+		//if(tab_name == BLOCKED_TAB_NAME)
+		//{
+		//	LLPanel* blocked_tab = mTabContainer->getCurrentPanel()->findChild<LLPanel>("panel_block_list_sidetray");
+		//	if(blocked_tab)
+		//	{
+		//		blocked_tab->onOpen(key);
+		//	}
+		//}
 	}
 }
 
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 44dce1ad568..e3f9be6cd97 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -69,7 +69,7 @@
 #include "lllogchat.h"
 #include "llmutelist.h"
 #include "llnotificationsutil.h"
-#include "llpanelblockedlist.h"
+//#include "llpanelblockedlist.h"
 #include "llpanelprofileclassifieds.h"
 #include "llpanelprofilepicks.h"
 #include "llthumbnailctrl.h"
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 9e95f57b309..9957a3d8b9b 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -1664,6 +1664,11 @@ void LLSelectMgr::dump()
 	{
 		LLViewerObject* objectp = (*iter)->getObject();
 		LL_INFOS() << "Object " << count << " type " << LLPrimitive::pCodeToString(objectp->getPCode()) << LL_ENDL;
+// [SL:KB] - Patch: World-Derender | Checked: 2014-08-10 (Catznip-3.7)
+		LL_INFOS() << "  isRoot " << objectp->isRoot() << LL_ENDL;
+		LL_INFOS() << "  idLocal " << objectp->getLocalID() << LL_ENDL;
+		LL_INFOS() << "  idGlobal " << objectp->getID() << LL_ENDL;
+// [/SL:KB]
 		LL_INFOS() << "  hasLSL " << objectp->flagScripted() << LL_ENDL;
 		LL_INFOS() << "  hasTouch " << objectp->flagHandleTouch() << LL_ENDL;
 		LL_INFOS() << "  hasMoney " << objectp->flagTakesMoney() << LL_ENDL;
@@ -6656,7 +6661,7 @@ S32 LLSelectNode::getLastSelectedTE() const
 	return mLastTESelected;
 }
 
-LLViewerObject* LLSelectNode::getObject()
+LLViewerObject* LLSelectNode::getObject() const
 {
 	if (!mObject)
 	{
@@ -6664,7 +6669,7 @@ LLViewerObject* LLSelectNode::getObject()
 	}
 	else if (mObject->isDead())
 	{
-		mObject = NULL;
+		mObject = nullptr;
 	}
 	return mObject;
 }
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 4205497109e..518d5453637 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -182,7 +182,7 @@ class LLSelectNode
 	void renderOneSilhouette(const LLColor4 &color);
 	void setTransient(BOOL transient) { mTransient = transient; }
 	BOOL isTransient() const { return mTransient; }
-	LLViewerObject* getObject();
+	LLViewerObject* getObject() const;
 	void setObject(LLViewerObject* object);
 	// *NOTE: invalidate stored textures and colors when # faces change
     // Used by tools floater's color/texture pickers to restore changes
@@ -241,7 +241,7 @@ class LLSelectNode
 	BOOL					mSilhouetteExists;	// need to generate silhouette?
 
 protected:
-	LLPointer<LLViewerObject>	mObject;
+	mutable LLPointer<LLViewerObject>	mObject;
 	S32				mTESelectMask;
 	S32				mLastTESelected;
 };
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index f0c2cc103a6..c820fed71c6 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -55,6 +55,9 @@
 #include "llfloaterbanduration.h"
 #include "llfloaterbigpreview.h"
 #include "llfloaterbeacons.h"
+// [SL:KB] - Patch: World-Derender | Checked: Catznip-3.2
+#include "llfloaterblocked.h"
+// [/SL:KB]
 #include "llfloaterbuildoptions.h"
 #include "llfloaterbulkpermission.h"
 #include "llfloaterbump.h"
@@ -351,6 +354,9 @@ void LLViewerFloaterReg::registerFloaters()
 
 	LLFloaterReg::add("ban_duration", "floater_ban_duration.xml", &LLFloaterReg::build<LLFloaterBanDuration>);
 	LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBeacons>);
+// [SL:KB] - Patch: World-Derender | Checked: Catznip-3.2
+	LLFloaterReg::add("blocked", "floater_blocked.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBlocked>);
+// [/SL:KB]
 	LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBulkPermission>);
 	LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater);
 	LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyCurrencyHTML>);	
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 9e116a855e4..7a99fe79f3b 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -59,6 +59,9 @@
 #include "llcompilequeue.h"
 #include "llconsole.h"
 #include "lldebugview.h"
+// [SL:KB] - Patch: World-Derender | Checked: 2011-12-15 (Catznip-3.2)
+#include "llderenderlist.h"
+// [/SL:KB]
 #include "lldiskcache.h"
 #include "llenvironment.h"
 #include "llfilepicker.h"
@@ -95,7 +98,11 @@
 #include "llinventorydefines.h"
 #include "llinventoryfunctions.h"
 #include "llpanellogin.h"
-#include "llpanelblockedlist.h"
+// [SL:KB] - World-Mute | Checked: 2013-07-10 (Catznip-3.5)
+#include "llfloaterblocked.h"
+// [/SL:KB]
+//#include "llpanelblockedlist.h"
+#include "llfloaterblocked.h"
 #include "llpanelmaininventory.h"
 #include "llmarketplacefunctions.h"
 #include "llmaterialeditor.h"
@@ -3539,7 +3546,8 @@ class LLObjectMute : public view_listener_t
 		else
 		{
 			LLMuteList::getInstance()->add(mute);
-			LLPanelBlockedList::showPanelAndSelect(mute.mID);
+			LLFloaterBlocked::showMuteAndSelect(mute.mID);
+			//LLPanelBlockedList::showPanelAndSelect(mute.mID);
 		}
 		
 		return true;
@@ -6031,6 +6039,42 @@ void handle_force_delete(void*)
 	LLSelectMgr::getInstance()->selectForceDelete();
 }
 
+// [SL:KB] - Patch: World-Derender | Checked: 2012-06-08 (Catznip-3.3)
+void handle_view_blocked(const LLSD& sdParam)
+{
+	if (LLVOAvatar* pAvatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
+	{
+		std::string strParam = sdParam.asString();
+		if (BLOCKED_TAB_NAME == strParam)
+			strParam = BLOCKED_PARAM_NAME;
+		else if (DERENDER_TAB_NAME == strParam)
+			strParam = DERENDER_PARAM_NAME;
+		else if (EXCEPTION_TAB_NAME == strParam)
+			strParam = EXCEPTION_PARAM_NAME;
+
+		LLFloaterReg::showInstance("blocked", LLSD().with(strParam, pAvatar->getID()));
+	}
+	else
+	{
+		LLFloaterReg::showInstance("blocked", sdParam);
+	}
+}
+
+void handle_object_derender(const LLSD& sdParam)
+{
+	std::vector<LLUUID> idList;
+	if (LLDerenderList::instance().addSelection("persistent" == sdParam.asString(), &idList))
+	{
+		LLFloaterReg::showInstance("blocked", LLSD().with("derender_to_select", idList.front()));
+	}
+}
+
+bool enable_object_derender()
+{
+	return LLDerenderList::canAddSelection();
+}
+// [/SL:KB]
+
 class LLViewEnableJoystickFlycam : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -7133,7 +7177,8 @@ class LLMuteParticle : public view_listener_t
 			else
 			{
 				LLMuteList::getInstance()->add(mute);
-				LLPanelBlockedList::showPanelAndSelect(mute.mID);
+				LLFloaterBlocked::showMuteAndSelect(mute.mID);
+				//LLPanelBlockedList::showPanelAndSelect(mute.mID);
 			}
 		}
 
@@ -9746,6 +9791,9 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLViewStatusAway(), "View.Status.CheckAway");
 	view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb");
 	view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments");
+// [SL:KB] - Patch: World-RenderExceptions | Checked: Catznip-5.2
+	commit.add("View.Blocked", boost::bind(&handle_view_blocked, _2));
+// [/SL:KB]
 	
 	//Communicate Nearby chat
 	view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat");
@@ -10077,6 +10125,10 @@ void initialize_menus()
 	commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original));
 	commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
 	commit.add("Object.Delete", boost::bind(&handle_object_delete));
+// [SL:KB] - Patch: World-Derender | Checked: 2011-12-15 (Catznip-3.2)
+	commit.add("Object.Derender", boost::bind(&handle_object_derender, _2));
+	enable.add("Object.EnableDerender", boost::bind(&enable_object_derender));
+// [/SL:KB]
 	view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
 	view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar");
 	view_listener_t::addMenu(new LLObjectReturn(), "Object.Return");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 7d03d0d1615..04eb687eb92 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -117,7 +117,8 @@
 #include "llkeythrottle.h"
 #include "llgroupactions.h"
 #include "llagentui.h"
-#include "llpanelblockedlist.h"
+//#include "llpanelblockedlist.h"
+#include "llfloaterblocked.h"
 #include "llpanelplaceprofile.h"
 #include "llviewerregion.h"
 #include "llfloaterregionrestarting.h"
@@ -1640,7 +1641,8 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,
 	LLMute mute(blocked_id, full_name, mute_type);
 	if (LLMuteList::getInstance()->add(mute))
 	{
-		LLPanelBlockedList::showPanelAndSelect(blocked_id);
+		LLFloaterBlocked::showMuteAndSelect(blocked_id);
+		//LLPanelBlockedList::showPanelAndSelect(blocked_id);
 	}
 
 	// purge the message queue of any previously queued inventory offers from the same source.
@@ -7068,7 +7070,8 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response)
 		{
 			// This call opens the sidebar, displays the block list, and highlights the newly blocked
 			// object in the list so the user can see that their block click has taken effect.
-			LLPanelBlockedList::showPanelAndSelect(object_id);
+			//LLPanelBlockedList::showPanelAndSelect(object_id);
+			LLFloaterBlocked::showMuteAndSelect(object_id);
 		}
 	}
 
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index cdde4d86c67..71bc966243e 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -69,6 +69,9 @@
 #include "llviewertexturelist.h"
 #include "lldatapacker.h"
 #include "llcallstack.h"
+// [SL:KB] - Patch: World-Derender | Checked: 2011-12-15 (Catznip-3.2.1)
+#include "llderenderlist.h"
+// [/SL:KB]
 #ifdef LL_USESYSTEMLIBS
 #include <zlib.h>
 #else
@@ -358,6 +361,15 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*
 		}
 	}
 
+// [SL:KB] - Patch: World-Derender | Checked: 2014-08-10 (Catznip-3.7)
+	// Don't recreate derendered objects (also kill the cache entry so we don't do this per-frame)
+	if (LLDerenderList::instance().processObjectUpdate(regionp->getHandle(), fullid, entry))
+	{
+		regionp->killCacheEntry(local_id);	// NOTE: this will kill all child entries from the cache as well
+		return NULL;
+	}
+// [/SL:KB]
+
 	bool justCreated = false;
 	if (!objectp)
 	{
@@ -646,6 +658,27 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			}
 #endif
 
+// [SL:KB] - Patch: World-Derender | Checked: 2012-06-08 (Catznip-3.3)
+			// Don't recreate derendered objects (update the core object information so we'll have enough information to rerequest it later if needed)
+			if ( (OUT_FULL == update_type) || (OUT_FULL_COMPRESSED == update_type) )
+			{
+				bool fBlockObject = false;
+				if (OUT_FULL == update_type)
+				{
+					U32 idRootLocal = 0;
+					mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ParentID, idRootLocal, i);
+					fBlockObject = LLDerenderList::instance().processObjectUpdate(regionp->getHandle(), fullid, local_id, idRootLocal);
+				}
+				else if (OUT_FULL_COMPRESSED == update_type)
+				{
+					fBlockObject = LLDerenderList::instance().processObjectUpdate(regionp->getHandle(), fullid, local_id, compressed_dp.getBuffer());
+				}
+
+				if (fBlockObject)
+					continue;
+			}
+// [/SL:KB]
+
 			objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());
 
 #ifdef SHOW_DEBUG
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index e14f78fd00e..88b207f920d 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2837,6 +2837,10 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB
 
 	if (entry)
 	{
+// [SL:KB] - Patch: World-Derender | Checked: 2014-08-10 (Catznip-3.7)
+		// If the entry isn't currently valid then we shouldn't just assume everything's in perfect working order
+		bool fUpdateObj = (!entry->isValid()) || (entry->getCRC() != crc);
+// [/SL:KB]
 		entry->setValid();
 
 		// we've seen this object before
@@ -2861,10 +2865,15 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB
 			// Update the cache entry 
 			entry->updateEntry(crc, dp);
 
-			decodeBoundingInfo(entry);
+//			decodeBoundingInfo(entry);
 
 			result = CACHE_UPDATE_CHANGED;
 		}		
+
+// [SL:KB] - Patch: World-Derender | Checked: 2014-08-10 (Catznip-3.7)
+		if (fUpdateObj)
+			decodeBoundingInfo(entry);
+// [/SL:KB]
 	}
 	else
 	{
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index e1fd2b206ce..4c111d655af 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -413,7 +413,7 @@ LLVOCacheEntry* LLVOCacheEntry::getChild()
 	return child;
 }
 
-LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP()
+LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP() const
 {
 	if (mDP.getBufferSize() == 0)
 	{
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index c0f4b3ae6a5..1eac9253d3f 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -130,7 +130,7 @@ class LLVOCacheEntry final
 
 	void dump() const;
 	S32 writeToBuffer(U8 *data_buffer) const;
-	LLDataPackerBinaryBuffer *getDP();
+	LLDataPackerBinaryBuffer *getDP() const;
 	void recordHit();
 	void recordDupe() { mDupeCount++; }
 	
@@ -169,6 +169,11 @@ class LLVOCacheEntry final
 
     typedef std::unordered_map<U32, LLGLTFOverrideCacheEntry>  vocache_gltf_overrides_map_t;
 
+// [SL:KB] - Patch: World-Derender | Checked: 2014-08-10 (Catznip-3.7)
+	vocache_entry_set_t::const_iterator getChildrenBegin() const { return mChildrenList.begin(); }
+	vocache_entry_set_t::const_iterator getChildrenEnd() const { return mChildrenList.end(); }
+// [/SL:KB]
+
 	S32                         mLastCameraUpdated;
 protected:
 	U32							mLocalID;
@@ -178,7 +183,7 @@ class LLVOCacheEntry final
 	S32							mHitCount;
 	S32							mDupeCount;
 	S32							mCRCChangeCount;
-	LLDataPackerBinaryBuffer	mDP;
+	mutable LLDataPackerBinaryBuffer	mDP;
 	U8							*mBuffer;
 
 	F32                         mSceneContrib; //projected scene contributuion of this object.
diff --git a/indra/newview/skins/default/xui/en/floater_blocked.xml b/indra/newview/skins/default/xui/en/floater_blocked.xml
new file mode 100644
index 00000000000..5033927fde7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_blocked.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_close="true"
+ can_minimize="true"
+ can_resize="true"
+ height="300"
+ help_topic="blocked_list"
+ layout="topleft"
+ min_height="300"
+ min_width="330"
+ name="blocked"
+ positioning="cascading"
+ save_rect="true"
+ save_visibility="false"
+ single_instance="true"
+ title="BLOCKED / DERENDER LIST"
+ width="350">
+    <filter_editor
+     follows="left|top|right"
+     height="23"
+     layout="topleft"
+     left="15"
+     label="Filter"
+     max_length_chars="300"
+     name="blocked_filter"
+     right="-15"
+     text_pad_left="10"
+     top="4"
+     />
+    <tab_container
+     follows="all"
+     layout="topleft"
+     left="8"  
+     name="blocked_tabs"
+     height="267"
+     right="-8"   
+     tab_height="25"
+     tab_min_width="100"
+     tab_position="top"
+     top_pad="4" >
+        <panel
+         class="panel_block_list"
+         filename="panel_block_list.xml"
+         label="BLOCKED"
+         layout="topleft"
+         name="mute_tab" />
+        <panel
+         class="panel_derender_list"
+         filename="panel_block_derender.xml"
+         label="DERENDERED"
+         layout="topleft"
+         name="derender_tab" />
+        <panel
+         class="panel_block_avatar_rendering"
+         filename="panel_block_avatar_rendering.xml"
+         label="AVATAR RENDERING"
+         layout="topleft"
+         name="avatar_rendering_tab" />
+    </tab_container>
+</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 2662b0df702..6afa27c3f33 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
@@ -105,8 +105,8 @@
       label="Render Exceptions..."
       name="RenderExceptions">
       <menu_item_call.on_click
-        function="Floater.ToggleOrBringToFront"
-        parameter="avatar_render_settings" />
+	      function="View.Blocked"
+	      parameter="avatar_rendering_tab" />
     </menu_item_call>
   </context_menu>
   <context_menu
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 26819704b69..8145b465c1d 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
@@ -107,8 +107,8 @@
       label="Render Exceptions..."
       name="RenderExceptions">
       <menu_item_call.on_click
-        function="Floater.ToggleOrBringToFront"
-        parameter="avatar_render_settings" />
+	      function="View.Blocked"
+	      parameter="avatar_rendering_tab" />
     </menu_item_call>
   </context_menu>
   <context_menu
diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml
index 58accf7429f..51d68c22732 100644
--- a/indra/newview/skins/default/xui/en/menu_object.xml
+++ b/indra/newview/skins/default/xui/en/menu_object.xml
@@ -251,6 +251,7 @@
       <menu_item_call.on_enable
           function="Object.EnableReportAbuse" />
     </menu_item_call>   
+   <menu_item_separator />
     <menu_item_call
    		  label="Block"        
           name="Object Mute">
@@ -267,6 +268,25 @@
         <menu_item_call.on_visible
           function="Object.EnableUnmute" />
     </menu_item_call>
+   <menu_item_call
+      label="Session Derender"
+      name="Object Session Derender">
+         <menu_item_call.on_click
+          function="Object.Derender"
+          parameter="temporary" />
+         <menu_item_call.on_enable
+          function="Object.EnableDerender" />
+   </menu_item_call>
+   <menu_item_call
+      label="Permanent Derender"
+      name="Object Permanent Derender">
+         <menu_item_call.on_click
+          function="Object.Derender"
+          parameter="persistent" />
+         <menu_item_call.on_enable
+          function="Object.EnableDerender" />
+   </menu_item_call>
+   <menu_item_separator />
     <menu_item_call
         enabled="false"
         label="Return"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index e0b7cae5398..a954e1c4ab3 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -671,11 +671,11 @@
          label="Block List"
          name="Block List">
             <menu_item_check.on_check
-             function="SideTray.CheckPanelPeopleTab"
-             parameter="blocked_panel" />
+             function="Floater.Visible"
+             parameter="blocked" />
             <menu_item_check.on_click
-              function="SideTray.PanelPeopleTab"
-              parameter="blocked_panel" />
+             function="Floater.Toggle"
+             parameter="blocked" />
         </menu_item_check>
       <menu_item_separator/>
       <menu_item_check
diff --git a/indra/newview/skins/default/xui/en/panel_block_avatar_rendering.xml b/indra/newview/skins/default/xui/en/panel_block_avatar_rendering.xml
new file mode 100644
index 00000000000..e43bf81032a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_block_avatar_rendering.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<panel
+ follows="all"
+ height="300"
+ label="AVATAR RENDERING"
+ layout="topleft"
+ name="panel_block_avatar_rendering"
+ width="350">
+    <string
+     name="av_never_render"
+     value="Never"/>
+    <string
+     name="av_always_render"
+     value="Always"/>
+    <name_list
+     draw_heading="true"
+     follows="all"
+     height="275"
+     layout="topleft"
+     left="1"
+     multi_select="false"
+     name="exception_list"
+     right="-1"
+     top="0" >
+        <name_list.columns
+         label="Name"
+         name="name"
+         relative_width="0.5" />
+        <name_list.columns
+         label="Render setting"
+         name="setting"
+         relative_width="0.25" />
+        <name_list.columns
+         label="Date added"
+         name="timestamp"
+         relative_width="0.25" />
+     </name_list>
+    <panel
+     follows="left|right|bottom"
+     height="25"
+     left="1"
+     layout="topleft"
+     name="bottom_panel"
+     right="-1"
+     top_pad="0" >
+        <button 
+         follows="left|bottom"
+         height="25"
+         image_hover_unselected="Toolbar_Left_Over"
+         image_overlay="AddItem_Off"
+         image_overlay_alignment="left"
+         image_selected="Toolbar_Left_Selected"
+         image_unselected="Toolbar_Left_Off"
+         label="Always Render"
+         left="1"
+         name="rendering_exception_always_btn"
+         tool_tip="Pick a resident to always render"
+         top="0"
+         width="119">
+            <button.commit_callback
+             function="Rendering.AddException"
+             parameter="always" />
+        </button>
+        <button 
+         follows="left|bottom"
+         height="25"
+         image_hover_unselected="Toolbar_Middle_Over"
+         image_overlay="AddItem_Off"
+         image_overlay_alignment="left"
+         image_selected="Toolbar_Middle_Selected"
+         image_unselected="Toolbar_Middle_Off"
+         label="Never Render"
+         left_pad="1"
+         name="rendering_exception_never_btn"
+         tool_tip="Pick a resident to never render"
+         width="109">
+            <button.commit_callback
+             function="Rendering.AddException"
+             parameter="never" />
+        </button>
+        <icon  
+         follows="left|bottom|right"
+         height="25"
+         image_name="Toolbar_Middle_Off"
+         left_pad="1"
+         right="-80"
+         name="rendering_spacer_icon" />
+        <button 
+         enabled="false"
+         follows="bottom|right"
+         height="25"
+         image_hover_unselected="Toolbar_Right_Over"
+         image_overlay="TrashItem_Off"
+         image_overlay_alignment="left"
+         image_selected="Toolbar_Right_Selected"
+         image_unselected="Toolbar_Right_Off"
+         label="Remove"
+         left_pad="1"
+         name="rendering_exception_trash_btn"
+         tool_tip="Remove the currently selected rendering exception"
+         width="79">
+            <button.commit_callback
+             function="Rendering.RemoveException" />
+        </button>
+    </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_block_derender.xml b/indra/newview/skins/default/xui/en/panel_block_derender.xml
new file mode 100644
index 00000000000..b5e1c2331ec
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_block_derender.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="all"
+ height="300"
+ label="DERENDERED LIST"
+ layout="topleft"
+ width="350">
+    <scroll_list
+     draw_border="false"
+     draw_heading="true"
+     draw_stripes="true"
+     follows="all"
+     height="275"
+     layout="topleft"
+     left="1"
+     multi_select="true"
+     name="derender_list"
+     right="-1"
+     tool_tip="List of currently derendered objects."
+     top="0" >
+        <scroll_list.columns
+         label="Object Name"
+         name="object_name" />
+        <scroll_list.columns
+         label="Location"
+         name="location"
+		 width="140" />
+        <scroll_list.columns
+         label="Type"
+         name="derender_type"
+         width="80" />
+    </scroll_list>
+    <panel
+     follows="left|right|bottom"
+     height="25"
+     left="1"
+     layout="topleft"
+     name="bottom_panel"
+     right="-1"
+     top_pad="0" >
+        <icon  
+         follows="bottom|left|right"
+         height="25"
+         image_name="Toolbar_Left_Off"
+         width="472"
+         left="1"
+         name="derender_spacer_icon"
+         right="-80"
+         top="0" />
+        <button 
+         enabled="false"
+         follows="bottom|right"
+         height="25"
+         image_hover_unselected="Toolbar_Right_Over"
+         image_overlay="TrashItem_Off"
+         image_overlay_alignment="left"
+         image_selected="Toolbar_Right_Selected"
+         image_unselected="Toolbar_Right_Off"
+         label="Restore"
+         left_pad="1"
+         name="derender_trash_btn"
+         tool_tip="Restore selected objects."
+         width="79" />
+    </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_block_list.xml b/indra/newview/skins/default/xui/en/panel_block_list.xml
new file mode 100644
index 00000000000..5594d7e57dc
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_block_list.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="all"
+ height="300"
+ label="BLOCKED LIST"
+ layout="topleft"
+ name="panel_block_list"
+ width="350">
+    <scroll_list
+     draw_border="false"
+     draw_heading="true"
+     draw_stripes="true"
+     follows="all"
+     height="275"
+     layout="topleft"
+     left="1"
+     multi_select="true"
+     name="block_list"
+     right="-1"
+     tool_tip="List of currently blocked Residents / Objects."
+     top="0" >
+        <scroll_list.columns
+         label="Name"
+         name="item_name" />
+        <scroll_list.columns
+         label="Block Type"
+         name="item_type"
+         width="100" />
+        <scroll_list.columns
+         can_sort="false"
+         halign="center"
+         label="T"
+         name="item_text"
+         tool_tip="Text"
+         width="20" />
+        <scroll_list.columns
+         can_sort="false"
+         halign="center"
+         label="V"
+         name="item_voice"
+         tool_tip="Voice"
+         width="20" />
+        <scroll_list.columns
+         can_sort="false"
+         halign="center"
+         label="P"
+         name="item_particles"
+         tool_tip="Particles"
+         width="20" />
+        <scroll_list.columns
+         can_sort="false"
+         halign="center"
+         label="S"
+         name="item_sounds"
+         tool_tip="Object Sounds"
+         width="20" />
+    </scroll_list>
+    <panel
+     follows="left|right|bottom"
+     height="25"
+     left="1"
+     layout="topleft"
+     name="bottom_panel"
+     right="-1"
+     top_pad="0" >
+        <button 
+         follows="left|bottom"
+         height="25"
+         image_hover_unselected="Toolbar_Left_Over"
+         image_overlay="AddItem_Off"
+         image_overlay_alignment="left"
+         image_selected="Toolbar_Left_Selected"
+         image_unselected="Toolbar_Left_Off"
+         label="Block Resident"
+         left="1"
+         name="block_resident_btn"
+         tool_tip="Pick a resident to block"
+         top="0"
+         width="119">
+            <button.commit_callback
+             function="Block.AddAvatar" />
+        </button>
+        <button 
+         follows="left|bottom"
+         height="25"
+         image_hover_unselected="Toolbar_Middle_Over"
+         image_overlay="AddItem_Off"
+         image_overlay_alignment="left"
+         image_selected="Toolbar_Middle_Selected"
+         image_unselected="Toolbar_Middle_Off"
+         label="Block Object"
+         left_pad="1"
+         name="block_object_btn"
+         tool_tip="Pick an object to block by name"
+         width="109">
+            <button.commit_callback
+             function="Block.AddByName" />
+        </button>
+        <icon  
+         follows="left|bottom|right"
+         height="25"
+         image_name="Toolbar_Middle_Off"
+         left_pad="1"
+         right="-80"
+         name="derenderx_spacer_icon" />
+        <button 
+         enabled="false"
+         follows="bottom|right"
+         height="25"
+         image_hover_unselected="Toolbar_Right_Over"
+         image_overlay="TrashItem_Off"
+         image_overlay_alignment="left"
+         image_selected="Toolbar_Right_Selected"
+         image_unselected="Toolbar_Right_Off"
+         label="Unblock"
+         left_pad="1"
+         name="block_trash_btn"
+         tool_tip="Remove selected items from the blocked list"
+         width="79">
+            <button.commit_callback
+             function="Block.Remove" />
+        </button>
+    </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 97b7964e8b9..a3451c92a5c 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -631,7 +631,7 @@ Learn about [https://community.secondlife.com/knowledgebase/joining-and-particip
 
 <!-- ================================= BLOCKED tab ========================== -->
 
-        <panel
+        <!--<panel
          background_opaque="true"
          background_visible="true"
          bg_alpha_color="DkGray"
@@ -657,6 +657,6 @@ Learn about [https://community.secondlife.com/knowledgebase/joining-and-particip
            font="SansSerifBold"
            top="0"
            right="-1" />
-        </panel>
+        </panel>-->
     </tab_container>
 </panel>
-- 
GitLab