diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp
index 7cda2d31e66ec154a91874b993a04e6913b0acaa..33e5046f5062b5fa90a99dc510a9ae2f226d9a96 100644
--- a/indra/newview/llavatarpropertiesprocessor.cpp
+++ b/indra/newview/llavatarpropertiesprocessor.cpp
@@ -440,11 +440,17 @@ void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id,void* data, E
 	// Copy the map (because observers may delete themselves when updated?)
 	LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers;
 
-	observer_multimap_t::iterator oi = observers.lower_bound(id);
-	observer_multimap_t::iterator end = observers.upper_bound(id);
+	observer_multimap_t::iterator oi = observers.begin();
+	observer_multimap_t::iterator end = observers.end();
 	for (; oi != end; ++oi)
 	{
-		oi->second->processProperties(data,type);
+		// only notify observers for the same agent, or if the observer
+		// didn't know the agent ID and passed a NULL id.
+		const LLUUID &agent_id = oi->first;
+		if (agent_id == id || agent_id.isNull())
+		{
+			oi->second->processProperties(data,type);
+		}
 	}
 }
 
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
index 59a68bc12d04bb40e8ffa3176e823cb29e983051..7d21867efcbfaab673ba37797b091677ad3bb760 100644
--- a/indra/newview/llpanelpicks.cpp
+++ b/indra/newview/llpanelpicks.cpp
@@ -37,6 +37,7 @@
 #include "llagent.h"
 #include "llagentpicksinfo.h"
 #include "llavatarconstants.h"
+#include "llcommandhandler.h"
 #include "llflatlistview.h"
 #include "llfloaterreg.h"
 #include "llfloaterworldmap.h"
@@ -55,6 +56,8 @@
 #include "llpanelprofile.h"
 #include "llpanelpick.h"
 #include "llpanelclassified.h"
+#include "llpanelprofileview.h"
+#include "llsidetray.h"
 
 static const std::string XML_BTN_NEW = "new_btn";
 static const std::string XML_BTN_DELETE = "trash_btn";
@@ -72,6 +75,83 @@ static const std::string CLASSIFIED_NAME("classified_name");
 
 static LLRegisterPanelClassWrapper<LLPanelPicks> t_panel_picks("panel_picks");
 
+class LLClassifiedHandler :
+	public LLCommandHandler,
+	public LLAvatarPropertiesObserver
+{
+public:
+	// throttle calls from untrusted browsers
+	LLClassifiedHandler() :	LLCommandHandler("classified", UNTRUSTED_THROTTLE) {}
+
+	std::set<LLUUID> mClassifiedIds;
+
+	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+	{
+		if (params.size() < 2)
+		{
+			return false;
+		}
+
+		// get the ID for the classified
+		LLUUID classified_id;
+		if (!classified_id.set(params[0], FALSE))
+		{
+			return false;
+		}
+
+		// show the classified in the side tray.
+		// need to ask the server for more info first though...
+		const std::string verb = params[1].asString();
+		if (verb == "about")
+		{
+			mClassifiedIds.insert(classified_id);
+			LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
+			LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id);
+			return true;
+		}
+
+		return false;
+	}
+
+	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type)
+	{
+		if (APT_CLASSIFIED_INFO != type)
+		{
+			return;
+		}
+
+		// is this the classified that we asked for?
+		LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
+		if (!c_info || mClassifiedIds.find(c_info->classified_id) == mClassifiedIds.end())
+		{
+			return;
+		}
+
+		// open the people profile page for the classified's owner
+		LLSD params;
+		params["id"] = c_info->creator_id;
+		params["classified"] = c_info->classified_id;
+		params["open_tab_name"] = "panel_profile";
+		LLPanelProfileView *profile = dynamic_cast<LLPanelProfileView*>(LLSideTray::getInstance()->showPanel("panel_profile_view", params));
+
+		// then open the classified panel on this user's profile panel
+		if (profile)
+		{
+			LLPanelPicks* panel_picks = profile->getChild<LLPanelPicks>("panel_picks");
+			if (panel_picks)
+			{
+				panel_picks->openClassifiedInfo(c_info);
+			}
+		}
+
+		// remove our observer now that we're done
+		mClassifiedIds.erase(c_info->classified_id);
+		LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this);
+	}
+
+};
+LLClassifiedHandler gClassifiedHandler;
+
 //////////////////////////////////////////////////////////////////////////
 
 /**
@@ -624,6 +704,25 @@ void LLPanelPicks::openClassifiedInfo()
 	getProfilePanel()->openPanel(mPanelClassifiedInfo, params);
 }
 
+void LLPanelPicks::openClassifiedInfo(LLAvatarClassifiedInfo *c_info)
+{
+	if (! c_info)
+	{
+		return;
+	}
+
+	createClassifiedInfoPanel();
+
+	LLSD params;
+	params["classified_id"] = c_info->classified_id;
+	params["avatar_id"] = c_info->creator_id;
+	params["snapshot_id"] = c_info->snapshot_id;
+	params["name"] = c_info->name;
+	params["desc"] = c_info->description;
+
+	getProfilePanel()->openPanel(mPanelClassifiedInfo, params);
+}
+
 void LLPanelPicks::showAccordion(const std::string& name, bool show)
 {
 	LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(name);
diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h
index 21794d56b2fe06ee952a33da2c3912d2cde5d132..893a0c53a3b1bcf0fc9ceb4a034a229089e8075f 100644
--- a/indra/newview/llpanelpicks.h
+++ b/indra/newview/llpanelpicks.h
@@ -86,6 +86,9 @@ class LLPanelPicks
 	// parent panels failed to work (picks related code was in my profile panel)
 	void setProfilePanel(LLPanelProfile* profile_panel);
 
+	// display the info panel for the given classified
+	void openClassifiedInfo(LLAvatarClassifiedInfo *c_info);
+
 protected:
 	/*virtual*/void updateButtons();