diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 2502640b05b582eb7b68d0e9247464e67cab1054..c0d6eb5be5ab992b353b9cff495eff40c177895e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -257,7 +257,7 @@ set(viewer_SOURCE_FILES
     llfloaterconversationpreview.cpp
     llfloaterdeleteprefpreset.cpp
     llfloaterdestinations.cpp
-	llfloaterdisplayname.cpp
+    llfloaterdisplayname.cpp
     llfloatereditextdaycycle.cpp
     llfloaterenvironmentadjust.cpp
     llfloaterevent.cpp
@@ -459,6 +459,7 @@ set(viewer_SOURCE_FILES
     llpanelavatar.cpp
     llpanelavatartag.cpp
     llpanelblockedlist.cpp
+    llpanelclassified.cpp
     llpanelcontents.cpp
     llpaneleditsky.cpp
     llpaneleditwater.cpp
@@ -924,7 +925,7 @@ set(viewer_HEADER_FILES
     llfloaterconversationpreview.h
     llfloaterdeleteprefpreset.h
     llfloaterdestinations.h
-	llfloaterdisplayname.h
+    llfloaterdisplayname.h
     llfloatereditextdaycycle.h
     llfloaterenvironmentadjust.h
     llfloaterevent.h
@@ -1118,6 +1119,7 @@ set(viewer_HEADER_FILES
     llpanelavatar.h
     llpanelavatartag.h
     llpanelblockedlist.h
+    llpanelclassified.h
     llpanelcontents.h
     llpaneleditsky.h
     llpaneleditwater.h
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..183000ceac2cb9d07da7bc6bb1e254eb1d3f5aa2
--- /dev/null
+++ b/indra/newview/llpanelclassified.cpp
@@ -0,0 +1,564 @@
+/** 
+ * @file llpanelclassified.cpp
+ * @brief LLPanelClassifiedInfo class implementation
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2021, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+// Display of a classified used both for the global view in the
+// Find directory, and also for each individual user's classified in their
+// profile.
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanelclassified.h"
+
+#include "lldispatcher.h"
+#include "llfloaterreg.h"
+#include "llparcel.h"
+
+#include "llagent.h"
+#include "llclassifiedflags.h"
+#include "lliconctrl.h"
+#include "lltexturectrl.h"
+#include "llfloaterworldmap.h"
+#include "llviewergenericmessage.h"	// send_generic_message
+#include "llviewerregion.h"
+#include "llscrollcontainer.h"
+#include "llcorehttputil.h"
+
+//static
+LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels;
+static LLPanelInjector<LLPanelClassifiedInfo> t_panel_panel_classified_info("panel_classified_info");
+
+// "classifiedclickthrough"
+// strings[0] = classified_id
+// strings[1] = teleport_clicks
+// strings[2] = map_clicks
+// strings[3] = profile_clicks
+class LLDispatchClassifiedClickThrough : public LLDispatchHandler
+{
+public:
+	virtual bool operator()(
+		const LLDispatcher* dispatcher,
+		const std::string& key,
+		const LLUUID& invoice,
+		const sparam_t& strings)
+	{
+		if (strings.size() != 4) return false;
+		LLUUID classified_id(strings[0]);
+		S32 teleport_clicks = atoi(strings[1].c_str());
+		S32 map_clicks = atoi(strings[2].c_str());
+		S32 profile_clicks = atoi(strings[3].c_str());
+
+		LLPanelClassifiedInfo::setClickThrough(
+			classified_id, teleport_clicks, map_clicks, profile_clicks, false);
+
+		return true;
+	}
+};
+static LLDispatchClassifiedClickThrough sClassifiedClickThrough;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLPanelClassifiedInfo::LLPanelClassifiedInfo()
+ : LLPanel()
+ , mInfoLoaded(false)
+ , mScrollingPanel(NULL)
+ , mScrollContainer(NULL)
+ , mScrollingPanelMinHeight(0)
+ , mScrollingPanelWidth(0)
+ , mSnapshotStreched(false)
+ , mTeleportClicksOld(0)
+ , mMapClicksOld(0)
+ , mProfileClicksOld(0)
+ , mTeleportClicksNew(0)
+ , mMapClicksNew(0)
+ , mProfileClicksNew(0)
+ , mSnapshotCtrl(NULL)
+{
+	sAllPanels.push_back(this);
+}
+
+LLPanelClassifiedInfo::~LLPanelClassifiedInfo()
+{
+	sAllPanels.remove(this);
+}
+
+BOOL LLPanelClassifiedInfo::postBuild()
+{
+	childSetAction("show_on_map_btn", boost::bind(&LLPanelClassifiedInfo::onMapClick, this));
+	childSetAction("teleport_btn", boost::bind(&LLPanelClassifiedInfo::onTeleportClick, this));
+
+	mScrollingPanel = getChild<LLPanel>("scroll_content_panel");
+	mScrollContainer = getChild<LLScrollContainer>("profile_scroll");
+
+	mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight();
+	mScrollingPanelWidth = mScrollingPanel->getRect().getWidth();
+
+	mSnapshotCtrl = getChild<LLTextureCtrl>("classified_snapshot");
+	mSnapshotRect = getDefaultSnapshotRect();
+
+	return TRUE;
+}
+
+void LLPanelClassifiedInfo::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
+{
+	LLPanel::reshape(width, height, called_from_parent);
+
+	if (!mScrollContainer || !mScrollingPanel)
+		return;
+
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
+
+	S32 scroll_height = mScrollContainer->getRect().getHeight();
+	if (mScrollingPanelMinHeight >= scroll_height)
+	{
+		mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight);
+	}
+	else
+	{
+		mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height);
+	}
+
+	mSnapshotRect = getDefaultSnapshotRect();
+	stretchSnapshot();
+}
+
+void LLPanelClassifiedInfo::onOpen(const LLSD& key)
+{
+	LLUUID avatar_id = key["classified_creator_id"];
+	if(avatar_id.isNull())
+	{
+		return;
+	}
+
+	if(getAvatarId().notNull())
+	{
+		LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
+	}
+
+	setAvatarId(avatar_id);
+
+	resetData();
+	resetControls();
+	scrollToTop();
+
+	setClassifiedId(key["classified_id"]);
+	setClassifiedName(key["classified_name"]);
+	setDescription(key["classified_desc"]);
+	setSnapshotId(key["classified_snapshot_id"]);
+	setFromSearch(key["from_search"]);
+
+	LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL;
+
+	LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
+	LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId());
+	gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough);
+
+	if (gAgent.getRegion())
+	{
+		// While we're at it let's get the stats from the new table if that
+		// capability exists.
+		std::string url = gAgent.getRegion()->getCapability("SearchStatRequest");
+		if (!url.empty())
+		{
+			LL_INFOS() << "Classified stat request via capability" << LL_ENDL;
+			LLSD body;
+			LLUUID classifiedId = getClassifiedId();
+			body["classified_id"] = classifiedId;
+			LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body,
+				boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1));
+		}
+	}
+	// Update classified click stats.
+	// *TODO: Should we do this when opening not from search?
+	sendClickMessage("profile");
+
+	setInfoLoaded(false);
+}
+
+/*static*/
+void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result)
+{
+    S32 teleport = result["teleport_clicks"].asInteger();
+    S32 map = result["map_clicks"].asInteger();
+    S32 profile = result["profile_clicks"].asInteger();
+    S32 search_teleport = result["search_teleport_clicks"].asInteger();
+    S32 search_map = result["search_map_clicks"].asInteger();
+    S32 search_profile = result["search_profile_clicks"].asInteger();
+
+    LLPanelClassifiedInfo::setClickThrough(classifiedId,
+        teleport + search_teleport,
+        map + search_map,
+        profile + search_profile,
+        true);
+}
+
+void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type)
+{
+	if(APT_CLASSIFIED_INFO == type)
+	{
+		LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
+		if(c_info && getClassifiedId() == c_info->classified_id)
+		{
+			setClassifiedName(c_info->name);
+			setDescription(c_info->description);
+			setSnapshotId(c_info->snapshot_id);
+			setParcelId(c_info->parcel_id);
+			setPosGlobal(c_info->pos_global);
+			setSimName(c_info->sim_name);
+
+			setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global));
+			getChild<LLUICtrl>("category")->setValue(LLClassifiedInfo::sCategories[c_info->category]);
+
+			static std::string mature_str = getString("type_mature");
+			static std::string pg_str = getString("type_pg");
+			static LLUIString  price_str = getString("l$_price");
+			static std::string date_fmt = getString("date_fmt");
+
+			bool mature = is_cf_mature(c_info->flags);
+			getChild<LLUICtrl>("content_type")->setValue(mature ? mature_str : pg_str);
+			getChild<LLIconCtrl>("content_type_moderate")->setVisible(mature);
+			getChild<LLIconCtrl>("content_type_general")->setVisible(!mature);
+
+			std::string auto_renew_str = is_cf_auto_renew(c_info->flags) ? 
+				getString("auto_renew_on") : getString("auto_renew_off");
+			getChild<LLUICtrl>("auto_renew")->setValue(auto_renew_str);
+
+			price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing));
+			getChild<LLUICtrl>("price_for_listing")->setValue(LLSD(price_str));
+
+			std::string date_str = date_fmt;
+			LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date));
+			getChild<LLUICtrl>("creation_date")->setValue(date_str);
+
+			setInfoLoaded(true);
+
+			LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
+		}
+	}
+}
+
+void LLPanelClassifiedInfo::resetData()
+{
+	setClassifiedName(LLStringUtil::null);
+	setDescription(LLStringUtil::null);
+	setClassifiedLocation(LLStringUtil::null);
+	setClassifiedId(LLUUID::null);
+	setSnapshotId(LLUUID::null);
+	setPosGlobal(LLVector3d::zero);
+	setParcelId(LLUUID::null);
+	setSimName(LLStringUtil::null);
+	setFromSearch(false);
+
+	// reset click stats
+	mTeleportClicksOld	= 0;
+	mMapClicksOld		= 0;
+	mProfileClicksOld	= 0;
+	mTeleportClicksNew	= 0;
+	mMapClicksNew		= 0;
+	mProfileClicksNew	= 0;
+
+	getChild<LLUICtrl>("category")->setValue(LLStringUtil::null);
+	getChild<LLUICtrl>("content_type")->setValue(LLStringUtil::null);
+	getChild<LLUICtrl>("click_through_text")->setValue(LLStringUtil::null);
+	getChild<LLUICtrl>("price_for_listing")->setValue(LLStringUtil::null);
+	getChild<LLUICtrl>("auto_renew")->setValue(LLStringUtil::null);
+	getChild<LLUICtrl>("creation_date")->setValue(LLStringUtil::null);
+	getChild<LLUICtrl>("click_through_text")->setValue(LLStringUtil::null);
+	getChild<LLIconCtrl>("content_type_moderate")->setVisible(FALSE);
+	getChild<LLIconCtrl>("content_type_general")->setVisible(FALSE);
+}
+
+void LLPanelClassifiedInfo::resetControls()
+{
+	bool is_self = getAvatarId() == gAgent.getID();
+
+	getChildView("edit_btn")->setEnabled(is_self);
+	getChildView("edit_btn")->setVisible( is_self);
+	getChildView("price_layout_panel")->setVisible( is_self);
+	getChildView("clickthrough_layout_panel")->setVisible( is_self);
+}
+
+void LLPanelClassifiedInfo::setClassifiedName(const std::string& name)
+{
+	getChild<LLUICtrl>("classified_name")->setValue(name);
+}
+
+std::string LLPanelClassifiedInfo::getClassifiedName()
+{
+	return getChild<LLUICtrl>("classified_name")->getValue().asString();
+}
+
+void LLPanelClassifiedInfo::setDescription(const std::string& desc)
+{
+	getChild<LLUICtrl>("classified_desc")->setValue(desc);
+}
+
+std::string LLPanelClassifiedInfo::getDescription()
+{
+	return getChild<LLUICtrl>("classified_desc")->getValue().asString();
+}
+
+void LLPanelClassifiedInfo::setClassifiedLocation(const std::string& location)
+{
+	getChild<LLUICtrl>("classified_location")->setValue(location);
+}
+
+std::string LLPanelClassifiedInfo::getClassifiedLocation()
+{
+	return getChild<LLUICtrl>("classified_location")->getValue().asString();
+}
+
+void LLPanelClassifiedInfo::setSnapshotId(const LLUUID& id)
+{
+	mSnapshotCtrl->setValue(id);
+	mSnapshotStreched = false;
+}
+
+void LLPanelClassifiedInfo::draw()
+{
+	LLPanel::draw();
+
+	// Stretch in draw because it takes some time to load a texture,
+	// going to try to stretch snapshot until texture is loaded
+	if(!mSnapshotStreched)
+	{
+		stretchSnapshot();
+	}
+}
+
+LLUUID LLPanelClassifiedInfo::getSnapshotId()
+{
+	return getChild<LLUICtrl>("classified_snapshot")->getValue().asUUID();
+}
+
+// static
+void LLPanelClassifiedInfo::setClickThrough(
+	const LLUUID& classified_id,
+	S32 teleport,
+	S32 map,
+	S32 profile,
+	bool from_new_table)
+{
+	LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: ["
+			<< teleport << ", " << map << ", " << profile << "] ("
+			<< (from_new_table ? "new" : "old") << ")" << LL_ENDL;
+
+	for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter)
+	{
+		LLPanelClassifiedInfo* self = *iter;
+		if (self->getClassifiedId() != classified_id)
+		{
+			continue;
+		}
+
+		// *HACK: Skip LLPanelClassifiedEdit instances: they don't display clicks data.
+		// Those instances should not be in the list at all.
+		if (typeid(*self) != typeid(LLPanelClassifiedInfo))
+		{
+			continue;
+		}
+
+		LL_INFOS() << "Updating classified info panel" << LL_ENDL;
+
+		// We need to check to see if the data came from the new stat_table 
+		// or the old classified table. We also need to cache the data from 
+		// the two separate sources so as to display the aggregate totals.
+
+		if (from_new_table)
+		{
+			self->mTeleportClicksNew = teleport;
+			self->mMapClicksNew = map;
+			self->mProfileClicksNew = profile;
+		}
+		else
+		{
+			self->mTeleportClicksOld = teleport;
+			self->mMapClicksOld = map;
+			self->mProfileClicksOld = profile;
+		}
+
+		static LLUIString ct_str = self->getString("click_through_text_fmt");
+
+		ct_str.setArg("[TELEPORT]",	llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld));
+		ct_str.setArg("[MAP]",		llformat("%d", self->mMapClicksNew + self->mMapClicksOld));
+		ct_str.setArg("[PROFILE]",	llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld));
+
+		self->getChild<LLUICtrl>("click_through_text")->setValue(ct_str.getString());
+		// *HACK: remove this when there is enough room for click stats in the info panel
+		self->getChildView("click_through_text")->setToolTip(ct_str.getString());  
+
+		LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)
+				<< ", map: "    << llformat("%d", self->mMapClicksNew + self->mMapClicksOld)
+				<< ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)
+				<< LL_ENDL;
+	}
+}
+
+// static
+std::string LLPanelClassifiedInfo::createLocationText(
+	const std::string& original_name, 
+	const std::string& sim_name, 
+	const LLVector3d& pos_global)
+{
+	std::string location_text;
+	
+	location_text.append(original_name);
+
+	if (!sim_name.empty())
+	{
+		if (!location_text.empty()) 
+			location_text.append(", ");
+		location_text.append(sim_name);
+	}
+
+	if (!location_text.empty()) 
+		location_text.append(" ");
+
+	if (!pos_global.isNull())
+	{
+		S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
+		S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
+		S32 region_z = ll_round((F32)pos_global.mdV[VZ]);
+		location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z));
+	}
+
+	return location_text;
+}
+
+void LLPanelClassifiedInfo::stretchSnapshot()
+{
+	// *NOTE dzaporozhan
+	// Could be moved to LLTextureCtrl
+
+	LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture();
+
+	if(!texture)
+	{
+		return;
+	}
+
+	if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight())
+	{
+		// looks like texture is not loaded yet
+		return;
+	}
+
+	LLRect rc = mSnapshotRect;
+	// *HACK dzaporozhan
+	// LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes
+	// drawn texture to be smaller than expected. (see LLTextureCtrl::draw())
+	// Lets increase texture height to force texture look as expected.
+	rc.mBottom -= BTN_HEIGHT_SMALL;
+
+	F32 t_width = texture->getFullWidth();
+	F32 t_height = texture->getFullHeight();
+
+	F32 ratio = llmin<F32>( (rc.getWidth() / t_width), (rc.getHeight() / t_height) );
+
+	t_width *= ratio;
+	t_height *= ratio;
+
+	rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height));
+	mSnapshotCtrl->setShape(rc);
+
+	mSnapshotStreched = true;
+}
+
+LLRect LLPanelClassifiedInfo::getDefaultSnapshotRect()
+{
+	// Using scroll container makes getting default rect a hard task
+	// because rect in postBuild() and in first reshape() is not the same.
+	// Using snapshot_panel makes it easier to reshape snapshot.
+	return getChild<LLUICtrl>("snapshot_panel")->getLocalRect();
+}
+
+void LLPanelClassifiedInfo::scrollToTop()
+{
+	LLScrollContainer* scrollContainer = findChild<LLScrollContainer>("profile_scroll");
+	if (scrollContainer)
+		scrollContainer->goToTop();
+}
+
+// static
+// *TODO: move out of the panel
+void LLPanelClassifiedInfo::sendClickMessage(
+		const std::string& type,
+		bool from_search,
+		const LLUUID& classified_id,
+		const LLUUID& parcel_id,
+		const LLVector3d& global_pos,
+		const std::string& sim_name)
+{
+	if (gAgent.getRegion())
+	{
+		// You're allowed to click on your own ads to reassure yourself
+		// that the system is working.
+		LLSD body;
+		body["type"]			= type;
+		body["from_search"]		= from_search;
+		body["classified_id"]	= classified_id;
+		body["parcel_id"]		= parcel_id;
+		body["dest_pos_global"]	= global_pos.getValue();
+		body["region_name"]		= sim_name;
+
+		std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");
+		LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL;
+		LL_INFOS() << "body: [" << body << "]" << LL_ENDL;
+        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
+            "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent.");
+	}
+}
+
+void LLPanelClassifiedInfo::sendClickMessage(const std::string& type)
+{
+	sendClickMessage(
+		type,
+		fromSearch(),
+		getClassifiedId(),
+		getParcelId(),
+		getPosGlobal(),
+		getSimName());
+}
+
+void LLPanelClassifiedInfo::onMapClick()
+{
+	sendClickMessage("map");
+	LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
+	LLFloaterReg::showInstance("world_map", "center");
+}
+
+void LLPanelClassifiedInfo::onTeleportClick()
+{
+	if (!getPosGlobal().isExactlyZero())
+	{
+		sendClickMessage("teleport");
+		gAgent.teleportViaLocation(getPosGlobal());
+		LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
+	}
+}
+
+//EOF
diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h
new file mode 100644
index 0000000000000000000000000000000000000000..471becd0f7fe330dc0c34bc001a394f72cd2668d
--- /dev/null
+++ b/indra/newview/llpanelclassified.h
@@ -0,0 +1,175 @@
+/** 
+ * @file llpanelclassified.h
+ * @brief LLPanelClassifiedInfo class definition
+ *
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2021, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+// Display of a classified used both for the global view in the
+// Find directory, and also for each individual user's classified in their
+// profile.
+#ifndef LL_LLPANELCLASSIFIED_H
+#define LL_LLPANELCLASSIFIED_H
+
+#include "llavatarpropertiesprocessor.h"
+#include "llclassifiedinfo.h"
+#include "llfloater.h"
+#include "llpanel.h"
+#include "llrect.h"
+
+class LLScrollContainer;
+class LLTextureCtrl;
+
+class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver
+{
+	LOG_CLASS(LLPanelClassifiedInfo);
+public:
+
+	LLPanelClassifiedInfo();
+	virtual ~LLPanelClassifiedInfo();
+
+	/*virtual*/ void onOpen(const LLSD& key);
+
+	/*virtual*/ BOOL postBuild();
+
+	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
+
+	void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; }
+
+	LLUUID& getAvatarId() { return mAvatarId; }
+
+	void setSnapshotId(const LLUUID& id);
+
+	LLUUID getSnapshotId();
+
+	void setClassifiedId(const LLUUID& id) { mClassifiedId = id; }
+
+	LLUUID& getClassifiedId() { return mClassifiedId; }
+
+	void setClassifiedName(const std::string& name);
+
+	std::string getClassifiedName();
+
+	void setDescription(const std::string& desc);
+
+	std::string getDescription();
+
+	void setClassifiedLocation(const std::string& location);
+
+	std::string getClassifiedLocation();
+
+	void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; }
+
+	LLVector3d& getPosGlobal() { return mPosGlobal; }
+
+	void setParcelId(const LLUUID& id) { mParcelId = id; }
+
+	LLUUID getParcelId() { return mParcelId; }
+
+	void setSimName(const std::string& sim_name) { mSimName = sim_name; }
+
+	std::string getSimName() { return mSimName; }
+
+	void setFromSearch(bool val) { mFromSearch = val; }
+
+	bool fromSearch() { return mFromSearch; }
+
+	bool getInfoLoaded() { return mInfoLoaded; }
+
+	void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; }
+
+	static void setClickThrough(
+		const LLUUID& classified_id,
+		S32 teleport,
+		S32 map,
+		S32 profile,
+		bool from_new_table);
+
+	static void sendClickMessage(
+			const std::string& type,
+			bool from_search,
+			const LLUUID& classified_id,
+			const LLUUID& parcel_id,
+			const LLVector3d& global_pos,
+			const std::string& sim_name);
+
+	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+
+	/*virtual*/ void draw();
+
+protected:
+
+	virtual void resetData();
+
+	virtual void resetControls();
+
+	static std::string createLocationText(
+		const std::string& original_name,
+		const std::string& sim_name, 
+		const LLVector3d& pos_global);
+
+	void stretchSnapshot();
+	void sendClickMessage(const std::string& type);
+
+	LLRect getDefaultSnapshotRect();
+
+	void scrollToTop();
+
+	void onMapClick();
+	void onTeleportClick();
+
+	bool mSnapshotStreched;
+	LLRect mSnapshotRect;
+	LLTextureCtrl* mSnapshotCtrl;
+
+private:
+
+	LLUUID mAvatarId;
+	LLUUID mClassifiedId;
+	LLVector3d mPosGlobal;
+	LLUUID mParcelId;
+	std::string mSimName;
+	bool mFromSearch;
+	bool mInfoLoaded;
+
+	LLScrollContainer*		mScrollContainer;
+	LLPanel*				mScrollingPanel;
+
+	S32 mScrollingPanelMinHeight;
+	S32 mScrollingPanelWidth;
+
+	// Needed for stat tracking
+	S32 mTeleportClicksOld;
+	S32 mMapClicksOld;
+	S32 mProfileClicksOld;
+	S32 mTeleportClicksNew;
+	S32 mMapClicksNew;
+	S32 mProfileClicksNew;
+
+    static void handleSearchStatResponse(LLUUID classifiedId, LLSD result);
+
+
+	typedef std::list<LLPanelClassifiedInfo*> panel_list_t;
+	static panel_list_t sAllPanels;
+};
+
+#endif // LL_LLPANELCLASSIFIED_H
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 1787b132d1b9d65f620014c9eadeaa2a86704cd8..fb6248910cd20deb980148491229dae0e974af16 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -64,7 +64,7 @@
 #include "llpanelprofilepicks.h"
 #include "lltrans.h"
 #include "llviewercontrol.h"
