diff --git a/doc/contributions.txt b/doc/contributions.txt
index 9266ae3c5b2f4d97dbe17231ba6b8c0549226b50..f21354b4069d4d9516fa8761d39f4721a18e5014 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -366,15 +366,17 @@ JB Kraft
 Joghert LeSabre
 	VWR-64
 Jonathan Yap
-	STORM-596
 	STORM-523
+	STORM-596
+	STORM-615
 	STORM-616
 	STORM-679
-	STORM-737
+	STORM-723
 	STORM-726
+	STORM-737
+	STORM-785
 	STORM-812
 	VWR-17801
-	STORM-785
 Kage Pixel
 	VWR-11
 Ken March
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index dbe0cf5cd051eb02b865210c6c39e104fc1caa6e..25a1b05d8ec2cd7a3b9ef2c962c6f49073753340 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -61,7 +61,7 @@ if (WINDOWS)
       /Oy-
       )
      
-  if(MSVC80 OR MSVC90)
+  if(MSVC)
     set(CMAKE_CXX_FLAGS_RELEASE
       "${CMAKE_CXX_FLAGS_RELEASE} -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
       CACHE STRING "C++ compiler release options" FORCE)
@@ -69,7 +69,7 @@ if (WINDOWS)
     add_definitions(
       /Zc:wchar_t-
       )
-  endif (MSVC80 OR MSVC90)
+  endif (MSVC)
   
   # Are we using the crummy Visual Studio KDU build workaround?
   if (NOT VS_DISABLE_FATAL_WARNINGS)
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 7ce57a5572336c4927a7f2b6e4e97d4e3aecb745..0b7eb7e99bb4386b1c025e3cba5339e1a452830c 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -10,23 +10,15 @@ if (STANDALONE)
   set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
   set(BOOST_REGEX_LIBRARY boost_regex-mt)
   set(BOOST_SIGNALS_LIBRARY boost_signals-mt)
+  set(BOOST_SYSTEM_LIBRARY boost_system-mt)
+  set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
 else (STANDALONE)
   use_prebuilt_binary(boost)
   set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 
   if (WINDOWS)
-    set(BOOST_VERSION 1_39)
-    if (MSVC71)
-      set(BOOST_PROGRAM_OPTIONS_LIBRARY 
-          optimized libboost_program_options-vc71-mt-s-${BOOST_VERSION}
-          debug libboost_program_options-vc71-mt-sgd-${BOOST_VERSION})
-      set(BOOST_REGEX_LIBRARY
-          optimized libboost_regex-vc71-mt-s-${BOOST_VERSION}
-          debug libboost_regex-vc71-mt-sgd-${BOOST_VERSION})
-      set(BOOST_SIGNALS_LIBRARY 
-          optimized libboost_signals-vc71-mt-s-${BOOST_VERSION}
-          debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION})
-    else (MSVC71)
+    set(BOOST_VERSION 1_45)
+    if(MSVC80)
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
           optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
           debug libboost_program_options-vc80-mt-gd-${BOOST_VERSION})
@@ -36,14 +28,38 @@ else (STANDALONE)
       set(BOOST_SIGNALS_LIBRARY 
           optimized libboost_signals-vc80-mt-${BOOST_VERSION}
           debug libboost_signals-vc80-mt-gd-${BOOST_VERSION})
-    endif (MSVC71)
+      set(BOOST_SYSTEM_LIBRARY 
+          optimized libboost_system-vc80-mt-${BOOST_VERSION}
+          debug libboost_system-vc80-mt-gd-${BOOST_VERSION})
+      set(BOOST_FILESYSTEM_LIBRARY 
+          optimized libboost_filesystem-vc80-mt-${BOOST_VERSION}
+          debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION})
+    else(MSVC80)
+      # MSVC 10.0 config
+      set(BOOST_PROGRAM_OPTIONS_LIBRARY 
+          optimized libboost_program_options-vc100-mt
+          debug libboost_program_options-vc100-mt-gd)
+      set(BOOST_REGEX_LIBRARY
+          optimized libboost_regex-vc100-mt
+          debug libboost_regex-vc100-mt-gd)
+      set(BOOST_SYSTEM_LIBRARY 
+          optimized libboost_system-vc100-mt
+          debug libboost_system-vc100-mt-gd)
+      set(BOOST_FILESYSTEM_LIBRARY 
+          optimized libboost_filesystem-vc100-mt
+          debug libboost_filesystem-vc100-mt-gd)    
+    endif (MSVC80)
   elseif (DARWIN)
     set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt)
     set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt)
     set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt)
+    set(BOOST_SYSTEM_LIBRARY boost_system-xgcc40-mt)
+    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-xgcc40-mt)
   elseif (LINUX)
     set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt)
     set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt)
     set(BOOST_SIGNALS_LIBRARY boost_signals-gcc41-mt)
+    set(BOOST_SYSTEM_LIBRARY boost_system-gcc41-mt)
+    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-gcc41-mt)
   endif (WINDOWS)
 endif (STANDALONE)
diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp
index c34115ee8064a6d8a63b3ad03ad85e7d44b5dfed..217e26c3ca527380c91fd8bbc1e1d42d3debc83b 100644
--- a/indra/integration_tests/llui_libtest/llui_libtest.cpp
+++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp
@@ -33,6 +33,7 @@
 // linden library includes
 #include "llcontrol.h"		// LLControlGroup
 #include "lldir.h"
+#include "lldiriterator.h"
 #include "llerrorcontrol.h"
 #include "llfloater.h"
 #include "llfontfreetype.h"
@@ -174,7 +175,9 @@ void export_test_floaters()
 	std::string delim = gDirUtilp->getDirDelimiter();
 	std::string xui_dir = get_xui_dir() + "en" + delim;
 	std::string filename;
-	while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename))
+
+	LLDirIterator iter(xui_dir, "floater_test_*.xml");
+	while (iter.next(filename))
 	{
 		if (filename.find("_new.xml") != std::string::npos)
 		{
diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp
index d909516bf8fbce6872458eec049e0b4c836df6ae..808ab3f64f81ab2da3d945212f7a510a251018ef 100644
--- a/indra/linux_updater/linux_updater.cpp
+++ b/indra/linux_updater/linux_updater.cpp
@@ -33,6 +33,7 @@
 #include "llerrorcontrol.h"
 #include "llfile.h"
 #include "lldir.h"
+#include "lldiriterator.h"
 #include "llxmlnode.h"
 #include "lltrans.h"
 
@@ -55,6 +56,8 @@ typedef struct _updater_app_state {
 	std::string strings_dirs;
 	std::string strings_file;
 
+	LLDirIterator *image_dir_iter;
+
 	GtkWidget *window;
 	GtkWidget *progress_bar;
 	GtkWidget *image;
@@ -108,7 +111,7 @@ bool translate_init(std::string comma_delim_path_list,
 void updater_app_ui_init(void);
 void updater_app_quit(UpdaterAppState *app_state);
 void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state);
-std::string next_image_filename(std::string& image_path);
+std::string next_image_filename(std::string& image_path, LLDirIterator& iter);
 void display_error(GtkWidget *parent, std::string title, std::string message);
 BOOL install_package(std::string package_file, std::string destination);
 BOOL spawn_viewer(UpdaterAppState *app_state);
@@ -174,7 +177,7 @@ void updater_app_ui_init(UpdaterAppState *app_state)
 
 		// load the first image
 		app_state->image = gtk_image_new_from_file
-			(next_image_filename(app_state->image_dir).c_str());
+			(next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str());
 		gtk_widget_set_size_request(app_state->image, 340, 310);
 		gtk_container_add(GTK_CONTAINER(frame), app_state->image);
 
@@ -205,7 +208,7 @@ gboolean rotate_image_cb(gpointer data)
 	llassert(data != NULL);
 	app_state = (UpdaterAppState *) data;
 
-	filename = next_image_filename(app_state->image_dir);
+	filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter);
 
 	gdk_threads_enter();
 	gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str());
@@ -214,10 +217,10 @@ gboolean rotate_image_cb(gpointer data)
 	return TRUE;
 }
 
-std::string next_image_filename(std::string& image_path)
+std::string next_image_filename(std::string& image_path, LLDirIterator& iter)
 {
 	std::string image_filename;
-	gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename);
+	iter.next(image_filename);
 	return image_path + "/" + image_filename;
 }
 
@@ -741,6 +744,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
 		else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc))
 		{
 			app_state->image_dir = argv[i];
+			app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg");
 		}
 		else if ((!strcmp(argv[i], "--dest")) && (++i < argc))
 		{
@@ -825,6 +829,7 @@ int main(int argc, char **argv)
 	}
 
 	bool success = !app_state->failure;
+	delete app_state->image_dir_iter;
 	delete app_state;
 	return success ? 0 : 1;
 }
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 8f02391e75a7dcbcf6f2d1b8734aca1550d7969f..c32a776c3f591f81e22fbabaf88af90d61266d7d 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -92,6 +92,17 @@ LLFILE*	LLFile::_fsopen(const std::string& filename, const char* mode, int shari
 #endif
 }
 
+int	LLFile::close(LLFILE * file)
+{
+	int ret_value = 0;
+	if (file)
+	{
+		ret_value = fclose(file);
+	}
+	return ret_value;
+}
+
+
 int	LLFile::remove(const std::string& filename)
 {
 #if	LL_WINDOWS
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 4913af7cb54dc52d09b81c2b67a6180e0673db90..dd7d36513a06d13c81638c1d7eafbdac2e60ab9e 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -71,6 +71,8 @@ class LL_COMMON_API LLFile
 	static	LLFILE*	fopen(const std::string& filename,const char* accessmode);	/* Flawfinder: ignore */
 	static	LLFILE*	_fsopen(const std::string& filename,const char* accessmode,int	sharingFlag);
 
+	static	int		close(LLFILE * file);
+
 	// perms is a permissions mask like 0777 or 0700.  In most cases it will
 	// be overridden by the user's umask.  It is ignored on Windows.
 	static	int		mkdir(const std::string& filename, int perms = 0700);
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index d30697e1784487c2f9694dae189b3d3ac9e11bf3..c4257827152fab8bf99420a3d2cb02e871f2f00b 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -272,9 +272,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
 	
 	initFromParams(p);
 	
-	// chrome floaters don't take focus at all
-	setFocusRoot(!getIsChrome());
-
 	initFloater(p);
 }
 
@@ -2910,8 +2907,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
 	params.from_xui = true;
 	applyXUILayout(params, parent);
  	initFromParams(params);
-	// chrome floaters don't take focus at all
-	setFocusRoot(!getIsChrome());
 
 	initFloater(params);
 	
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 6c0d47ef63d08ffc776cb5bf2cb3de240c93585d..32d7be377a3386a34f769fbb20876712b7b0ef3f 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -1637,6 +1637,10 @@ LLMenuScrollItem::LLMenuScrollItem(const Params& p)
 	}
 
 	LLButton::Params bparams;
+
+	// Disabled the Return key handling by LLMenuScrollItem instead of
+	// passing the key press to the currently selected menu item. See STORM-385.
+	bparams.commit_on_return(false);
 	bparams.mouse_opaque(true);
 	bparams.scale_image(false);
 	bparams.click_callback(p.scroll_callback);
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 4f7b4be52609206899dee5e9934bdf6c9aa49d62..9db1feafd1b179c9bea839139188158b4b4de205 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -36,6 +36,7 @@
 #include "llcachename.h"
 #include "lltrans.h"
 #include "lluicolortable.h"
+#include "message.h"
 
 #define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
 
@@ -684,8 +685,8 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
 LLStyle::Params LLUrlEntryGroup::getStyle() const
 {
 	LLStyle::Params style_params = LLUrlEntryBase::getStyle();
-	style_params.color = LLUIColorTable::instance().getColor("GroupLinkColor");
-	style_params.readonly_color = LLUIColorTable::instance().getColor("GroupLinkColor");
+	style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+	style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
 	return style_params;
 }
 
@@ -740,6 +741,13 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
 	return LLUrlEntryBase::getLocation(url);
 }
 
+// LLUrlEntryParcel statics.
+LLUUID	LLUrlEntryParcel::sAgentID(LLUUID::null);
+LLUUID	LLUrlEntryParcel::sSessionID(LLUUID::null);
+LLHost	LLUrlEntryParcel::sRegionHost(LLHost::invalid);
+bool	LLUrlEntryParcel::sDisconnected(false);
+std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers;
+
 ///
 /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
 /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
@@ -751,13 +759,88 @@ LLUrlEntryParcel::LLUrlEntryParcel()
 							boost::regex::perl|boost::regex::icase);
 	mMenuName = "menu_url_parcel.xml";
 	mTooltip = LLTrans::getString("TooltipParcelUrl");
+
+	sParcelInfoObservers.insert(this);
+}
+
+LLUrlEntryParcel::~LLUrlEntryParcel()
+{
+	sParcelInfoObservers.erase(this);
 }
 
 std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
 {
+	LLSD path_array = LLURI(url).pathArray();
+	S32 path_parts = path_array.size();
+
+	if (path_parts < 3) // no parcel id
+	{
+		llwarns << "Failed to parse url [" << url << "]" << llendl;
+		return url;
+	}
+
+	std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id
+
+	// Add an observer to call LLUrlLabelCallback when we have parcel name.
+	addObserver(parcel_id_string, url, cb);
+
+	LLUUID parcel_id(parcel_id_string);
+
+	sendParcelInfoRequest(parcel_id);
+
 	return unescapeUrl(url);
 }
 