-#include "llviewermenu.h"
+#include "llviewermenu.h" //is_agent_mappable
 #include "llvoiceclient.h"
 #include "llweb.h"
 #include "rlvhandler.h"
@@ -1219,10 +1219,24 @@ void LLPanelProfileFirstLife::updateButtons()
 
 LLPanelProfileNotes::LLPanelProfileNotes()
 : LLPanelProfileTab()
+, mAvatarNameCacheConnection()
 {
 
 }
 
+LLPanelProfileNotes::~LLPanelProfileNotes()
+{
+    if (getAvatarId().notNull())
+    {
+        LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
+    }
+
+    if (mAvatarNameCacheConnection.connected())
+    {
+        mAvatarNameCacheConnection.disconnect();
+    }
+}
+
 void LLPanelProfileNotes::updateData()
 {
     LLUUID avatar_id = getAvatarId();
@@ -1239,6 +1253,7 @@ BOOL LLPanelProfileNotes::postBuild()
     mMapRights = getChild<LLCheckBoxCtrl>("map_check");
     mEditObjectRights = getChild<LLCheckBoxCtrl>("objects_check");
     mNotesEditor = getChild<LLTextEditor>("notes_edit");
+    mCharacterLimitWarning = getChild<LLTextBox>("character_limit_warning");
 
     mEditObjectRights->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitRights, this));
 
@@ -1254,6 +1269,8 @@ void LLPanelProfileNotes::onOpen(const LLSD& key)
     resetData();
 
     fillRightsData();
+
+    mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileNotes::onAvatarNameCache, this, _1, _2));
 }
 
 void LLPanelProfileNotes::apply()
@@ -1361,6 +1378,27 @@ void LLPanelProfileNotes::applyRights()
     LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(getAvatarId(), rights);
 }
 
+void LLPanelProfileNotes::updateWarning()
+{
+    mCharacterLimitWarning->setText(std::string());
+
+    std::string str = getString("header_symbol_limit");
+    mCharacterLimitWarning->appendText(str, false, LLStyle::Params().color(LLColor4::yellow));
+    mCharacterLimitWarning->appendText(" ", false, LLStyle::Params());
+
+    LLStringUtil::format_map_t args;
+    if (!mURLWebProfile.empty())
+    {
+        args["[PROFILE_URL]"] = mURLWebProfile;
+    }
+    else
+    {
+        args["[PROFILE_URL]"] = getProfileURL(getAvatarId().asString());
+    }
+    str = getString("body_symbol_limit", args);
+    mCharacterLimitWarning->appendText(str, false, LLStyle::Params());
+}
+
 void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType type)
 {
     if (APT_NOTES == type)
@@ -1372,6 +1410,16 @@ void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType typ
             mNotesEditor->setEnabled(TRUE);
             updateButtons();
 
+            if (avatar_notes->notes.size() > 1000)
+            {
+                mCharacterLimitWarning->setVisible(TRUE);
+                updateWarning();
+            }
+            else
+            {
+                mCharacterLimitWarning->setVisible(FALSE);
+            }
+
             LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this);
         }
     }