+void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id)
+{
+	if (sRegionHost == LLHost::invalid || sDisconnected) return;
+
+	LLMessageSystem *msg = gMessageSystem;
+	msg->newMessage("ParcelInfoRequest");
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, sAgentID );
+	msg->addUUID("SessionID", sSessionID);
+	msg->nextBlock("Data");
+	msg->addUUID("ParcelID", parcel_id);
+	msg->sendReliable(sRegionHost);
+}
+
+void LLUrlEntryParcel::onParcelInfoReceived(const std::string &id, const std::string &label)
+{
+	callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon);
+}
+
+// static
+void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data)
+{
+	std::string label(LLStringUtil::null);
+	if (!parcel_data.name.empty())
+	{
+		label = parcel_data.name;
+	}
+	// If parcel name is empty use Sim_name (x, y, z) for parcel label.
+	else if (!parcel_data.sim_name.empty())
+	{
+		S32 region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS;
+		S32 region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS;
+		S32 region_z = llround(parcel_data.global_z);
+
+		label = llformat("%s (%d, %d, %d)",
+				parcel_data.sim_name.c_str(), region_x, region_y, region_z);
+	}
+
+	for (std::set<LLUrlEntryParcel*>::iterator iter = sParcelInfoObservers.begin();
+			iter != sParcelInfoObservers.end();
+			++iter)
+	{
+		LLUrlEntryParcel* url_entry = *iter;
+		if (url_entry)
+		{
+			url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label);
+		}
+	}
+}
+
 //
 // LLUrlEntryPlace Describes secondlife://<location> URLs
 //
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 1791739061cdae4c3cf3db6891984ef99d2eeb08..5f82721c0fdf9067383f1d974a052242c4c8a2a3 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -31,6 +31,9 @@
 #include "lluuid.h"
 #include "lluicolor.h"
 #include "llstyle.h"
+
+#include "llhost.h" // for resolving parcel name by parcel id
+
 #include <boost/signals2.hpp>
 #include <boost/regex.hpp>
 #include <string>
@@ -285,8 +288,44 @@ class LLUrlEntryObjectIM : public LLUrlEntryBase
 class LLUrlEntryParcel : public LLUrlEntryBase
 {
 public:
+	struct LLParcelData
+	{
+		LLUUID		parcel_id;
+		std::string	name;
+		std::string	sim_name;
+		F32			global_x;
+		F32			global_y;
+		F32			global_z;
+	};
+
 	LLUrlEntryParcel();
+	~LLUrlEntryParcel();
 	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+
+	// Sends a parcel info request to sim.
+	void sendParcelInfoRequest(const LLUUID& parcel_id);
+
+	// Calls observers of certain parcel id providing them with parcel label.
+	void onParcelInfoReceived(const std::string &id, const std::string &label);
+
+	// Processes parcel label and triggers notifying observers.
+	static void processParcelInfo(const LLParcelData& parcel_data);
+
+	// Next 4 setters are used to update agent and viewer connection information
+	// upon events like user login, viewer disconnect and user changing region host.
+	// These setters are made public to be accessible from newview and should not be
+	// used in other cases.
+	static void setAgentID(const LLUUID& id) { sAgentID = id; }
+	static void setSessionID(const LLUUID& id) { sSessionID = id; }
+	static void setRegionHost(const LLHost& host) { sRegionHost = host; }
+	static void setDisconnected(bool disconnected) { sDisconnected = disconnected; }
+
+private:
+	static LLUUID						sAgentID;
+	static LLUUID						sSessionID;
+	static LLHost						sRegionHost;
+	static bool							sDisconnected;
+	static std::set<LLUrlEntryParcel*>	sParcelInfoObservers;
 };
 
 ///
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index f30704cb2269c8b40b9fd5b0f44fe51aa934e7db..96ebe83826c5137dd90cd0458620a15d2777a4c8 100644
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -30,6 +30,7 @@
 #include "llavatarnamecache.h"
 #include "llcachename.h"
 #include "lluuid.h"
+#include "message.h"
 
 #include <string>
 
@@ -191,3 +192,20 @@ LLFontGL* LLFontGL::getFontDefault()
 {
 	return NULL; 
 }
+
+char* _PREHASH_AgentData = "AgentData";
+char* _PREHASH_AgentID = "AgentID";
+
+LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS);
+
+LLMessageSystem* gMessageSystem = NULL;
+
+//
+// Stub implementation for LLMessageSystem
+//
+void LLMessageSystem::newMessage(const char *name) { }
+void LLMessageSystem::nextBlockFast(const char *blockname) { }
+void LLMessageSystem::nextBlock(const char *blockname) { }
+void LLMessageSystem::addUUIDFast( const char *varname, const LLUUID& uuid) { }
+void LLMessageSystem::addUUID( const char *varname, const LLUUID& uuid) { }
+S32 LLMessageSystem::sendReliable(const LLHost &host) { return 0; }
diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt
index 722f4e2bfdef9c6212c9edf06f2abee5f55ff996..a3782d824b4cbbcf0abe31ecb5d754238cf3c8a5 100644
--- a/indra/llvfs/CMakeLists.txt
+++ b/indra/llvfs/CMakeLists.txt
@@ -12,6 +12,7 @@ include_directories(
 
 set(llvfs_SOURCE_FILES
     lldir.cpp
+    lldiriterator.cpp
     lllfsthread.cpp
     llpidlock.cpp
     llvfile.cpp
@@ -24,6 +25,7 @@ set(llvfs_HEADER_FILES
 
     lldir.h
     lldirguard.h
+    lldiriterator.h
     lllfsthread.h
     llpidlock.h
     llvfile.h
@@ -60,6 +62,11 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES})
 
 add_library (llvfs ${llvfs_SOURCE_FILES})
 
+target_link_libraries(llvfs
+    ${BOOST_FILESYSTEM_LIBRARY}
+    ${BOOST_SYSTEM_LIBRARY}
+    )
+
 if (DARWIN)
   include(CMakeFindFrameworks)
   find_library(CARBON_LIBRARY Carbon)
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index 64556bcb4c34dcacd2b48f391dbfebf0eb528421..ab7d15dfefdcbec79c3d894b19dee81f0352b0a3 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -40,6 +40,8 @@
 #include "lltimer.h"	// ms_sleep()
 #include "lluuid.h"
 
+#include "lldiriterator.h"
+
 #if LL_WINDOWS
 #include "lldir_win32.h"
 LLDir_Win32 gDirUtil;
@@ -83,7 +85,9 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
 	std::string filename; 
 	std::string fullpath;
 	S32 result;
-	while (getNextFileInDir(dirname, mask, filename))
+
+	LLDirIterator iter(dirname, mask);
+	while (iter.next(filename))
 	{
 		fullpath = dirname;
 		fullpath += getDirDelimiter();
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 42996fd051b9f5cc8ed949645fa7fda5c4c58f74..5ee8bdb542da2ebc4ee3d10ce114a7df3c1e20b6 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -75,31 +75,6 @@ class LLDir
 // pure virtual functions
 	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0;
 
-    /// Walk the files in a directory, with file pattern matching
-	virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash!
-                                  const std::string& mask,    ///< file pattern string (use "*" for all)
-                                  std::string& fname          ///< output: found file name
-                                  ) = 0;
-    /**<
-     * @returns true if a file was found, false if the entire directory has been scanned.
-     *
-     * @note that this function is NOT thread safe
-     *
-     * This function may not be used to scan part of a directory, then start a new search of a different
-     * directory, and then restart the first search where it left off; the entire search must run to
-     * completion or be abandoned - there is no restart.
-     *
-     * @bug: See http://jira.secondlife.com/browse/VWR-23697
-     *       and/or the tests in test/lldir_test.cpp
-     *       This is known to fail with patterns that have both:
-     *       a wildcard left of a . and more than one sequential ? right of a .
-     *       the pattern foo.??x appears to work
-     *       but *.??x or foo?.??x do not
-     *
-     * @todo this really should be rewritten as an iterator object, and the
-     *       filtering should be done in a platform-independent way.
-     */
-
 	virtual std::string getCurPath() = 0;
 	virtual BOOL fileExists(const std::string &filename) const = 0;
 
diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp
index 73f2336f94fa70bf2d43bc6b924ed6262b7bd2e8..4ba2f519b0f8080d700dd4c672abeac8ce803962 100644
--- a/indra/llvfs/lldir_linux.cpp
+++ b/indra/llvfs/lldir_linux.cpp
@@ -242,68 +242,6 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &
 	return (file_count);
 }
 
-// get the next file in the directory
-BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
-	glob_t g;
-	BOOL result = FALSE;
-	fname = "";
-	
-	if(!(dirname == mCurrentDir))
-	{
-		// different dir specified, close old search
-		mCurrentDirIndex = -1;
-		mCurrentDirCount = -1;
-		mCurrentDir = dirname;
-	}
-	
-	std::string tmp_str;
-	tmp_str = dirname;
-	tmp_str += mask;
-
-	if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
-	{
-		if(g.gl_pathc > 0)
-		{
-			if((int)g.gl_pathc != mCurrentDirCount)
-			{
-				// Number of matches has changed since the last search, meaning a file has been added or deleted.
-				// Reset the index.
-				mCurrentDirIndex = -1;
-				mCurrentDirCount = g.gl_pathc;
-			}
-	
-			mCurrentDirIndex++;
-	
-			if(mCurrentDirIndex < (int)g.gl_pathc)
-			{
-//				llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
-				// The API wants just the filename, not the full path.
-				//fname = g.gl_pathv[mCurrentDirIndex];
-
-				char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-				
-				if(s == NULL)
-					s = g.gl_pathv[mCurrentDirIndex];
-				else if(s[0] == '/')
-					s++;
-					
-				fname = s;
-				
-				result = TRUE;
-			}
-		}
-		
-		globfree(&g);
-	}
-	
-	return(result);
-}
-
-
-
-
 std::string LLDir_Linux::getCurPath()
 {
 	char tmp_str[LL_MAX_PATH];	/* Flawfinder: ignore */ 
diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h
index 451e81ae93c560114b83f556120f3fd42f6dbec9..ff4c48759a03327d6b04191d3b179451ad0fd3fd 100644
--- a/indra/llvfs/lldir_linux.h
+++ b/indra/llvfs/lldir_linux.h
@@ -43,7 +43,6 @@ class LLDir_Linux : public LLDir
 public:	
 	virtual std::string getCurPath();
 	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
-	virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
 	/*virtual*/ BOOL fileExists(const std::string &filename) const;
 
 	/*virtual*/ std::string getLLPluginLauncher();
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index 445285aa43ac2c5dae2c11187e73280dc88614db..2d039527c06fa05286ddcbd04226a4425c0e85fb 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -258,67 +258,6 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma
 	return (file_count);
 }
 
-// get the next file in the directory
-BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
-	glob_t g;
-	BOOL result = FALSE;
-	fname = "";
-	
-	if(!(dirname == mCurrentDir))
-	{
-		// different dir specified, close old search
-		mCurrentDirIndex = -1;
-		mCurrentDirCount = -1;
-		mCurrentDir = dirname;
-	}
-	
-	std::string tmp_str;
-	tmp_str = dirname;
-	tmp_str += mask;
-
-	if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
-	{
-		if(g.gl_pathc > 0)
-		{
-			if(g.gl_pathc != mCurrentDirCount)
-			{
-				// Number of matches has changed since the last search, meaning a file has been added or deleted.
-				// Reset the index.
-				mCurrentDirIndex = -1;
-				mCurrentDirCount = g.gl_pathc;
-			}
-	
-			mCurrentDirIndex++;
-	
-			if(mCurrentDirIndex < g.gl_pathc)
-			{
-//				llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
-				// The API wants just the filename, not the full path.
-				//fname = g.gl_pathv[mCurrentDirIndex];
-
-				char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-				
-				if(s == NULL)
-					s = g.gl_pathv[mCurrentDirIndex];
-				else if(s[0] == '/')
-					s++;
-					
-				fname = s;
-				
-				result = TRUE;
-			}
-		}
-		
-		globfree(&g);
-	}
-	
-	return(result);
-}
-
-
-
 S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask)
 {
 	glob_t g;
diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h
index 4eac3c3ae6fce824624bc7c048b8922c6c86e517..e60d5e41c2deca2e9aaca01d8f34306fbb896c1a 100644
--- a/indra/llvfs/lldir_mac.h
+++ b/indra/llvfs/lldir_mac.h
@@ -43,7 +43,6 @@ class LLDir_Mac : public LLDir
 	virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask);
 	virtual std::string getCurPath();
 	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
-	virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
 	virtual BOOL fileExists(const std::string &filename) const;
 
 	/*virtual*/ std::string getLLPluginLauncher();
diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp
index 515fd66b6e9a9f4d2aef1647ad78134a15419f0c..21f8c3acdbeefa56272bac597cf5b1d1858ba46c 100644
--- a/indra/llvfs/lldir_solaris.cpp
+++ b/indra/llvfs/lldir_solaris.cpp
@@ -260,68 +260,6 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string
 	return (file_count);
 }
 
-// get the next file in the directory
-BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
-	glob_t g;
-	BOOL result = FALSE;
-	fname = "";
-	
-	if(!(dirname == mCurrentDir))
-	{
-		// different dir specified, close old search
-		mCurrentDirIndex = -1;
-		mCurrentDirCount = -1;
-		mCurrentDir = dirname;
-	}
-	
-	std::string tmp_str;
-	tmp_str = dirname;
-	tmp_str += mask;
-
-	if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
-	{
-		if(g.gl_pathc > 0)
-		{
-			if((int)g.gl_pathc != mCurrentDirCount)
-			{
-				// Number of matches has changed since the last search, meaning a file has been added or deleted.
-				// Reset the index.
-				mCurrentDirIndex = -1;
-				mCurrentDirCount = g.gl_pathc;
-			}
-	
-			mCurrentDirIndex++;
-	
-			if(mCurrentDirIndex < (int)g.gl_pathc)
-			{
-//				llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
-				// The API wants just the filename, not the full path.
-				//fname = g.gl_pathv[mCurrentDirIndex];
-
-				char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-				
-				if(s == NULL)
-					s = g.gl_pathv[mCurrentDirIndex];
-				else if(s[0] == '/')
-					s++;
-					
-				fname = s;
-				
-				result = TRUE;
-			}
-		}
-		
-		globfree(&g);
-	}
-	
-	return(result);
-}
-
-
-
-
 std::string LLDir_Solaris::getCurPath()
 {
 	char tmp_str[LL_MAX_PATH];	/* Flawfinder: ignore */ 
diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h
index 4a1794f53950dab8f147dae3c4bc9cfe4e3b1088..f7e1a6301dbdc19a713e568d44cb28812b048427 100644
--- a/indra/llvfs/lldir_solaris.h
+++ b/indra/llvfs/lldir_solaris.h
@@ -43,7 +43,6 @@ class LLDir_Solaris : public LLDir
 public:	
 	virtual std::string getCurPath();
 	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
-	virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
 	/*virtual*/ BOOL fileExists(const std::string &filename) const;
 
 private:
diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp
index 33718e520d71b4c3e2595574187c22d0224c0ce7..2f96fbbbc10d2aeee4a78a3c29742aacad05c6e2 100644
--- a/indra/llvfs/lldir_win32.cpp
+++ b/indra/llvfs/lldir_win32.cpp
@@ -236,67 +236,6 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string &
 	return (file_count);
 }
 
-
-// get the next file in the directory
-BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
-    BOOL fileFound = FALSE;
-	fname = "";
-
-	WIN32_FIND_DATAW FileData;
-    llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask);
-
-	if (pathname != mCurrentDir)
-	{
-		// different dir specified, close old search
-		if (mCurrentDir[0])
-		{
-			FindClose(mDirSearch_h);
-		}
-		mCurrentDir = pathname;
-
-		// and open new one
-		// Check error opening Directory structure
-		if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE)   
-		{
-           fileFound = TRUE;
-		}
-	}
-
-    // Loop to skip over the current (.) and parent (..) directory entries
-    // (apparently returned in Win7 but not XP)
-    do
-    {
-       if (   fileFound
-           && (  (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0)
-               ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0)
-               )
-           )
-       {
-          fileFound = FALSE;
-       }
-    } while (   mDirSearch_h != INVALID_HANDLE_VALUE
-             && !fileFound
-             && (fileFound = FindNextFile(mDirSearch_h, &FileData)
-                 )
-             );
-
-    if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES)
-    {
-       // No more files, so reset to beginning of directory
-       FindClose(mDirSearch_h);
-       mCurrentDir[0] = '\000';
-    }
-
-    if (fileFound)
-    {
-        // convert from TCHAR to char
-        fname = utf16str_to_utf8str(FileData.cFileName);
-	}
-    
-	return fileFound;
-}
-
 std::string LLDir_Win32::getCurPath()
 {
 	WCHAR w_str[MAX_PATH];
diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h
index 4c932c932c8f06d6015c106f2b2cd8c9bd50e7f6..19c610eb8b2f6aeee28622a62568a7e14df7517d 100644
--- a/indra/llvfs/lldir_win32.h
+++ b/indra/llvfs/lldir_win32.h
@@ -40,15 +40,12 @@ class LLDir_Win32 : public LLDir
 
 	/*virtual*/ std::string getCurPath();
 	/*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask);
-	/*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
 	/*virtual*/ BOOL fileExists(const std::string &filename) const;
 
 	/*virtual*/ std::string getLLPluginLauncher();
 	/*virtual*/ std::string getLLPluginFilename(std::string base_name);
 
 private:
-	BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname);
-	
 	void* mDirSearch_h;
 	llutf16string mCurrentDir;
 };
diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5536ed8f69a97c49721cf0242d8a97bf5d89ad1f
--- /dev/null
+++ b/indra/llvfs/lldiriterator.cpp
@@ -0,0 +1,203 @@
+/**
+ * @file lldiriterator.cpp
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#include "lldiriterator.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/regex.hpp>
+
+namespace fs = boost::filesystem;
+
+static std::string glob_to_regex(const std::string& glob);
+
+class LLDirIterator::Impl
+{
+public:
+	Impl(const std::string &dirname, const std::string &mask);
+	~Impl();
+
+	bool next(std::string &fname);
+
+private:
+	boost::regex			mFilterExp;
+	fs::directory_iterator	mIter;
+	bool					mIsValid;
+};
+
+LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask)
+	: mIsValid(false)
+{
+	fs::path dir_path(dirname);
+
+	// Check if path exists.
+	if (!fs::exists(dir_path))
+	{
+		llerrs << "Invalid path: \"" << dir_path.string() << "\"" << llendl;
+		return;
+	}
+
+	// Initialize the directory iterator for the given path.
+	try
+	{
+		mIter = fs::directory_iterator(dir_path);
+	}
+	catch (fs::basic_filesystem_error<fs::path>& e)
+	{
+		llerrs << e.what() << llendl;
+		return;
+	}
+
+	// Convert the glob mask to a regular expression
+	std::string exp = glob_to_regex(mask);
+
+	// Initialize boost::regex with the expression converted from
+	// the glob mask.
+	// An exception is thrown if the expression is not valid.
+	try
+	{
+		mFilterExp.assign(exp);
+	}
+	catch (boost::regex_error& e)
+	{
+		llerrs << "\"" << exp << "\" is not a valid regular expression: "
+				<< e.what() << llendl;
+		return;
+	}
+
+	mIsValid = true;
+}
+
+LLDirIterator::Impl::~Impl()
+{
+}
+
+bool LLDirIterator::Impl::next(std::string &fname)
+{
+	fname = "";
+
+	if (!mIsValid)
+	{
+		llerrs << "The iterator is not correctly initialized." << llendl;
+		return false;
+	}
+
+	fs::directory_iterator end_itr; // default construction yields past-the-end
+	bool found = false;
+	while (mIter != end_itr && !found)
+	{
+		boost::smatch match;
+		std::string name = mIter->path().filename();
+		if (found = boost::regex_match(name, match, mFilterExp))
+		{
+			fname = name;
+		}
+
+		++mIter;
+	}
+
+	return found;
+}
+
+std::string glob_to_regex(const std::string& glob)
+{
+	std::string regex;
+	regex.reserve(glob.size()<<1);
+	S32 braces = 0;
+	bool escaped = false;
+	bool square_brace_open = false;
+
+	for (std::string::const_iterator i = glob.begin(); i != glob.end(); ++i)
+	{
+		char c = *i;
+
+		switch (c)
+		{
+			case '.':
+				regex+="\\.";
+				break;
+			case '*':
+				if (glob.begin() == i)
+				{
+					regex+="[^.].*";
+				}
+				else
+				{
+					regex+= escaped ? "*" : ".*";
+				}
+				break;
+			case '?':
+				regex+= escaped ? '?' : '.';
+				break;
+			case '{':
+				braces++;
+				regex+='(';
+				break;
+			case '}':
+				if (!braces)
+				{
+					llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl;
+				}
+
+				regex+=')';
+				braces--;
+				break;
+			case ',':
+				regex+= braces ? '|' : c;
+				break;
+			case '!':
+				regex+= square_brace_open ? '^' : c;
+				break;
+			default:
+				regex+=c;
+				break;
+		}
+
+		escaped = ('\\' == c);
+		square_brace_open = ('[' == c);
+	}
+
+	if (braces)
+	{
+		llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl;
+	}
+
+	return regex;
+}
+
+LLDirIterator::LLDirIterator(const std::string &dirname, const std::string &mask)
+{
+	mImpl = new Impl(dirname, mask);
+}
+
+LLDirIterator::~LLDirIterator()
+{
+	delete mImpl;
+}
+
+bool LLDirIterator::next(std::string &fname)
+{
+	return mImpl->next(fname);
+}
diff --git a/indra/llvfs/lldiriterator.h b/indra/llvfs/lldiriterator.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b48be41b321c71935957773ea5a43494c9d5959
--- /dev/null
+++ b/indra/llvfs/lldiriterator.h
@@ -0,0 +1,87 @@
+/**
+ * @file lldiriterator.h
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#ifndef LL_LLDIRITERATOR_H
+#define LL_LLDIRITERATOR_H
+
+#include "linden_common.h"
+
+/**
+ * Class LLDirIterator
+ *
+ * Iterates through directory entries matching the search pattern.
+ */
+class LLDirIterator
+{
+public:
+	/**
+	 * Constructs LLDirIterator object to search for glob pattern
+	 * matches in a directory.
+	 *
+	 * @param dirname - name of a directory to search in.
+	 * @param mask - search pattern, a glob expression
+	 *
+	 * Wildcards supported in glob expressions:
+	 * --------------------------------------------------------------
+	 * | Wildcard 	| Matches										|
+	 * --------------------------------------------------------------
+	 * | 	* 		|zero or more characters						|
+	 * | 	?		|exactly one character							|
+	 * | [abcde]	|exactly one character listed					|
+	 * | [a-e]		|exactly one character in the given range		|
+	 * | [!abcde]	|any character that is not listed				|
+	 * | [!a-e]		|any character that is not in the given range	|
+	 * | {abc,xyz}	|exactly one entire word in the options given	|
+	 * --------------------------------------------------------------
+	 */
+	LLDirIterator(const std::string &dirname, const std::string &mask);
+
+	~LLDirIterator();
+
+	/**
+	 * Searches for the next directory entry matching the glob mask
+	 * specified upon iterator construction.
+	 * Returns true if a match is found, sets fname
+	 * parameter to the name of the matched directory entry and
+	 * increments the iterator position.
+	 *
+	 * Typical usage:
+	 * <code>
+	 * LLDirIterator iter(directory, pattern);
+	 * if ( iter.next(scanResult) )
+	 * </code>
+	 *
+	 * @param fname - name of the matched directory entry.
+	 * @return true if a match is found, false otherwise.
+	 */
+	bool next(std::string &fname);
+
+protected:
+	class Impl;
+	Impl* mImpl;
+};
+
+#endif //LL_LLDIRITERATOR_H
diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp
index 8788bd63e87d2b8030324ffcd0e0434057844151..ea321c5ae958829d739137eae3548f5cbf07c540 100644
--- a/indra/llvfs/tests/lldir_test.cpp
+++ b/indra/llvfs/tests/lldir_test.cpp
@@ -28,6 +28,7 @@
 #include "linden_common.h"
 
 #include "../lldir.h"
+#include "../lldiriterator.h"
 
 #include "../test/lltut.h"
 
@@ -259,13 +260,12 @@ namespace tut
 
    std::string makeTestFile( const std::string& dir, const std::string& file )
    {
-      std::string delim = gDirUtilp->getDirDelimiter();
-      std::string path = dir + delim + file;
+      std::string path = dir + file;
       LLFILE* handle = LLFile::fopen( path, "w" );
       ensure("failed to open test file '"+path+"'", handle != NULL );
       // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs
       // returns EOF; otherwise, it returns some other, nonnegative value."
-      ensure("failed to write to test file '"+path+"'", fputs("test file", handle) >= 0);
+      ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) );
       fclose(handle);
       return path;
    }
@@ -290,7 +290,7 @@ namespace tut
    }
 
    static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" };