@@ -1384,6 +1432,9 @@ void LLPanelProfileNotes::resetData()
     mOnlineStatus->setValue(FALSE);
     mMapRights->setValue(FALSE);
     mEditObjectRights->setValue(FALSE);
+    mCharacterLimitWarning->setVisible(FALSE);
+
+    mURLWebProfile.clear();
 }
 
 void LLPanelProfileNotes::enableCheckboxes(bool enable)
@@ -1393,14 +1444,6 @@ void LLPanelProfileNotes::enableCheckboxes(bool enable)
     mEditObjectRights->setEnabled(enable);
 }
 
-LLPanelProfileNotes::~LLPanelProfileNotes()
-{
-    if (getAvatarId().notNull())
-    {
-        LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
-    }
-}
-
 // virtual, called by LLAvatarTracker
 void LLPanelProfileNotes::changed(U32 mask)
 {
@@ -1421,6 +1464,28 @@ void LLPanelProfileNotes::setAvatarId(const LLUUID& avatar_id)
     }
 }
 
+void LLPanelProfileNotes::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+    mAvatarNameCacheConnection.disconnect();
+
+    std::string username = av_name.getAccountName();
+    if (username.empty())
+    {
+        username = LLCacheName::buildUsername(av_name.getDisplayName());
+    }
+    else
+    {
+        LLStringUtil::replaceChar(username, ' ', '.');
+    }
+
+    mURLWebProfile = getProfileURL(username, false);
+
+    if (mCharacterLimitWarning->getVisible())
+    {
+        updateWarning();
+    }
+}
+
 
 //////////////////////////////////////////////////////////////////////////
 // LLPanelProfile
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index 1696294fca3b5d832e6adc238450a2f6e03c2f03..66ba3e0fdb57b5b65781c49174d11a4952bc72ea 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -361,6 +361,8 @@ class LLPanelProfileNotes
 	 */
 	virtual void apply();
 