-   
+
    void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5])
    {
 
@@ -300,7 +300,8 @@ namespace tut
       bool  filesFound[5] = { false, false, false, false, false };
       //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n";
 
-      while ( found <= 5 && gDirUtilp->getNextFileInDir(directory, pattern, scanResult) )
+      LLDirIterator iter(directory, pattern);
+      while ( found <= 5 && iter.next(scanResult) )
       {
          found++;
          //std::cerr << "  found '"+scanResult+"'\n";
@@ -334,15 +335,15 @@ namespace tut
    
    template<> template<>
    void LLDirTest_object_t::test<5>()
-      // getNextFileInDir
+      // LLDirIterator::next
    {
       std::string delim = gDirUtilp->getDirDelimiter();
       std::string dirTemp = LLFile::tmpdir();
 
       // Create the same 5 file names of the two directories
 
-      std::string dir1 = makeTestDir(dirTemp + "getNextFileInDir");
-      std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir");
+      std::string dir1 = makeTestDir(dirTemp + "LLDirIterator");
+      std::string dir2 = makeTestDir(dirTemp + "LLDirIterator");
       std::string dir1files[5];
       std::string dir2files[5];
       for (int i=0; i<5; i++)
@@ -380,19 +381,17 @@ namespace tut
       scanTest(dir2, "file?.x?z", expected7);
 
       // Scan dir2 and see if any file?.??c files are found
-      // THESE FAIL ON Mac and Windows, SO ARE COMMENTED OUT FOR NOW
-      //      bool  expected8[5] = { true, true, false, false, false };
-      //      scanTest(dir2, "file?.??c", expected8);
-      //      scanTest(dir2, "*.??c", expected8);
+      bool  expected8[5] = { true, true, false, false, false };
+      scanTest(dir2, "file?.??c", expected8);
+      scanTest(dir2, "*.??c", expected8);
 
       // Scan dir1 and see if any *.?n? files are found
       bool  expected9[5] = { false, false, false, false, true };
       scanTest(dir1, "*.?n?", expected9);
 
       // Scan dir1 and see if any *.???? files are found
-      // THIS ONE FAILS ON WINDOWS (returns three charater suffixes) SO IS COMMENTED OUT FOR NOW
-      // bool  expected10[5] = { false, false, false, false, false };
-      // scanTest(dir1, "*.????", expected10);
+      bool  expected10[5] = { false, false, false, false, false };
+      scanTest(dir1, "*.????", expected10);
 
       // Scan dir1 and see if any ?????.* files are found
       bool  expected11[5] = { true, true, true, true, true };
@@ -402,6 +401,15 @@ namespace tut
       bool  expected12[5] = { false, false, true, true, false };
       scanTest(dir1, "??l??.xyz", expected12);
 
+      bool expected13[5] = { true, false, true, false, false };
+      scanTest(dir1, "file1.{abc,xyz}", expected13);
+
+      bool expected14[5] = { true, true, false, false, false };
+      scanTest(dir1, "file[0-9].abc", expected14);
+
+      bool expected15[5] = { true, true, false, false, false };
+      scanTest(dir1, "file[!a-z].abc", expected15);
+
       // clean up all test files and directories
       for (int i=0; i<5; i++)
       {
diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l
index 8fe9f5ed29c1f9752addde37f2b8f3fd5c2c4d42..188c9e1950a0bbfffd2c3d2792875a376045150f 100644
--- a/indra/lscript/lscript_compile/indra.l
+++ b/indra/lscript/lscript_compile/indra.l
@@ -8,8 +8,11 @@ FS			(f|F)
 %n 4000
 %p 5000
 
+%top {
+	#include "linden_common.h"
+}
+
 %{
-#include "linden_common.h"
 // Deal with the fact that lex/yacc generates unreachable code
 #ifdef LL_WINDOWS
 #pragma warning (disable : 4018) // warning C4018: signed/unsigned mismatch
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b5cb06706142bb08818fbf0a338ca3ac380db383..8e006001b45796b3f6da0efec8de2eb4222994a8 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -530,6 +530,7 @@ set(viewer_SOURCE_FILES
     llviewerregion.cpp
     llviewershadermgr.cpp
     llviewerstats.cpp
+    llviewerstatsrecorder.cpp
     llviewertexteditor.cpp
     llviewertexture.cpp
     llviewertextureanim.cpp
@@ -1063,6 +1064,7 @@ set(viewer_HEADER_FILES
     llviewerregion.h
     llviewershadermgr.h
     llviewerstats.h
+    llviewerstatsrecorder.h
     llviewertexteditor.h
     llviewertexture.h
     llviewertextureanim.h
@@ -1545,7 +1547,7 @@ if (WINDOWS)
       ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qtwcodecsd4.dll
       SLPlugin
       media_plugin_quicktime
-      media_plugin_webkit
+      #media_plugin_webkit
       winmm_shim
       windows-crash-logger
       windows-updater
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 77552663abd8d72458b8d9c86e6b7c0c8c00883c..7d908df5ceed5469064c52543e304114be028dc7 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -64,6 +64,7 @@
 #include "lltool.h"
 #include "lltoolmgr.h"
 #include "lltrans.h"
+#include "llurlentry.h"
 #include "llviewercontrol.h"
 #include "llviewerdisplay.h"
 #include "llviewerjoystick.h"
@@ -649,6 +650,10 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 	}
 	mRegionp = regionp;
 
+	// Pass the region host to LLUrlEntryParcel to resolve parcel name
+	// with a server request.
+	LLUrlEntryParcel::setRegionHost(getRegionHost());
+
 	// Must shift hole-covering water object locations because local
 	// coordinate frame changed.
 	LLWorld::getInstance()->updateWaterObjects();
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 80734b0d41ae5231d670a03cf50c2bb5ef8f5868..f40fed5ad3450010bbfbc964f2b0b0332592cb84 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1300,8 +1300,16 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
 		return false;
 	}
 
-	// Check whether the outfit contains the full set of body parts (shape+skin+hair+eyes).
-	return getCanMakeFolderIntoOutfit(outfit_cat_id);
+	// Check whether the outfit contains any wearables we aren't wearing already (STORM-702).
+	LLInventoryModel::cat_array_t cats;
+	LLInventoryModel::item_array_t items;
+	LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true);
+	gInventory.collectDescendentsIf(outfit_cat_id,
+		cats,
+		items,
+		LLInventoryModel::EXCLUDE_TRASH,
+		is_worn);
+	return items.size() > 0;
 }
 
 void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 3a98c23e05d70a2a4b43a32ebf6b05a666577a06..fab6343864a6394db71fd24a8336bf072a80af40 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -44,6 +44,7 @@
 #include "llagentwearables.h"
 #include "llwindow.h"
 #include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
 #include "llmd5.h"
 #include "llpumpio.h"
 #include "llmimetypes.h"
@@ -89,10 +90,12 @@
 
 // Linden library includes
 #include "llavatarnamecache.h"
+#include "lldiriterator.h"
 #include "llimagej2c.h"
 #include "llmemory.h"
 #include "llprimitive.h"
 #include "llurlaction.h"
+#include "llurlentry.h"
 #include "llvfile.h"
 #include "llvfsthread.h"
 #include "llvolumemgr.h"
@@ -666,6 +669,10 @@ bool LLAppViewer::init()
 
     mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
 
+#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::initClass();
+#endif
+
     // *NOTE:Mani - LLCurl::initClass is not thread safe. 
     // Called before threads are created.
     LLCurl::initClass();
@@ -989,6 +996,8 @@ bool LLAppViewer::init()
 
 	LLAgentLanguage::init();
 
+
+
 	return true;
 }
 
@@ -1709,6 +1718,10 @@ bool LLAppViewer::cleanup()
 	}
 	LLMetricPerformanceTesterBasic::cleanClass() ;
 
+#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::cleanupClass();
+#endif
+
 	llinfos << "Cleaning up Media and Textures" << llendflush;
 
 	//Note:
@@ -3290,7 +3303,9 @@ void LLAppViewer::migrateCacheDirectory()
 			S32 file_count = 0;
 			std::string file_name;
 			std::string mask = delimiter + "*.*";
-			while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name))
+
+			LLDirIterator iter(old_cache_dir, mask);
+			while (iter.next(file_name))
 			{
 				if (file_name == "." || file_name == "..") continue;
 				std::string source_path = old_cache_dir + delimiter + file_name;
@@ -3509,7 +3524,8 @@ bool LLAppViewer::initCache()
 		dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
 
 		std::string found_file;
-		if (gDirUtilp->getNextFileInDir(dir, mask, found_file))
+		LLDirIterator iter(dir, mask);
+		if (iter.next(found_file))
 		{
 			old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file;
 
@@ -4567,6 +4583,10 @@ void LLAppViewer::disconnectViewer()
 
 	cleanup_xfer_manager();
 	gDisconnected = TRUE;
+
+	// Pass the connection state to LLUrlEntryParcel not to attempt
+	// parcel info requests while disconnected.
+	LLUrlEntryParcel::setDisconnected(gDisconnected);
 }
 
 void LLAppViewer::forceErrorLLError()
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 898cc1c0ba8686bc615b685e2d17353c5d51dbb9..fc7a27e5e04ec302e8d0ff161e2de215c888717f 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -30,6 +30,7 @@
 
 #include "llcommandlineparser.h"
 
+#include "lldiriterator.h"
 #include "llmemtype.h"
 #include "llurldispatcher.h"		// SLURL from other app instance
 #include "llviewernetwork.h"
@@ -504,7 +505,9 @@ std::string LLAppViewerLinux::generateSerialNumber()
 
 	// trawl /dev/disk/by-uuid looking for a good-looking UUID to grab
 	std::string this_name;
-	while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name))
+
+	LLDirIterator iter(uuiddir, "*");
+	while (iter.next(this_name))
 	{
 		if (this_name.length() > best.length() ||
 		    (this_name.length() == best.length() &&
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 11b3379814a52d3de44e343675abd7196417e5e9..182d3d23f1a868355b19dfb6be4fe03959a2ade6 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -35,6 +35,7 @@
 #include "llfloateruipreview.h"			// Own header
 
 // Internal utility
+#include "lldiriterator.h"
 #include "lleventtimer.h"
 #include "llexternaleditor.h"
 #include "llrender.h"
@@ -481,9 +482,11 @@ BOOL LLFloaterUIPreview::postBuild()
 	std::string language_directory;
 	std::string xui_dir = get_xui_dir();	// directory containing localizations -- don't forget trailing delim
 	mLanguageSelection->removeall();																				// clear out anything temporarily in list from XML
+
+	LLDirIterator iter(xui_dir, "*");
 	while(found)																									// for every directory
 	{
-		if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory)))							// get next directory
+		if((found = iter.next(language_directory)))							// get next directory
 		{
 			std::string full_path = xui_dir + language_directory;
 			if(LLFile::isfile(full_path.c_str()))																	// if it's not a directory, skip it
@@ -635,42 +638,51 @@ void LLFloaterUIPreview::refreshList()
 	mFileList->clearRows();		// empty list
 	std::string name;
 	BOOL found = TRUE;
+
+	LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml");
 	while(found)				// for every floater file that matches the pattern
 	{
-		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name)))	// get next file matching pattern
+		if((found = floater_iter.next(name)))	// get next file matching pattern
 		{
 			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)
 		}
 	}
 	found = TRUE;
+
+	LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml");
 	while(found)				// for every inspector file that matches the pattern
 	{
-		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name)))	// get next file matching pattern
+		if((found = inspect_iter.next(name)))	// get next file matching pattern
 		{
 			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)
 		}
 	}
 	found = TRUE;
+
+	LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml");
 	while(found)				// for every menu file that matches the pattern
 	{
-		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name)))	// get next file matching pattern
+		if((found = menu_iter.next(name)))	// get next file matching pattern
 		{
 			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)
 		}
 	}
 	found = TRUE;
+
+	LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml");
 	while(found)				// for every panel file that matches the pattern
 	{
-		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name)))	// get next file matching pattern
+		if((found = panel_iter.next(name)))	// get next file matching pattern
 		{
 			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)
 		}
 	}
-
 	found = TRUE;
+
+	LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml");
 	while(found)				// for every sidepanel file that matches the pattern
 	{
-		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name)))	// get next file matching pattern
+		if((found = sidepanel_iter.next(name)))	// get next file matching pattern
 		{
 			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)
 		}
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 7546c070ea6070559d2a96611d897bc01b419a9b..ce936a9924cac208cd6da38db143bbc3e6e94dfc 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -52,6 +52,7 @@
 #include <boost/regex.hpp>
 
 #if LL_MSVC
+#pragma warning(push)   
 // disable boost::lexical_cast warning
 #pragma warning (disable:4702)
 #endif
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index ef2086911401ccdcda96cdaf0d3196fdccdd1694..61d0a150b719603072987d96288f4fed97d4b559 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -686,6 +686,12 @@ bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* it
 		return false;
 	}
 
+	// Skip broken links.
+	if (vitem->getIsBrokenLink())
+	{
+		return false;
+	}
+
 	return (bool) get_is_item_worn(item->getUUID()) == mIsWorn;
 }
 
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 1527f8f4c9484ca1a36fb9aaad701922b40d4061..55164f609494e7e1214fb29cc1b50b2f6faa196c 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -547,6 +547,10 @@ void LLLocationInputCtrl::onFocusLost()
 {
 	LLUICtrl::onFocusLost();
 	refreshLocation();
+
+	// Setting cursor to 0  to show the left edge of the text. See STORM-370.
+	mTextEntry->setCursor(0);
+
 	if(mTextEntry->hasSelection()){
 		mTextEntry->deselect();
 	}
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 9adf374c71642fc0f3525b36453d93572c7af1b2..efc4e2383881d2fb5aa57828a7707b7d6d3b4d35 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -32,6 +32,7 @@
 #include "lltrans.h"
 #include "llviewercontrol.h"
 
+#include "lldiriterator.h"
 #include "llinstantmessage.h"
 #include "llsingleton.h" // for LLSingleton
 
@@ -41,6 +42,7 @@
 #include <boost/regex/v4/match_results.hpp>
 
 #if LL_MSVC
+#pragma warning(push)  
 // disable warning about boost::lexical_cast unreachable code
 // when it fails to parse the string
 #pragma warning (disable:4702)
@@ -601,7 +603,8 @@ std::string LLLogChat::oldLogFileName(std::string filename)
 	//LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
 	std::vector<std::string> allfiles;
 
-    while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult))
+	LLDirIterator iter(directory, pattern);
+	while (iter.next(scanResult))
     {
 		//LL_INFOS("") << "Found   :" << scanResult << LL_ENDL;
         allfiles.push_back(scanResult);
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index c10c21683b4faafc5c1404c989326b8c8f48b724..9346e48d1ecbc53f416125fd82ee95612eacca42 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -1323,19 +1323,19 @@ void LLPanelOutfitEdit::getCurrentItemUUID(LLUUID& selected_id)
 
 void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list)
 {
+	void (uuid_vec_t::* tmp)(LLUUID const &) = &uuid_vec_t::push_back;
 	if (mInventoryItemsPanel->getVisible())
 	{
 		std::set<LLUUID> item_set = mInventoryItemsPanel->getRootFolder()->getSelectionList();
 
-		std::for_each(item_set.begin(), item_set.end(), boost::bind( &uuid_vec_t::push_back, &uuid_list, _1));
+		std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, _1));
 	}
 	else if (mWearablesListViewPanel->getVisible())
 	{
 		std::vector<LLSD> item_set;
 		mWearableItemsList->getSelectedValues(item_set);
 
-		std::for_each(item_set.begin(), item_set.end(), boost::bind( &uuid_vec_t::push_back, &uuid_list, boost::bind(&LLSD::asUUID, _1 )));
-
+		std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, boost::bind(&LLSD::asUUID, _1 )));
 	}
 
 //	return selected_id;
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index e5ef51bdd18c6b54c1ac0e801fa3567f6f15ec87..3862dac340d0db44d3ed0411a56c7cbee3a4ac01 100644
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -33,6 +33,7 @@
 #include "llpanel.h"
 #include "llhttpclient.h"
 #include "llsdserialize.h"
+#include "llurlentry.h"
 #include "llviewerregion.h"
 #include "llview.h"
 
@@ -168,6 +169,18 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v
 	{
 		observers.erase(*i);
 	}
+
+	LLUrlEntryParcel::LLParcelData url_data;
+	url_data.parcel_id = parcel_data.parcel_id;
+	url_data.name = parcel_data.name;
+	url_data.sim_name = parcel_data.sim_name;
+	url_data.global_x = parcel_data.global_x;
+	url_data.global_y = parcel_data.global_y;
+	url_data.global_z = parcel_data.global_z;
+
+	// Pass the parcel data to LLUrlEntryParcel to render
+	// human readable parcel name.
+	LLUrlEntryParcel::processParcelInfo(url_data);
 }
 
 void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id)
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index aef665a35cd4db8079689d71296109b8f8dc4c40..19d1bdee862b5bafd624cae04bb367724fd0eb2d 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -498,8 +498,8 @@ class LLSideTrayButton : public LLButton
 
 LLSideTray::Params::Params()
 :	collapsed("collapsed",false),
-	tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("sidebar_tab_left.tga")),
-	tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("button_enabled_selected_32x128.tga")),
+	tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Off.png")),
+	tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Selected.png")),
 	default_button_width("tab_btn_width",32),
 	default_button_height("tab_btn_height",32),
 	default_button_margin("tab_btn_margin",0)
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 960e72ee421e9b3ac65de574fc0489ca81273c7a..8adb8c30e05410e2f6e393ca38bb9363bc89710c 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2578,6 +2578,49 @@ void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
 	gGL.end();
 }
 
+void renderUpdateType(LLDrawable* drawablep)
+{
+	LLViewerObject* vobj = drawablep->getVObj();
+	if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType())
+	{
+		return;
+	}
+	LLGLEnable blend(GL_BLEND);
+	switch (vobj->getLastUpdateType())
+	{
+	case OUT_FULL:
+		glColor4f(0,1,0,0.5f);
+		break;
+	case OUT_TERSE_IMPROVED:
+		glColor4f(0,1,1,0.5f);
+		break;
+	case OUT_FULL_COMPRESSED:
+		if (vobj->getLastUpdateCached())
+		{
+			glColor4f(1,0,0,0.5f);
+		}
+		else
+		{
+			glColor4f(1,1,0,0.5f);
+		}
+		break;
+	case OUT_FULL_CACHED:
+		glColor4f(0,0,1,0.5f);
+		break;
+	default:
+		llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl;
+		break;
+	};
+	S32 num_faces = drawablep->getNumFaces();
+	if (num_faces)
+	{
+		for (S32 i = 0; i < num_faces; ++i)
+		{
+			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+		}
+	}
+}
+
 
 void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
 {
@@ -3018,6 +3061,10 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			{
 				renderRaycast(drawable);
 			}
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
+			{
+				renderUpdateType(drawable);
+			}
 
 			LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
 			
@@ -3180,6 +3227,7 @@ void LLSpatialPartition::renderDebug()
 									  LLPipeline::RENDER_DEBUG_OCCLUSION |
 									  LLPipeline::RENDER_DEBUG_LIGHTS |
 									  LLPipeline::RENDER_DEBUG_BATCH_SIZE |
+									  LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
 									  LLPipeline::RENDER_DEBUG_BBOXES |
 									  LLPipeline::RENDER_DEBUG_POINTS |
 									  LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 611f9de2e6db8dcdb24f2edf9fe9789c0bcd6684..5617eea4c339a3763c1ad151c3ca47552307e488 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -139,6 +139,7 @@
 #include "lltrans.h"
 #include "llui.h"
 #include "llurldispatcher.h"
+#include "llurlentry.h"
 #include "llslurl.h"
 #include "llurlhistory.h"
 #include "llurlwhitelist.h"
@@ -2882,9 +2883,17 @@ bool process_login_success_response()
 	if(!text.empty()) gAgentID.set(text);
 	gDebugInfo["AgentID"] = text;
 	
+	// Agent id needed for parcel info request in LLUrlEntryParcel
+	// to resolve parcel name.
+	LLUrlEntryParcel::setAgentID(gAgentID);
+
 	text = response["session_id"].asString();
 	if(!text.empty()) gAgentSessionID.set(text);
 	gDebugInfo["SessionID"] = text;
+
+	// Session id needed for parcel info request in LLUrlEntryParcel
+	// to resolve parcel name.
+	LLUrlEntryParcel::setSessionID(gAgentSessionID);
 	
 	text = response["secure_session_id"].asString();
 	if(!text.empty()) gAgent.mSecureSessionID.set(text);
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index d3b6dcd86f2f937121d61890f9c997ae0869fd08..8a0d0a6623b8138b67227c8225781656979a17be 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -54,6 +54,7 @@
 #include "llfilepicker.h"
 #include "llnotifications.h"
 
+#include "lldiriterator.h"
 #include "llevent.h"		// LLSimpleListener
 #include "llnotificationsutil.h"
 #include "lluuid.h"
@@ -1115,7 +1116,8 @@ void LLViewerMedia::clearAllCookies()
 	}
 	
 	// the hard part: iterate over all user directories and delete the cookie file from each one
-	while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename))
+	LLDirIterator dir_iter(base_dir, "*_*");
+	while (dir_iter.next(filename))
 	{
 		target = base_dir;
 		target += filename;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 60b118284b18cc010bc6ad138d0e8e1885fd8494..7cc04e0338a0e81e8be7c2c3831531e4b471dfed 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -906,6 +906,10 @@ U32 info_display_from_string(std::string info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_BATCH_SIZE;
 	}
+	else if ("update type" == info_display)
+	{
+		return LLPipeline::RENDER_DEBUG_UPDATE_TYPE;
+	}
 	else if ("texture anim" == info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 18d6e4c8c87c3c79e9c1ea1994965aabff37770d..48794c4c9d24b2a917017465aa439e83608f8255 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -234,7 +234,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mState(0),
 	mMedia(NULL),
 	mClickAction(0),
-	mAttachmentItemID(LLUUID::null)
+	mAttachmentItemID(LLUUID::null),
+	mLastUpdateType(OUT_UNKNOWN),
+	mLastUpdateCached(FALSE)
 {
 	if (!is_global)
 	{
@@ -5403,6 +5405,26 @@ void LLViewerObject::setAttachmentItemID(const LLUUID &id)
 	mAttachmentItemID = id;
 }
 
+EObjectUpdateType LLViewerObject::getLastUpdateType() const
+{
+	return mLastUpdateType;
+}
+
+void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type)
+{
+	mLastUpdateType = last_update_type;
+}
+
+BOOL LLViewerObject::getLastUpdateCached() const
+{
+	return mLastUpdateCached;
+}
+
+void LLViewerObject::setLastUpdateCached(BOOL last_update_cached)
+{
+	mLastUpdateCached = last_update_cached;
+}
+
 const LLUUID &LLViewerObject::extractAttachmentItemID()
 {
 	LLUUID item_id = LLUUID::null;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 5c1a34d5555c86c74dbed636a71b8cb02378dd6a..614a5e59fa20d586b083d23560626f1e9fa66c58 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -77,6 +77,7 @@ typedef enum e_object_update_type
 	OUT_TERSE_IMPROVED,
 	OUT_FULL_COMPRESSED,
 	OUT_FULL_CACHED,
+	OUT_UNKNOWN,
 } EObjectUpdateType;
 
 
@@ -693,8 +694,15 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	const LLUUID &getAttachmentItemID() const;
 	void setAttachmentItemID(const LLUUID &id);
 	const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object
+	EObjectUpdateType getLastUpdateType() const;
+	void setLastUpdateType(EObjectUpdateType last_update_type);
+	BOOL getLastUpdateCached() const;
+	void setLastUpdateCached(BOOL last_update_cached);
+
 private:
 	LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory.
+	EObjectUpdateType	mLastUpdateType;
+	BOOL	mLastUpdateCached;
 };
 
 ///////////////////
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index f5a32438cfef2effc43e3372208c528b924b9e0a..5849ab4307c016364537d3bac79839daf0f7f768 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -56,6 +56,7 @@
 #include "llresmgr.h"
 #include "llviewerregion.h"
 #include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
 #include "llvoavatarself.h"
 #include "lltoolmgr.h"
 #include "lltoolpie.h"
@@ -302,8 +303,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 	// have to transform to absolute coordinates.
 	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
 
+	// I don't think this case is ever hit.  TODO* Test this.
 	if (!cached && !compressed && update_type != OUT_FULL)
 	{
+		//llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl;
 		gTerseObjectUpdates += num_objects;
 		S32 size;
 		if (mesgsys->getReceiveCompressedSize())
@@ -314,7 +317,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 		{
 			size = mesgsys->getReceiveSize();
 		}
-		// llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl;
+		//llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl;
 	}
 	else
 	{
@@ -345,9 +348,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 	U8 compressed_dpbuffer[2048];
 	LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048);
 	LLDataPacker *cached_dpp = NULL;
-	
+
+#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp);
+#endif
+
 	for (i = 0; i < num_objects; i++)
 	{
+		// timer is unused?
 		LLTimer update_timer;
 		BOOL justCreated = FALSE;
 
@@ -359,9 +367,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);
 		
 			// Lookup data packer and add this id to cache miss lists if necessary.
-			cached_dpp = regionp->getDP(id, crc);
+			U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
+			cached_dpp = regionp->getDP(id, crc, cache_miss_type);
 			if (cached_dpp)
 			{
+				// Cache Hit.
 				cached_dpp->reset();
 				cached_dpp->unpackUUID(fullid, "ID");
 				cached_dpp->unpackU32(local_id, "LocalID");
@@ -369,6 +379,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			}
 			else
 			{
+				// Cache Miss.
+				#if LL_RECORD_VIEWER_STATS
+				LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type);
+				#endif
+
 				continue; // no data packer, skip this object
 			}
 		}
@@ -380,13 +395,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			compressed_dp.reset();
 
 			U32 flags = 0;
-			if (update_type != OUT_TERSE_IMPROVED)
+			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
 			{
 				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
 			}
 			
+			// I don't think we ever use this flag from the server.  DK 2010/12/09
 			if (flags & FLAGS_ZLIB_COMPRESSED)
 			{
+				//llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl;
 				compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data);
 				mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i);
 				uncompressed_length = 2048;
@@ -402,7 +419,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			}
 
 
-			if (update_type != OUT_TERSE_IMPROVED)
+			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
 			{
 				compressed_dp.unpackUUID(fullid, "ID");
 				compressed_dp.unpackU32(local_id, "LocalID");
@@ -422,7 +439,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				}
 			}
 		}
-		else if (update_type != OUT_FULL)
+		else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only?
 		{
 			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
 			getUUIDFromLocal(fullid,
@@ -435,7 +452,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				mNumUnknownUpdates++;
 			}
 		}
-		else
+		else // OUT_FULL only?
 		{
 			mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i);
 			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
@@ -467,12 +484,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 							gMessageSystem->getSenderPort());
 			
 			if (objectp->mLocalID != local_id)
-			{    // Update local ID in object with the one sent from the region
+			{	// Update local ID in object with the one sent from the region
 				objectp->mLocalID = local_id;
 			}
 			
 			if (objectp->getRegion() != regionp)
-			{    // Object changed region, so update it
+			{	// Object changed region, so update it
 				objectp->updateRegion(regionp); // for LLVOAvatar
 			}
 		}
@@ -483,18 +500,24 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			{
 				if (update_type == OUT_TERSE_IMPROVED)
 				{
-					// llinfos << "terse update for an unknown object:" << fullid << llendl;
+					// llinfos << "terse update for an unknown object (compressed):" << fullid << llendl;
+					#if LL_RECORD_VIEWER_STATS
+					LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+					#endif
 					continue;
 				}
 			}
-			else if (cached)
+			else if (cached) // Cache hit only?
 			{
 			}
 			else
 			{
 				if (update_type != OUT_FULL)
 				{
-					// llinfos << "terse update for an unknown object:" << fullid << llendl;
+					//llinfos << "terse update for an unknown object:" << fullid << llendl;
+					#if LL_RECORD_VIEWER_STATS
+					LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+					#endif
 					continue;
 				}
 
@@ -504,7 +527,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			if (mDeadObjects.find(fullid) != mDeadObjects.end())
 			{
 				mNumDeadObjectUpdates++;
-				// llinfos << "update for a dead object:" << fullid << llendl;
+				//llinfos << "update for a dead object:" << fullid << llendl;
+				#if LL_RECORD_VIEWER_STATS
+				LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+				#endif
 				continue;
 			}
 #endif
@@ -512,6 +538,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());
 			if (!objectp)
 			{
+				llinfos << "createObject failure for object: " << fullid << llendl;
+				#if LL_RECORD_VIEWER_STATS
+				LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+				#endif
 				continue;
 			}
 			justCreated = TRUE;
@@ -524,19 +554,26 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl;
 		}
 
+		bool bCached = false;
 		if (compressed)
 		{
-			if (update_type != OUT_TERSE_IMPROVED)
+			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
 			{
 				objectp->mLocalID = local_id;
 			}
 			processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated);
-			if (update_type != OUT_TERSE_IMPROVED)
+			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
 			{
+				bCached = true;
+				#if LL_RECORD_VIEWER_STATS
+				LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+				LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp);
+				#else
 				objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+				#endif
 			}
 		}
-		else if (cached)
+		else if (cached) // Cache hit only?
 		{
 			objectp->mLocalID = local_id;
 			processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated);
@@ -549,8 +586,17 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			}
 			processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated);
 		}
+		#if LL_RECORD_VIEWER_STATS
+		LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp);
+		#endif
+		objectp->setLastUpdateType(update_type);
+		objectp->setLastUpdateCached(bCached);
 	}
 
+#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
+#endif
+
 	LLVOAvatar::cullAvatarsByPixelArea();
 }
 
@@ -681,12 +727,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 
 	// update global timer
 	F32 last_time = gFrameTimeSeconds;
-	U64 time = totalTime();                 // this will become the new gFrameTime when the update is done
+	U64 time = totalTime();				 // this will become the new gFrameTime when the update is done
 	// Time _can_ go backwards, for example if the user changes the system clock.
 	// It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here.
 //	llassert(time > gFrameTime);
 	F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC;
-	gFrameTime    = time;
+	gFrameTime	= time;
 	F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC;
 	gFrameTimeSeconds = (F32)time_since_start;
 