+    void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+
 protected:
 	/**
 	 * Fills rights data for friends.
@@ -374,11 +376,17 @@ class LLPanelProfileNotes
 	void enableCheckboxes(bool enable);
 
 	void applyRights();
+    void updateWarning();
 
     LLCheckBoxCtrl*     mOnlineStatus;
 	LLCheckBoxCtrl*     mMapRights;
 	LLCheckBoxCtrl*     mEditObjectRights;
 	LLTextEditor*       mNotesEditor;
+    LLTextBox*          mCharacterLimitWarning;
+
+    std::string			mURLWebProfile;
+
+    boost::signals2::connection	mAvatarNameCacheConnection;
 };
 
 
diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp
index 161826ee56aa25b7b76710eaa4ad7e3d737df2b1..607954e53365d51fa357e2091cc19880548eeaf6 100644
--- a/indra/newview/llpanelprofileclassifieds.cpp
+++ b/indra/newview/llpanelprofileclassifieds.cpp
@@ -37,6 +37,7 @@
 #include "llcorehttputil.h"
 #include "lldispatcher.h"
 #include "llfloaterreg.h"
+#include "llfloatersidepanelcontainer.h"
 #include "llfloaterworldmap.h"
 #include "lliconctrl.h"
 #include "lllineeditor.h"
@@ -72,13 +73,16 @@ LLPanelProfileClassified::panel_list_t LLPanelProfileClassified::sAllPanels;
 static LLPanelInjector<LLPanelProfileClassifieds> t_panel_profile_classifieds("panel_profile_classifieds");
 static LLPanelInjector<LLPanelProfileClassified> t_panel_profile_classified("panel_profile_classified");
 
-class LLClassifiedHandler : public LLCommandHandler
+class LLClassifiedHandler : public LLCommandHandler, public LLAvatarPropertiesObserver
 {
 public:
     // throttle calls from untrusted browsers
     LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) {}
-
-    bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+	
+	std::set<LLUUID> mClassifiedIds;
+	std::string mRequestVerb;
+    
+	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
     {
         if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableClassifieds"))
         {
@@ -111,7 +115,10 @@ class LLClassifiedHandler : public LLCommandHandler
         const std::string verb = params[1].asString();
         if (verb == "about")
         {
-            LLAvatarActions::showClassified(gAgent.getID(), classified_id, false);
+            mRequestVerb = verb;
+            mClassifiedIds.insert(classified_id);
+            LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
+            LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id);
             return true;
         }
         else if (verb == "edit")
@@ -122,6 +129,53 @@ class LLClassifiedHandler : public LLCommandHandler
 
         return false;
     }
+
+    void openClassified(LLAvatarClassifiedInfo* c_info)
+    {
+        if (mRequestVerb == "about")
+        {
+            if (c_info->creator_id == gAgent.getID())
+            {
+                LLAvatarActions::showClassified(gAgent.getID(), c_info->classified_id, false);
+            }
+            else
+            {
+                LLSD params;
+                params["id"] = c_info->creator_id;
+                params["open_tab_name"] = "panel_picks";
+                params["show_tab_panel"] = "classified_details";
+                params["classified_id"] = c_info->classified_id;
+                params["classified_creator_id"] = c_info->creator_id;
+                params["classified_snapshot_id"] = c_info->snapshot_id;
+                params["classified_name"] = c_info->name;
+                params["classified_desc"] = c_info->description;
+                params["from_search"] = true;
+                LLFloaterSidePanelContainer::showPanel("picks", params);
+            }
+        }
+    }
+
+    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 detail side tray for this classified
+        openClassified(c_info);
+
+        // remove our observer now that we're done
+        mClassifiedIds.erase(c_info->classified_id);
+        LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this);
+    }
 };
 LLClassifiedHandler gClassifiedHandler;
 
@@ -264,6 +318,9 @@ void LLPanelProfileClassifieds::callbackDeleteClassified(const LLSD& notificatio
         }
 
         updateButtons();
+
+        BOOL no_data = !mTabContainer->getTabCount();
+        mNoItemsLabel->setVisible(no_data);
     }
 }
 
diff --git a/indra/newview/skins/default/xui/en/floater_picks.xml b/indra/newview/skins/default/xui/en/floater_picks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3cd6abafe54a51bbfd2e6da2b664e9fc570e42e2
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_picks.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<floater
+ positioning="cascading"
+ can_close="true"
+ can_resize="false"
+ height="572"
+ help_topic="sidebar_me"
+ min_width="333"
+ min_height="440"
+ name="floater_picks"
+ save_rect="true"
+ save_visibility="false"
+ reuse_instance="true"
+ title="Picks"
+ width="333" >
+   <panel
+    class="panel_classified_info"
+    name="main_panel"
+    filename="panel_classified_info.xml"
+    follows="all"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/panel_classified_info.xml b/indra/newview/skins/default/xui/en/panel_classified_info.xml
index d4a2745d1d694f262b2727950f433ddd70550400..04a0bc800d8882ff2870aea6d18f1b024d4317a7 100644
--- a/indra/newview/skins/default/xui/en/panel_classified_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_classified_info.xml
@@ -38,28 +38,15 @@
   name="auto_renew_off">
     Disabled
  </panel.string>
-    <button
-     follows="top|left"
-     height="24"
-     image_hover_unselected="BackButton_Over"
-     image_pressed="BackButton_Press"
-     image_unselected="BackButton_Off"
-     layout="topleft"
-     name="back_btn"
-     left="10"
-     tab_stop="false"
-     top="2"
-     width="30"
-     use_draw_context_alpha="false" />
     <text
      follows="top|left|right"
      font="SansSerifHugeBold"
      height="26"
      layout="topleft"
-     left_pad="4"
+     left="12"
      name="title"
      text_color="LtGray"
-     top="0"
+     top="2"
      value="Classified Info"
      use_ellipses="true"
      width="275" />
@@ -420,7 +407,7 @@
 		         height="23"
 		         label="Teleport"
 		         layout="topleft"
-		         left="0"
+		         left="2"
 		         name="teleport_btn"
 		         top="0"
 		         width="101" />	
@@ -443,24 +430,6 @@
 		         top="0"
 		         width="100" />
 		  </layout_panel>	  
-		  
-		  <layout_panel
-			  follows="bottom|left|right"
-			  height="23"
-			  layout="bottomleft"
-			  left_pad="3"
-			  name="edit_btn_lp"
-		      auto_resize="true"
-			  width="101">
-			  <button
-		         follows="bottom|left|right"
-		         height="23"
-		         label="Edit"
-		         layout="topleft"
-		         name="edit_btn"
-		         top="0"
-		         width="101" />
-		  </layout_panel>
 	   </layout_stack>
     </panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_notes.xml b/indra/newview/skins/default/xui/en/panel_profile_notes.xml
index 0bafaac36132503317215bb568ca1eaf323ba657..179fa0136caeb8ec945a6185630ff668af1280f7 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_notes.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_notes.xml
@@ -9,6 +9,14 @@
  follows="all"
  layout="topleft"
 >
+    <!--these strings will be combined into one with different styles-->
+    <string name="header_symbol_limit">
+Warning: Your notes contain more than 1000 characters.
+    </string>
+    <string name="body_symbol_limit">
+Only first 1000 characters are shown here. If you edit your notes and click OK, the extra characters will be lost. To preserve the extra characters, you must edit it [[PROFILE_URL] on the web]
+    </string>
+
     <loading_indicator
      name="progress_indicator"
      top="3"
@@ -36,16 +44,27 @@
      top_pad="4"
      left="6"
      right="-6"
-     height="335"
+     height="311"
      follows="all"
      layout="topleft"
      max_length="1000"
      word_wrap="true"
     />
+    <text
+     layout="topleft"
+     follows="left|bottom|right"
+     top_pad="2"
+     left="6"
+     right="-6"
+     height ="28"
+     name="character_limit_warning"
+     word_wrap="true">
+      Placeholder: Your notes contain more than 1000 characters. Only first 1000 characters are shown here. If you edit your notes and click OK, the extra characters will be lost. To preserve the extra characters, you must edit it [https://my.secondlife.com/settings/profile on the web]
+    </text>
     <text
      name="status_message2"
      value="Allow this avatar to:"
-     top_pad="8"
+     top_pad="11"
      left="6"
      right="-6"
      height="16"
@@ -57,6 +76,7 @@
      name="status_check"
      label="See when I am online"
      enabled="false"
+     top_pad="0"
      left="10"
      height="16"
      width="293"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_web.xml b/indra/newview/skins/default/xui/en/panel_profile_web.xml
index af2ac57f589c173307ef53db9faf866913501328..e0cb4d3d06f9ec6130db17b96a39d0fc9c3fbc47 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_web.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_web.xml
@@ -31,5 +31,6 @@
      follows="bottom|left|right"
      layout="topleft"
      halign="center"
+     parse_urls="false"
     />
 </panel>