@@ -788,7 +834,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 		{
 			std::string id_str;
 			objectp->mID.toString(id_str);
-			std::string tmpstr = std::string("Par:    ") + id_str;
+			std::string tmpstr = std::string("Par:	") + id_str;
 			addDebugBeacon(objectp->getPositionAgent(),
 							tmpstr,
 							LLColor4(1.f,0.f,0.f,1.f),
@@ -808,12 +854,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 			std::string tmpstr;
 			if (objectp->getParent())
 			{
-				tmpstr = std::string("ChP:    ") + id_str;
+				tmpstr = std::string("ChP:	") + id_str;
 				text_color = LLColor4(0.f, 1.f, 0.f, 1.f);
 			}
 			else
 			{
-				tmpstr = std::string("ChNoP:    ") + id_str;
+				tmpstr = std::string("ChNoP:	") + id_str;
 				text_color = LLColor4(1.f, 0.f, 0.f, 1.f);
 			}
 			id = sIndexAndLocalIDToUUID[oi.mParentInfo];
@@ -1519,8 +1565,8 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
 			llinfos << "Agent: " << objectp->getPositionAgent() << llendl;
 			addDebugBeacon(objectp->getPositionAgent(),"");
 #endif
-            gPipeline.markMoved(objectp->mDrawable);                
-            objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE);
+			gPipeline.markMoved(objectp->mDrawable);				
+			objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE);
 
 			// Flag the object as no longer orphaned
 			childp->mOrphaned = FALSE;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 2a67d12b648d6ae985003f437183ae75b4632ddb..3b2cfe656f0475cc3ed5e83f7b48250bf90b7f77 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -59,6 +59,7 @@
 #include "llurldispatcher.h"
 #include "llviewerobjectlist.h"
 #include "llviewerparceloverlay.h"
+#include "llviewerstatsrecorder.h"
 #include "llvlmanager.h"
 #include "llvlcomposition.h"
 #include "llvocache.h"
@@ -1032,7 +1033,7 @@ void LLViewerRegion::getInfo(LLSD& info)
 	info["Region"]["Handle"]["y"] = (LLSD::Integer)y;
 }
 
-void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
+LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
 {
 	U32 local_id = objectp->getLocalID();
 	U32 crc = objectp->getCRC();
@@ -1046,35 +1047,36 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary
 		{
 			// Record a hit
 			entry->recordDupe();
+			return CACHE_UPDATE_DUPE;
 		}
-		else
-		{
-			// Update the cache entry
-			mCacheMap.erase(local_id);
-			delete entry;
-			entry = new LLVOCacheEntry(local_id, crc, dp);
-			mCacheMap[local_id] = entry;
-		}
-	}
-	else
-	{
-		// we haven't seen this object before
 
-		// Create new entry and add to map
-		if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
-		{
-			mCacheMap.erase(mCacheMap.begin());
-		}
+		// Update the cache entry
+		mCacheMap.erase(local_id);
+		delete entry;
 		entry = new LLVOCacheEntry(local_id, crc, dp);
-
 		mCacheMap[local_id] = entry;
+		return CACHE_UPDATE_CHANGED;
 	}
-	return ;
+
+	// we haven't seen this object before
+
+	// Create new entry and add to map
+	eCacheUpdateResult result = CACHE_UPDATE_ADDED;
+	if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
+	{
+		mCacheMap.erase(mCacheMap.begin());
+		result = CACHE_UPDATE_REPLACED;
+		
+	}
+	entry = new LLVOCacheEntry(local_id, crc, dp);
+
+	mCacheMap[local_id] = entry;
+	return result;
 }
 
 // Get data packer for this object, if we have cached data
 // AND the CRC matches. JC
-LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
+LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
 {
 	llassert(mCacheLoaded);
 
@@ -1087,17 +1089,20 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
 		{
 			// Record a hit
 			entry->recordHit();
+			cache_miss_type = CACHE_MISS_TYPE_NONE;
 			return entry->getDP(crc);
 		}
 		else
 		{
 			// llinfos << "CRC miss for " << local_id << llendl;
+			cache_miss_type = CACHE_MISS_TYPE_CRC;
 			mCacheMissCRC.put(local_id);
 		}
 	}
 	else
 	{
 		// llinfos << "Cache miss for " << local_id << llendl;
+		cache_miss_type = CACHE_MISS_TYPE_FULL;
 		mCacheMissFull.put(local_id);
 	}
 	return NULL;
@@ -1119,9 +1124,6 @@ void LLViewerRegion::requestCacheMisses()
 	S32 blocks = 0;
 	S32 i;
 
-	const U8 CACHE_MISS_TYPE_FULL = 0;
-	const U8 CACHE_MISS_TYPE_CRC  = 1;
-
 	// Send full cache miss updates.  For these, we KNOW we don't
 	// have a viewer object.
 	for (i = 0; i < full_count; i++)
@@ -1184,6 +1186,11 @@ void LLViewerRegion::requestCacheMisses()
 
 	mCacheDirty = TRUE ;
 	// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
+	#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this);
+	LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count);
+	LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
+	#endif
 }
 
 void LLViewerRegion::dumpCache()
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 3d3f1d62a6678ea280c0d70404ece557a3ef972e..7c6559203e5fa7606685f67a5cc8b328e1ffdf4a 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -51,7 +51,7 @@
 // Surface id's
 #define LAND  1
 #define WATER 2
-const U32	MAX_OBJECT_CACHE_ENTRIES = 10000;
+const U32	MAX_OBJECT_CACHE_ENTRIES = 50000;
 
 
 class LLEventPoll;
@@ -275,9 +275,24 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 
 	void getInfo(LLSD& info);
 
+	typedef enum
+	{
+		CACHE_MISS_TYPE_FULL = 0,
+		CACHE_MISS_TYPE_CRC,
+		CACHE_MISS_TYPE_NONE
+	} eCacheMissType;
+
+	typedef enum
+	{
+		CACHE_UPDATE_DUPE = 0,
+		CACHE_UPDATE_CHANGED,
+		CACHE_UPDATE_ADDED,
+		CACHE_UPDATE_REPLACED
+	} eCacheUpdateResult;
+
 	// handle a full update message
-	void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
-	LLDataPacker *getDP(U32 local_id, U32 crc);
+	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
+	LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);
 	void requestCacheMisses();
 	void addCacheMissFull(const U32 local_id);
 
diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9d21b4848e4c6d8069df681eaf66cee337a96aa
--- /dev/null
+++ b/indra/newview/llviewerstatsrecorder.cpp
@@ -0,0 +1,258 @@
+/**
+ * @file llviewerstatsrecorder.cpp
+ * @brief record info about viewer events to a metrics log file
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llviewerstatsrecorder.h"
+
+#if LL_RECORD_VIEWER_STATS
+
+#include "llfile.h"
+#include "llviewerregion.h"
+#include "llviewerobject.h"
+
+
+// To do - something using region name or global position
+#if LL_WINDOWS
+	static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv");
+#else
+	static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv");
+#endif
+
+LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL;
+LLViewerStatsRecorder::LLViewerStatsRecorder() :
+	mObjectCacheFile(NULL),
+	mTimer(),
+	mRegionp(NULL),
+	mStartTime(0.f),
+	mProcessingTime(0.f)
+{
+	if (NULL != sInstance)
+	{
+		llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl;
+	}
+	sInstance = this;
+	clearStats();
+}
+
+LLViewerStatsRecorder::~LLViewerStatsRecorder()
+{
+	if (mObjectCacheFile != NULL)
+	{
+		LLFile::close(mObjectCacheFile);
+		mObjectCacheFile = NULL;
+	}
+}
+
+// static
+void LLViewerStatsRecorder::initClass()
+{
+	sInstance = new LLViewerStatsRecorder();
+}
+
+// static
+void LLViewerStatsRecorder::cleanupClass()
+{
+	delete sInstance;
+	sInstance = NULL;
+}
+
+
+void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp)
+{
+	if (mObjectCacheFile == NULL)
+	{
+		mStartTime = LLTimer::getTotalTime();
+		mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb");
+		if (mObjectCacheFile)
+		{	// Write column headers
+			std::ostringstream data_msg;
+			data_msg << "EventTime, "
+				<< "ProcessingTime, "
+				<< "CacheHits, "
+				<< "CacheFullMisses, "
+				<< "CacheCrcMisses, "
+				<< "FullUpdates, "
+				<< "TerseUpdates, "
+				<< "CacheMissRequests, "
+				<< "CacheMissResponses, "
+				<< "CacheUpdateDupes, "
+				<< "CacheUpdateChanges, "
+				<< "CacheUpdateAdds, "
+				<< "CacheUpdateReplacements, "
+				<< "UpdateFailures"
+				<< "\n";
+
+			fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
+		}
+	}
+}
+
+void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp)
+{
+	initStatsRecorder(regionp);
+	mRegionp = regionp;
+	mProcessingTime = LLTimer::getTotalTime();
+	clearStats();
+}
+
+void LLViewerStatsRecorder::clearStats()
+{
+	mObjectCacheHitCount = 0;
+	mObjectCacheMissFullCount = 0;
+	mObjectCacheMissCrcCount = 0;
+	mObjectFullUpdates = 0;
+	mObjectTerseUpdates = 0;
+	mObjectCacheMissRequests = 0;
+	mObjectCacheMissResponses = 0;
+	mObjectCacheUpdateDupes = 0;
+	mObjectCacheUpdateChanges = 0;
+	mObjectCacheUpdateAdds = 0;
+	mObjectCacheUpdateReplacements = 0;
+	mObjectUpdateFailures = 0;
+}
+
+
+void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type)
+{
+	mObjectUpdateFailures++;
+}
+
+void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type)
+{
+	if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type)
+	{
+		mObjectCacheMissFullCount++;
+	}
+	else
+	{
+		mObjectCacheMissCrcCount++;
+	}
+}
+
+void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp)
+{
+	switch (update_type)
+	{
+	case OUT_FULL:
+		mObjectFullUpdates++;
+		break;
+	case OUT_TERSE_IMPROVED:
+		mObjectTerseUpdates++;
+		break;
+	case OUT_FULL_COMPRESSED:
+		mObjectCacheMissResponses++;
+		break;
+	case OUT_FULL_CACHED:
+		mObjectCacheHitCount++;
+		break;
+	default:
+		llwarns << "Unknown update_type" << llendl;
+		break;
+	};
+}
+
+void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp)
+{
+	switch (update_result)
+	{
+		case LLViewerRegion::CACHE_UPDATE_DUPE:
+			mObjectCacheUpdateDupes++;
+			break;
+		case LLViewerRegion::CACHE_UPDATE_CHANGED:
+			mObjectCacheUpdateChanges++;
+			break;
+		case LLViewerRegion::CACHE_UPDATE_ADDED:
+			mObjectCacheUpdateAdds++;
+			break;
+		case LLViewerRegion::CACHE_UPDATE_REPLACED:
+			mObjectCacheUpdateReplacements++;
+			break;
+		default:
+			llwarns << "Unknown update_result type" << llendl;
+			break;
+	};
+}
+
+void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count)
+{
+	mObjectCacheMissRequests += count;
+}
+
+void LLViewerStatsRecorder::endObjectUpdateEvents()
+{
+	llinfos << "ILX: " 
+		<< mObjectCacheHitCount << " hits, " 
+		<< mObjectCacheMissFullCount << " full misses, "
+		<< mObjectCacheMissCrcCount << " crc misses, "
+		<< mObjectFullUpdates << " full updates, "
+		<< mObjectTerseUpdates << " terse updates, "
+		<< mObjectCacheMissRequests << " cache miss requests, "
+		<< mObjectCacheMissResponses << " cache miss responses, "
+		<< mObjectCacheUpdateDupes << " cache update dupes, "
+		<< mObjectCacheUpdateChanges << " cache update changes, "
+		<< mObjectCacheUpdateAdds << " cache update adds, "
+		<< mObjectCacheUpdateReplacements << " cache update replacements, "
+		<< mObjectUpdateFailures << " update failures"
+		<< llendl;
+
+	S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures;
+	if (mObjectCacheFile != NULL &&
+		total_objects > 0)
+	{
+		std::ostringstream data_msg;
+		F32 processing32 = (F32) ((LLTimer::getTotalTime() - mProcessingTime) / 1000.0);
+
+		data_msg << getTimeSinceStart()
+			<< ", " << processing32
+			<< ", " << mObjectCacheHitCount
+			<< ", " << mObjectCacheMissFullCount
+			<< ", " << mObjectCacheMissCrcCount
+			<< ", " << mObjectFullUpdates
+			<< ", " << mObjectTerseUpdates
+			<< ", " << mObjectCacheMissRequests
+			<< ", " << mObjectCacheMissResponses
+			<< ", " << mObjectCacheUpdateDupes
+			<< ", " << mObjectCacheUpdateChanges
+			<< ", " << mObjectCacheUpdateAdds
+			<< ", " << mObjectCacheUpdateReplacements
+			<< ", " << mObjectUpdateFailures
+			<< "\n";
+
+		fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
+	}
+
+	clearStats();
+}
+
+F32 LLViewerStatsRecorder::getTimeSinceStart()
+{
+	return (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0);
+}
+
+#endif
+
+
+
diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h
new file mode 100644
index 0000000000000000000000000000000000000000..612ac380f7f9c92ef13f9c79cfbb91e0f6686550
--- /dev/null
+++ b/indra/newview/llviewerstatsrecorder.h
@@ -0,0 +1,97 @@
+/**
+ * @file llviewerstatsrecorder.h
+ * @brief record info about viewer events to a metrics log file
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#ifndef LLVIEWERSTATSRECORDER_H
+#define LLVIEWERSTATSRECORDER_H
+
+
+// This is a diagnostic class used to record information from the viewer
+// for analysis.
+
+// This is normally 0.  Set to 1 to enable viewer stats recording
+#define LL_RECORD_VIEWER_STATS	0
+
+
+#if LL_RECORD_VIEWER_STATS
+#include "llframetimer.h"
+#include "llviewerobject.h"
+#include "llviewerregion.h"
+
+class LLMutex;
+class LLViewerRegion;
+class LLViewerObject;
+
+class LLViewerStatsRecorder
+{
+ public:
+	LLViewerStatsRecorder();
+	~LLViewerStatsRecorder();
+
+	static void initClass();
+	static void cleanupClass();
+	static LLViewerStatsRecorder* instance() {return sInstance; }
+
+	void initStatsRecorder(LLViewerRegion *regionp);
+
+	void beginObjectUpdateEvents(LLViewerRegion *regionp);
+	void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type);
+	void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type);
+	void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp);
+	void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp);
+	void recordRequestCacheMissesEvent(S32 count);
+	void endObjectUpdateEvents();
+
+	F32 getTimeSinceStart();
+
+private:
+	static LLViewerStatsRecorder* sInstance;
+
+	LLFILE *	mObjectCacheFile;		// File to write data into
+	LLFrameTimer	mTimer;
+	LLViewerRegion*	mRegionp;
+	F64			mStartTime;
+	F64			mProcessingTime;
+
+	S32			mObjectCacheHitCount;
+	S32			mObjectCacheMissFullCount;
+	S32			mObjectCacheMissCrcCount;
+	S32			mObjectFullUpdates;
+	S32			mObjectTerseUpdates;
+	S32			mObjectCacheMissRequests;
+	S32			mObjectCacheMissResponses;
+	S32			mObjectCacheUpdateDupes;
+	S32			mObjectCacheUpdateChanges;
+	S32			mObjectCacheUpdateAdds;
+	S32			mObjectCacheUpdateReplacements;
+	S32			mObjectUpdateFailures;
+
+
+	void	clearStats();
+};
+#endif	// LL_RECORD_VIEWER_STATS
+
+#endif // LLVIEWERSTATSRECORDER_H
+
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 145ee31260b94e43d1580fe2e6a129501a6f83a0..c26008d6406dcb71d9b313267576689b463cfea7 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -40,6 +40,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
 	return apr_file->write(src, n_bytes) == n_bytes ;
 }
 
+
 //---------------------------------------------------------------------------
 // LLVOCacheEntry
 //---------------------------------------------------------------------------
@@ -212,8 +213,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 		if(success)
 		{
 			success = check_write(apr_file, (void*)mBuffer, size);
+		}
 	}
-}
 
 	return success ;
 }
@@ -224,7 +225,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 // Format string used to construct filename for the object cache
 static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
 
-const U32 NUM_ENTRIES_TO_PURGE = 16 ;
+// Throw out 1/20 (5%) of our cache entries if we run out of room.
+const U32 ENTRIES_PURGE_FACTOR = 20;
 const char* object_cache_dirname = "objectcache";
 const char* header_filename = "object.cache";
 
@@ -259,7 +261,6 @@ void LLVOCache::destroyClass()
 LLVOCache::LLVOCache():
 	mInitialized(FALSE),
 	mReadOnly(TRUE),
-	mNumEntries(0),
 	mCacheSize(1)
 {
 	mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled");
@@ -286,8 +287,15 @@ void LLVOCache::setDirNames(ELLPath location)
 
 void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 {
-	if(mInitialized || !mEnabled)
+	if(!mEnabled)
 	{
+		llwarns << "Not initializing cache: Cache is currently disabled." << llendl;
+		return ;
+	}
+
+	if(mInitialized)
+	{
+		llwarns << "Cache already initialized." << llendl;
 		return ;
 	}
 
@@ -299,7 +307,6 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 
 	mCacheSize = size;
 
-	mMetaInfo.mVersion = cache_version;
 	readCacheHeader();
 	mInitialized = TRUE ;
 
@@ -321,12 +328,14 @@ void LLVOCache::removeCache(ELLPath location)
 {
 	if(mReadOnly)
 	{
+		llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl;
 		return ;
 	}
 
 	std::string delem = gDirUtilp->getDirDelimiter();
 	std::string mask = delem + "*";
 	std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
+	llinfos << "Removing cache at " << cache_dir << llendl;
 	gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files
 	LLFile::rmdir(cache_dir);
 
@@ -339,11 +348,13 @@ void LLVOCache::removeCache()
 	llassert_always(mInitialized) ;
 	if(mReadOnly)
 	{
+		llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl;
 		return ;
 	}
 
 	std::string delem = gDirUtilp->getDirDelimiter();
 	std::string mask = delem + "*";
+	llinfos << "Removing cache at " << mObjectCacheDirName << llendl;
 	gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); 
 
 	clearCacheInMemory() ;
@@ -352,16 +363,8 @@ void LLVOCache::removeCache()
 
 void LLVOCache::clearCacheInMemory()
 {
-	if(!mHeaderEntryQueue.empty()) 
-	{
-		for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter)
-		{
-			delete *iter ;
-		}
-		mHeaderEntryQueue.clear();
-		mHandleEntryMap.clear();
-		mNumEntries = 0 ;
-	}
+	std::for_each(mHandleEntryMap.begin(), mHandleEntryMap.end(), DeletePairedPointer());
+	mHandleEntryMap.clear();
 }
 
 void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename) 
@@ -379,6 +382,7 @@ void LLVOCache::removeFromCache(U64 handle)
 {
 	if(mReadOnly)
 	{
+		llwarns << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << llendl;
 		return ;
 	}
 
@@ -387,24 +391,28 @@ void LLVOCache::removeFromCache(U64 handle)
 	LLAPRFile::remove(filename, mLocalAPRFilePoolp);	
 }
 
-BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) 
+BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error)
 {
 	if(!check_read(apr_file, src, n_bytes))
 	{
-		delete apr_file ;
-		removeCache() ;
+		if (remove_cache_on_error)
+		{
+			removeCache() ;
+		}
 		return FALSE ;
 	}
 
 	return TRUE ;
 }
 
-BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) 
+BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error) 
 {
 	if(!check_write(apr_file, src, n_bytes))
 	{
-		delete apr_file ;
-		removeCache() ;
+		if (remove_cache_on_error)
+		{
+			removeCache() ;
+		}
 		return FALSE ;
 	}
 
@@ -415,7 +423,8 @@ void LLVOCache::readCacheHeader()
 {
 	if(!mEnabled)
 	{
-		return ;
+		llwarns << "Not reading cache header: Cache is currently disabled." << llendl;
+		return;
 	}
 
 	//clear stale info.
@@ -423,33 +432,35 @@ void LLVOCache::readCacheHeader()
 
 	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
 	{
-		LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		
+		LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);		
 		
 		//read the meta element
-		if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
+		bool remove_cache_on_error = false;
+		if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo), remove_cache_on_error))
 		{
-			return ;
+			llwarns << "Error reading meta information from cache header." << llendl;
+			delete apr_file;
+			return;
 		}
 
 		HeaderEntryInfo* entry ;
-		mNumEntries = 0 ;
-		while(mNumEntries < mCacheSize)
+		for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index)
 		{
 			entry = new HeaderEntryInfo() ;
-			if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo)))
+			if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo), remove_cache_on_error))
 			{
+				llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl;
 				delete entry ;			
-				return ;
+				break;
 			}
 			else if(!entry->mTime) //end of the cache.
 			{
 				delete entry ;
-				return ;
+				break;
 			}
 
-			entry->mIndex = mNumEntries++ ;
-			mHeaderEntryQueue.insert(entry) ;
-			mHandleEntryMap[entry->mHandle] = entry ;
+			entry->mIndex = entry_index;
+			mHandleEntryMap[entry->mHandle] = entry;
 		}
 
 		delete apr_file ;
@@ -462,40 +473,57 @@ void LLVOCache::readCacheHeader()
 
 void LLVOCache::writeCacheHeader()
 {
-	if(mReadOnly || !mEnabled)
+	if (!mEnabled)
 	{
-		return ;
-	}	
+		llwarns << "Not writing cache header: Cache is currently disabled." << llendl;
+		return;
+	}
+
+	if(mReadOnly)
+	{
+		llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl;
+		return;
+	}
 
-	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
 
 	//write the meta element
 	if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
 	{
-		return ;
+		llwarns << "Error writing meta information to cache header." << llendl;
+		delete apr_file;
+		return;
 	}
 
-	mNumEntries = 0 ;
-	for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter)
+	U32 entry_index = 0;
+	handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
+	for(handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
+		iter != iter_end;
+		++iter)
 	{
-		(*iter)->mIndex = mNumEntries++ ;
-		if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo)))
+		HeaderEntryInfo* entry = iter->second;
+		entry->mIndex = entry_index++;
+		if(!checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)))
 		{
-			return ;
+			llwarns << "Failed to write cache header for entry " << entry->mHandle << " (entry_index = " << entry_index << ")" << llendl;
+			delete apr_file;
+			return;
 		}
 	}
 
-	mNumEntries = mHeaderEntryQueue.size() ;
-	if(mNumEntries < mCacheSize)
+	// Why do we need to fill the cache header with default entries?  DK 2010-12-14
+	// It looks like we currently rely on the file being pre-allocated so we can seek during updateEntry().
+	if(entry_index < mCacheSize)
 	{
 		HeaderEntryInfo* entry = new HeaderEntryInfo() ;
-		for(U32 i = mNumEntries ; i < mCacheSize; i++)
+		for(; entry_index < mCacheSize; ++entry_index)
 		{
 			//fill the cache with the default entry.
 			if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo)))
 			{
+				llwarns << "Failed to fill cache header with default entries (entry_index = " << entry_index << ").  Switching to read-only mode." << llendl;
 				mReadOnly = TRUE ; //disable the cache.
-				return ;
+				break;
 			}
 		}
 		delete entry ;
@@ -505,16 +533,19 @@ void LLVOCache::writeCacheHeader()
 
 BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
 {
-	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_WRITE|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
 	apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
 
-	return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
+	BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
+	delete apr_file;
+	return result;
 }
 
 void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) 
 {
 	if(!mEnabled)
 	{
+		llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl;
 		return ;
 	}
 	llassert_always(mInitialized);
@@ -522,22 +553,24 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
 	if(iter == mHandleEntryMap.end()) //no cache
 	{
+		llwarns << "No handle map entry for " << handle << llendl;
 		return ;
 	}
 
 	std::string filename;
 	getObjectCacheFilename(handle, filename);
-	LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+	LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
 
 	LLUUID cache_id ;
 	if(!checkRead(apr_file, cache_id.mData, UUID_BYTES))
 	{
+		llwarns << "Error reading cache_id from " << filename << llendl;
+		delete apr_file;
 		return ;
 	}
 	if(cache_id != id)
 	{
-		llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
-
+		llwarns << "Cache ID (" << cache_id << ") doesn't match id for this region (" << id << "), discarding.  handle = " << handle << llendl;
 		delete apr_file ;
 		return ;
 	}
@@ -545,6 +578,8 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 	S32 num_entries;
 	if(!checkRead(apr_file, &num_entries, sizeof(S32)))
 	{
+		llwarns << "Error reading num_entries from " << filename << llendl;
+		delete apr_file;
 		return ;
 	}
 	
@@ -553,13 +588,12 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 		LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file);
 		if (!entry->getLocalID())
 		{
-			llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
+			llwarns << "Aborting cache file load for " << filename << ", cache file corruption! (entry number = " << i << ")" << llendl;
 			delete entry ;
 			break;
 		}
 		cache_entry_map[entry->getLocalID()] = entry;
 	}
-	num_entries = cache_entry_map.size() ;
 
 	delete apr_file ;
 	return ;
@@ -567,86 +601,104 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 	
 void LLVOCache::purgeEntries()
 {
-	U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ;
-	while(mHeaderEntryQueue.size() > limit)
-	{
-		header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
-		HeaderEntryInfo* entry = *iter ;
+	U32 limit = mCacheSize - (mCacheSize / ENTRIES_PURGE_FACTOR);
+	limit = llclamp(limit, (U32)1, mCacheSize);
+	// Construct a vector of entries out of the map so we can sort by time.
+	std::vector<HeaderEntryInfo*> header_vector;
+	handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
+	for (handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
+		iter != iter_end;
+		++iter)
+	{
+		header_vector.push_back(iter->second);
+	}
+	// Sort by time, oldest first.
+	std::sort(header_vector.begin(), header_vector.end(), header_entry_less());
+	while(header_vector.size() > limit)
+	{
+		HeaderEntryInfo* entry = header_vector.front();
 		
-		removeFromCache(entry->mHandle) ;
-		mHandleEntryMap.erase(entry->mHandle) ;		
-		mHeaderEntryQueue.erase(iter) ;
-		delete entry ;
+		removeFromCache(entry->mHandle);
+		mHandleEntryMap.erase(entry->mHandle);
+		header_vector.erase(header_vector.begin());
+		delete entry;
 	}
 
 	writeCacheHeader() ;
+	// *TODO: Verify that we can avoid re-reading the cache header.  DK 2010-12-14
 	readCacheHeader() ;
-	mNumEntries = mHandleEntryMap.size() ;
 }
 
 void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) 
 {
 	if(!mEnabled)
 	{
+		llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl;
 		return ;
 	}
 	llassert_always(mInitialized);
 
 	if(mReadOnly)
 	{
+		llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl;
 		return ;
 	}
 
+	U32 num_handle_entries = mHandleEntryMap.size();
+	
 	HeaderEntryInfo* entry;
 	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
 	if(iter == mHandleEntryMap.end()) //new entry
-	{		
-		if(mNumEntries >= mCacheSize)
+	{
+		if(num_handle_entries >= mCacheSize)
 		{
 			purgeEntries() ;
+			num_handle_entries = mHandleEntryMap.size();
 		}
 		
 		entry = new HeaderEntryInfo();
 		entry->mHandle = handle ;
 		entry->mTime = time(NULL) ;
-		entry->mIndex = mNumEntries++ ;
-		mHeaderEntryQueue.insert(entry) ;
+		entry->mIndex = num_handle_entries++;
 		mHandleEntryMap[handle] = entry ;
 	}
 	else
 	{
+		// Update access time.
 		entry = iter->second ;
 		entry->mTime = time(NULL) ;
-
-		//resort
-		mHeaderEntryQueue.erase(entry) ;
-		mHeaderEntryQueue.insert(entry) ;
 	}
 
 	//update cache header
 	if(!updateEntry(entry))
 	{
+		llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl;
 		return ; //update failed.
 	}
 
 	if(!dirty_cache)
 	{
+		llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl;
 		return ; //nothing changed, no need to update.
 	}
 
 	//write to cache file
 	std::string filename;
 	getObjectCacheFilename(handle, filename);
-	LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
 	
 	if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES))
 	{
+		llwarns << "Error writing id to " << filename << llendl;
+		delete apr_file;
 		return ;
 	}
 
 	S32 num_entries = cache_entry_map.size() ;
 	if(!checkWrite(apr_file, &num_entries, sizeof(S32)))
 	{
+		llwarns << "Error writing num_entries to " << filename << llendl;
+		delete apr_file;
 		return ;
 	}
 
@@ -654,10 +706,10 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 	{
 		if(!iter->second->writeToFile(apr_file))
 		{
+			llwarns << "Aborting cache file write for " << filename << ", error writing to file!" << llendl;
 			//failed
-			delete apr_file ;
 			removeCache() ;
-			return ;
+			break;
 		}
 	}
 
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index ed2bc8bafecbeaa49e600cc2afe1d46e93e7c05f..e1030079793a01a91e36c9c9cee9f670ae69dc57 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -95,10 +95,13 @@ class LLVOCache
 	{
 		bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const
 		{
-			return lhs->mTime < rhs->mTime; // older entry in front of queue (set)
+			if (lhs->mTime == rhs->mTime)
+			{
+				return lhs->mHandle < rhs->mHandle;
+			}
+			return lhs->mTime < rhs->mTime; // older entry in front
 		}
 	};
-	typedef std::set<HeaderEntryInfo*, header_entry_less> header_entry_queue_t;
 	typedef std::map<U64, HeaderEntryInfo*> handle_entry_map_t;
 private:
 	LLVOCache() ;
@@ -125,8 +128,8 @@ class LLVOCache
 	void removeCache() ;
 	void purgeEntries();
 	BOOL updateEntry(const HeaderEntryInfo* entry);
-	BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
-	BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
+	BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ;
+	BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ;
 	
 private:
 	BOOL                 mEnabled;
@@ -134,11 +137,9 @@ class LLVOCache
 	BOOL                 mReadOnly ;
 	HeaderMetaInfo       mMetaInfo;
 	U32                  mCacheSize;
-	U32                  mNumEntries;
 	std::string          mHeaderFileName ;
 	std::string          mObjectCacheDirName;
 	LLVolatileAPRPool*   mLocalAPRFilePoolp ; 	
-	header_entry_queue_t mHeaderEntryQueue;
 	handle_entry_map_t   mHandleEntryMap;	
 
 	static LLVOCache* sInstance ;
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index d239347810648188b9b7dd2917a8030d8d6d99a7..4f6ec4ca616ccb4721b9eb7b82b016f97acf9817 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -33,6 +33,7 @@
 #include "pipeline.h"
 #include "llsky.h"
 
+#include "lldiriterator.h"
 #include "llfloaterreg.h"
 #include "llsliderctrl.h"
 #include "llspinctrl.h"
@@ -85,11 +86,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)
 	std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", ""));
 	LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL;
 			
-	bool found = true;			
+	bool found = true;
+	LLDirIterator app_settings_iter(path_name, "*.xml");
 	while(found) 
 	{
 		std::string name;
-		found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name);
+		found = app_settings_iter.next(name);
 		if(found)
 		{
 
@@ -111,11 +113,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)
 	std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));
 	LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL;
 			
-	found = true;			
+	found = true;
+	LLDirIterator user_settings_iter(path_name2, "*.xml");
 	while(found) 
 	{
 		std::string name;
-		found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name);
+		found = user_settings_iter.next(name);
 		if(found)
 		{
 			name=name.erase(name.length()-4);
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index e5f52dfc979b5ef4cd09c8366d6b5263d541b9ba..848efcbb49e5f8e28f3bd393df7767dd003b27ee 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -31,6 +31,7 @@
 #include "pipeline.h"
 #include "llsky.h"
 
+#include "lldiriterator.h"
 #include "llfloaterreg.h"
 #include "llsliderctrl.h"
 #include "llspinctrl.h"
@@ -100,11 +101,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
 	std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""));
 	LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL;
 			
-	bool found = true;			
+	bool found = true;
+	LLDirIterator app_settings_iter(path_name, "*.xml");
 	while(found) 
 	{
 		std::string name;
-		found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name);
+		found = app_settings_iter.next(name);
 		if(found)
 		{
 
@@ -126,11 +128,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
 	std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
 	LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL;
 			
-	found = true;			
+	found = true;
+	LLDirIterator user_settings_iter(path_name2, "*.xml");
 	while(found) 
 	{
 		std::string name;
-		found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name);
+		found = user_settings_iter.next(name);
 		if(found)
 		{
 			name=name.erase(name.length()-4);
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 3f785a99fef3f178e8ea1fa4ed5f90173630dd56..cef3d87f3605c84c554d51a09ad755d35a69e175 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -424,6 +424,7 @@ class LLPipeline
 		RENDER_DEBUG_AVATAR_VOLUME      = 0x0100000,
 		RENDER_DEBUG_BUILD_QUEUE		= 0x0200000,
 		RENDER_DEBUG_AGENT_TARGET       = 0x0400000,
+		RENDER_DEBUG_UPDATE_TYPE		= 0x0800000,
 	};
 
 public:
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 62441fd9841df8d9ea98aa7b9f7423302d0c9dfd..75aec21f93b6c50732591715620b8d8e2bef8a97 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -114,9 +114,6 @@
     <color
      name="AlertCautionTextColor"
      reference="LtYellow" />
-    <color
-     name="AgentLinkColor"
-     reference="EmphasisColor" />
     <color
      name="AlertTextColor"
      value="0.58 0.66 0.84 1" />
@@ -348,9 +345,6 @@
     <color
      name="GridlineShadowColor"
      value="0 0 0 0.31" />
-    <color
-     name="GroupLinkColor"
-     reference="White" />
     <color
      name="GroupNotifyBoxColor"
      value="0.3344 0.5456 0.5159 1" />
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index 70299c61b4e8506ecc0bc07506a46179d6be2535..593e686d4c126da89574cedc0946567e368c84ee 100644
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -1636,7 +1636,7 @@ Knappen vil blive vist når der er nok plads til den.
 	<notification name="ShareItemsConfirmation">
 		Er du sikker på at du vil dele følgende genstande:
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 Med følgende beboere:
 
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 06cc02cd847a5181d9ec94da8d9bbffe6b9310b7..a2d0b5a1702394375b508705f78c376017549bfd 100644
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -2747,7 +2747,7 @@ Die Schaltfläche wird angezeigt, wenn genügend Platz vorhanden ist.
 	<notification name="ShareItemsConfirmation">
 		Möchten Sie diese Objekte wirklich für andere freigeben:
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 Für folgende Einwohner:
 
diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml
index c751aa4e0c2caa949e8530d5cc5237750ab70ebf..719509301b0a9486393c0c5490df6ab4244b1620 100644
--- a/indra/newview/skins/default/xui/en/menu_object.xml
+++ b/indra/newview/skins/default/xui/en/menu_object.xml
@@ -100,7 +100,7 @@
          name="Object Attach HUD" />
    </context_menu>
    <context_menu
-         label="Remove"
+         label="Manage"
          name="Remove">
    <menu_item_call
          enabled="false"
@@ -129,15 +129,6 @@
          <menu_item_call.on_enable
           function="Object.EnableReturn" />
      </menu_item_call>
-     <menu_item_call
-   enabled="false"
-   label="Delete"
-   name="Delete">
-      <menu_item_call.on_click
-       function="Object.Delete" />
-      <menu_item_call.on_enable
-       function="Object.EnableDelete" />
-    </menu_item_call>
     </context_menu>
    <menu_item_separator layout="topleft" />
    <menu_item_call
@@ -176,4 +167,13 @@
       <menu_item_call.on_enable
        function="Object.EnableBuy" />
    </menu_item_call>
+   <menu_item_call
+     enabled="false"
+     label="Delete"
+     name="Delete">
+      <menu_item_call.on_click
+       function="Object.Delete" />
+      <menu_item_call.on_enable
+       function="Object.EnableDelete" />
+  </menu_item_call>
 </context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 3d500c2371daf44fab9b230efea77770a4170e68..2207e418c8dff036b8e58a3823378bb4cd10abd8 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2152,6 +2152,16 @@
            function="Advanced.ToggleInfoDisplay"
            parameter="render batches" />
         </menu_item_check>
+        <menu_item_check
+         label="Update Type"
+         name="Update Type">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="update type" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="update type" />
+        </menu_item_check>
         <menu_item_check
          label="Texture Anim"
          name="Texture Anim">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 3df53ac442120dd9872e5c2621a531037a1ab106..6f21938bdb0fd21f9543cec2305f3cfdebce4948 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6431,7 +6431,7 @@ Select residents to share with.
    type="alertmodal">
 Are you sure you want to share the following items:
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 With the following Residents:
 
diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
index 61d6cbb2d0e1c0d0936a5a14eb7c6ff9897706f0..eff674c628af3d10d055b2c393788ca3271d5298 100644
--- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
@@ -67,23 +67,23 @@
         <scroll_list.columns
          label="Parcel"
          name="name"
-         width="47" />
+         relative_width="0.2" />
         <scroll_list.columns
          label="Region"
          name="location"
-         width="47" />
+         relative_width="0.2" />
         <scroll_list.columns
          label="Type"
          name="type"
-         width="47" />
+         relative_width="0.2" />
         <scroll_list.columns
          label="Area"
          name="area"
-         width="47" />
+         relative_width="0.2" />
         <scroll_list.columns
          label="Hidden"
          name="hidden"
-         width="47" />
+         relative_width="0.2" />
     </scroll_list>
     <text
      type="string"
diff --git a/indra/newview/skins/default/xui/en/widgets/floater.xml b/indra/newview/skins/default/xui/en/widgets/floater.xml
index 85d0c633af5fb362983869118c12a711f1550fe5..2e5ebafe46bf3dd3a1c21829ecb9a578d6badcdc 100644
--- a/indra/newview/skins/default/xui/en/widgets/floater.xml
+++ b/indra/newview/skins/default/xui/en/widgets/floater.xml
@@ -21,4 +21,5 @@
  tear_off_pressed_image="tearoff_pressed.tga"
  dock_pressed_image="Icon_Dock_Press"
  help_pressed_image="Icon_Help_Press"
+ focus_root="true"
   />
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 2dd7a6b0f549de273aa8a827b7a1342fcefa2483..14ce39e8fc673c493d4442ebe5cc79db4bf06be5 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -2734,7 +2734,7 @@ Se mostrará cuando haya suficiente espacio.
 	<notification name="ShareItemsConfirmation">
 		¿Estás seguro de que quieres compartir los elementos siguientes?
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 Con los siguientes residentes:
 
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index ec362d7f22f73a87e66df815fe5463757c9d098e..f0b0e63af0079ca4bac7786f1bdf29268a68901b 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -2730,7 +2730,7 @@ Le bouton sera affiché quand il y aura suffisamment de place.
 	<notification name="ShareItemsConfirmation">
 		Voulez-vous vraiment partager les articles suivants :
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 avec les résidents suivants :
 
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index 32483881b2b6d07aa2a5f62210bf4ab6df776145..5e53080c77b312a87c8d54e4c31e591aeebc2a8e 100644
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -2679,7 +2679,7 @@ Il pulsante verrà visualizzato quando lo spazio sarà sufficiente.
 	<notification name="ShareItemsConfirmation">
 		Sei sicuro di volere condividere gli oggetti
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 Con i seguenti residenti?
 
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index c0af0e03ff2edfddb4ddeb85b97272b97703b3fe..f133bb361afcaf578764b04fc60c07c0f25f1cad 100644
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -2731,7 +2731,7 @@ M キーを押して変更します。
 	<notification name="ShareItemsConfirmation">
 		次のアイテムを共有しますか:
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 次の住人と共有しますか:
 
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index 8151c7eb938304846d51f890b8b1d769879b4d9f..57a6b8b8ef9e6cfd258dff586746536f8c7d276c 100644
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -2691,7 +2691,7 @@ Przycisk zostanie wyświetlony w przypadku dostatecznej ilości przestrzeni.
 	<notification name="ShareItemsConfirmation">
 		Jesteś pewien/pewna, że chcesz udostępnić następujące obiekty:
 
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 następującym Rezydentom:
 
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index dc38b740aaf54053ecb2bc2e575919a6937a26f0..a1855f2e892ce26b66be0a7b38aa19bf41fd6153 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -477,7 +477,7 @@ Para aumentar a qualidade do vídeo, vá para Preferências &gt; Vídeo.
 	</notification>
 	<notification name="CannotCopyWarning">
 		Você não tem autorização para copiar os itens abaixo:
-[ITENS]
+[ITEMS]
 ao dá-los, você ficará sem eles no seu inventário. Deseja realmente dar estes itens?
 		<usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/>
 	</notification>
@@ -2714,7 +2714,7 @@ O botão será exibido quando houver espaço suficente.
 	<notification name="ShareItemsConfirmation">
 		Tem certeza de que quer compartilhar os items abaixo?
 
-[ITENS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
 
 Com os seguintes residentes:
 
diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp
index dae22521bb606a2dbe48d1200b177e5d7b49125a..7862cce3a1de667ec909a8f26751c9f55a64dd36 100644
--- a/indra/newview/tests/llremoteparcelrequest_test.cpp
+++ b/indra/newview/tests/llremoteparcelrequest_test.cpp
@@ -32,6 +32,7 @@
 
 #include "../llagent.h"
 #include "message.h"
+#include "llurlentry.h"
 
 namespace {
 	LLControlGroup s_saved_settings("dummy_settings");
@@ -72,6 +73,7 @@ LLUIColor::LLUIColor(void) { }
 LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { }
 LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker<LLControlGroup, std::string>(name) { }
 LLControlGroup::~LLControlGroup(void) { }
+void LLUrlEntryParcel::processParcelInfo(const LLUrlEntryParcel::LLParcelData& parcel_data) { }
 
 namespace tut
 {
diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
index 88ab5a22845fe1b774dce553b4eb3c049d918ea6..e19d5724f172b5bdc552d2243007611b285076e6 100644
--- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
+++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
@@ -59,12 +59,6 @@ class LLDir_Mock : public LLDir
 		return 0;
 	}
 
-	BOOL getNextFileInDir(const std::string &dirname, 
-						  const std::string &mask, 
-						  std::string &fname) 
-	{
-		return false;
-	}
 	void getRandomFileInDir(const std::string &dirname, 
 							const std::string &mask, 
 							std::string &fname) {}