diff --git a/autobuild.xml b/autobuild.xml
index b1478a46b24017b18aee5e26009cca3a3b24d54e..8194b3d4ebb6735ba61f6c863edf154a56f49155 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1965,11 +1965,11 @@
     <key>package_description</key>
     <map>
       <key>description</key>
-      <string>Spell checking dictionaries</string>
+      <string>Second Life Viewer</string>
       <key>license</key>
-      <string>various open</string>
+      <string>LGPL</string>
       <key>name</key>
-      <string>dictionaries</string>
+      <string>Second Life Viewer</string>
       <key>platforms</key>
       <map>
         <key>common</key>
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 931211f6226ea947d3a42515bd4291df73123e76..0c7ba2471244727170043ad63ea3bbed8cbf4e09 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -175,8 +175,11 @@ Ansariel Hiller
 	STORM-1685
 	STORM-1713
 	STORM-1899
+	STORM-1932
+	STORM-1933
 	MAINT-2368
 	STORM-1931
+	MAINT-2773
 Aralara Rajal
 Arare Chantilly
 	CHUIBUG-191
@@ -304,9 +307,12 @@ Christopher  Organiser
 Ciaran Laval
 Cinder Roxley
     BUG-2326
+    OPEN-185
     STORM-1703
 	STORM-1948
+    STORM-1958
     STORM-1952
+    STORM-1951
 Clara Young
 Coaldust Numbers
     VWR-1095
@@ -652,7 +658,7 @@ Jonathan Yap
 	STORM-1809
 	STORM-1793
 	STORM-1810
-	STORM-1877
+	STORM-1838
 	STORM-1892
 	STORM-1894
 	STORM-1860
@@ -662,8 +668,11 @@ Jonathan Yap
 	STORM-1858
 	STORM-1862
 	STORM-1918
+	STORM-1929
 	STORM-1953
 	OPEN-161
+	STORM-1953
+	STORM-1957
 Kadah Coba
 	STORM-1060
     STORM-1843
@@ -680,6 +689,7 @@ Kaimen Takahe
 Katharine Berry
 	STORM-1900
 	STORM-1940
+    OPEN-149
 	STORM-1941
 Keklily Longfall
 Ken Lavender
@@ -929,6 +939,7 @@ Nicky Dasmijn
 	BUG-3605
 	CHUIBUG-197
 	STORM-1937
+	OPEN-187
 Nicky Perian
 	OPEN-1
 	STORM-1087
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index af2063ce6d7ad8d2f9d241baec448ec41734df0e..e4b63dc7cb8d8c4bdc954c954299106565a02fdb 100755
--- a/indra/cmake/BuildVersion.cmake
+++ b/indra/cmake/BuildVersion.cmake
@@ -16,22 +16,26 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
 
         else (DEFINED ENV{revision})
            find_program(MERCURIAL hg)
-           if (DEFINED MERCURIAL)
+           find_program(WORDCOUNT wc)
+           find_program(SED sed)
+           if (DEFINED MERCURIAL AND DEFINED WORDCOUNT AND DEFINED SED)
               execute_process(
-                 COMMAND ${MERCURIAL} log -r tip --template "{rev}"
+                 COMMAND ${MERCURIAL} log -r tip:0 --template '\\n'
+                 COMMAND ${WORDCOUNT} -l
+                 COMMAND ${SED} "s/ //g"
                  OUTPUT_VARIABLE VIEWER_VERSION_REVISION
                  OUTPUT_STRIP_TRAILING_WHITESPACE
                  )
               if ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
                  message("Revision (from hg) ${VIEWER_VERSION_REVISION}")
               else ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
+                 message("Revision not set (repository not found?); using 0")
                  set(VIEWER_VERSION_REVISION 0 )
-                 message("Revision not set, repository not found, using ${VIEWER_VERSION_REVISION}")
               endif ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
-           else (DEFINED MERCURIAL)
+           else (DEFINED MERCURIAL AND DEFINED WORDCOUNT AND DEFINED SED)
+              message("Revision not set: 'hg', 'wc' or 'sed' not found; using 0")
               set(VIEWER_VERSION_REVISION 0)
-              message("Revision not set, 'hg' not found (${MERCURIAL}), using ${VIEWER_VERSION_REVISION}")
-           endif (DEFINED MERCURIAL)
+           endif (DEFINED MERCURIAL AND DEFINED WORDCOUNT AND DEFINED SED)
         endif (DEFINED ENV{revision})
         message("Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
     else ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index b047f86e6ef0c9fbcefaa3a7dfd3b4aec33ef402..8c8c3158087429239b1ad50501da01344f1122b8 100755
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -50,7 +50,7 @@ class LLColor4
 		LLColor4(F32 r, F32 g, F32 b);		// Initializes LLColor4 to (r, g, b, 1)
 		LLColor4(F32 r, F32 g, F32 b, F32 a);		// Initializes LLColor4 to (r. g, b, a)
 		LLColor4(U32 clr);							// Initializes LLColor4 to (r=clr>>24, etc))
-		LLColor4(const F32 *vec);			// Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1)
+		LLColor4(const F32 *vec);			// Initializes LLColor4 to (vec[0]. vec[1], vec[2], vec[3])
 		LLColor4(const LLColor3 &vec, F32 a = 1.f);	// Initializes LLColor4 to (vec, a)
 		explicit LLColor4(const LLSD& sd);
 		explicit LLColor4(const LLColor4U& color4u);  // "explicit" to avoid automatic conversion
diff --git a/indra/llmessage/llinstantmessage.h b/indra/llmessage/llinstantmessage.h
index db4a38ea9e968668632ae8f81ee188fec70388c4..f7118f8ccf33765918c69fe562ff20ea3447bbf2 100755
--- a/indra/llmessage/llinstantmessage.h
+++ b/indra/llmessage/llinstantmessage.h
@@ -126,7 +126,7 @@ enum EInstantMessage
 	IM_LURE_ACCEPTED = 23,
 	IM_LURE_DECLINED = 24,
 	IM_GODLIKE_LURE_USER = 25,
-	IM_YET_TO_BE_USED = 26,
+	IM_TELEPORT_REQUEST = 26,
 
 	// IM that notifie of a new group election.
 	// Name is name of person who called vote.
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 34a08603fabdb165486892b21c9cc69b2faf6923..589ceac5016ebccd554dcd8e70e6ba99515f66cf 100755
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -75,6 +75,7 @@ set(llui_SOURCE_FILES
     llmultislider.cpp
     llmultisliderctrl.cpp
     llnotifications.cpp
+    llnotificationslistener.cpp
     llnotificationsutil.cpp
     llpanel.cpp
     llprogressbar.cpp
@@ -128,6 +129,7 @@ set(llui_SOURCE_FILES
     llviewmodel.cpp
     llview.cpp
     llviewquery.cpp
+    llviewereventrecorder.cpp
     llwindowshade.cpp
     llxuiparser.cpp
     )
@@ -183,6 +185,7 @@ set(llui_HEADER_FILES
     llmultislider.h
     llnotificationptr.h
     llnotifications.h
+    llnotificationslistener.h
     llnotificationsutil.h
     llnotificationtemplate.h
     llnotificationvisibilityrule.h
@@ -240,6 +243,7 @@ set(llui_HEADER_FILES
     llviewinject.h
     llviewmodel.h
     llview.h
+    llviewereventrecorder.h
     llviewquery.h
     llwindowshade.h
     llxuiparser.h
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 44f2c1efe92d98a586b437efea382ad802fa0406..50ac511d18f1560c1678dfb358274c0a83bcde29 100755
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -49,6 +49,7 @@
 #include "lluictrlfactory.h"
 #include "llhelp.h"
 #include "lldockablefloater.h"
+#include "llviewereventrecorder.h"
 
 static LLDefaultChildRegistry::Register<LLButton> r("button");
 
@@ -443,6 +444,8 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
 		 */
 		LLUICtrl::handleMouseDown(x, y, mask);
 
+		LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
+
 		if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
 
 		mMouseDownTimer.start();
@@ -473,6 +476,7 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 		 * by calling LLUICtrl::mMouseUpSignal(x, y, mask);
 		 */
 		LLUICtrl::handleMouseUp(x, y, mask);
+		LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); 
 
 		// Regardless of where mouseup occurs, handle callback
 		if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 6ea0080f6ccb1221ec6c56fbd3abb3f79994fc4a..182c5cfd8acf731f16cf77690004349af0c7ec13 100755
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -29,7 +29,7 @@
 // mini-map floater, etc.
 
 #include "linden_common.h"
-
+#include "llviewereventrecorder.h"
 #include "llfloater.h"
 
 #include "llfocusmgr.h"
@@ -642,7 +642,10 @@ void LLFloater::handleVisibilityChange ( BOOL new_visibility )
 
 void LLFloater::openFloater(const LLSD& key)
 {
-	llinfos << "Opening floater " << getName() << llendl;
+    llinfos << "Opening floater " << getName() << " full path: " << getPathname() << llendl;
+
+	LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), true,"floater"); // Last param is event subtype or empty string
+
 	mKey = key; // in case we need to open ourselves again
 
 	if (getSoundFlags() != SILENT 
@@ -696,6 +699,7 @@ void LLFloater::openFloater(const LLSD& key)
 void LLFloater::closeFloater(bool app_quitting)
 {
 	llinfos << "Closing floater " << getName() << llendl;
+	LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), false,"floater"); // Last param is event subtype or empty string
 	if (app_quitting)
 	{
 		LLFloater::sQuitting = true;
@@ -1542,6 +1546,17 @@ BOOL LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return TRUE;//always
 }
 
+// virtual
+BOOL LLFloater::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+	lldebugs << "LLFloater::handleMouseUp calling LLPanel (really LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << llendl;
+	BOOL handled = LLPanel::handleMouseUp(x,y,mask); // Not implemented in LLPanel so this actually calls LLView
+	if (handled) {
+		LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
+	}
+	return handled;
+}
+
 // virtual
 BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
 {
@@ -1562,7 +1577,11 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
 	else
 	{
 		bringToFront( x, y );
-		return LLPanel::handleMouseDown( x, y, mask );
+		BOOL handled = LLPanel::handleMouseDown( x, y, mask ); 
+		if (handled) {
+			LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); 
+		}
+		return handled;
 	}
 }
 
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 59448530d9b518ad1af758ccc9d6086ba8964cb5..953689498f28bbbe0c233c059239a80f21affb69 100755
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -289,6 +289,7 @@ class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater>
 	S32				getHeaderHeight() const { return mHeaderHeight; }
 
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
+	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleRightMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleDoubleClick(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMiddleMouseDown(S32 x, S32 y, MASK mask);
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 3186c5460ade175c8093eae8f8d6b5b2656c8e29..5c288c3f03e618a1597c630dd005475c522262ad 100755
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1206,6 +1206,7 @@ LLNotifications::LLNotifications()
 :	LLNotificationChannelBase(LLNotificationFilters::includeEverything),
 	mIgnoreAllNotifications(false)
 {
+        mListener.reset(new LLNotificationsListener(*this));
 	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
 }
 
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 3b620084eee59165f2e2a1bf872b76df1892c5a7..6ac4a988060a653b668cbcd0ef7c4a121b211698 100755
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -98,6 +98,8 @@
 #include "llrefcount.h"
 #include "llsdparam.h"
 
+#include "llnotificationslistener.h"
+
 class LLAvatarName;
 typedef enum e_notification_priority
 {
@@ -978,6 +980,8 @@ class LLNotifications :
 
 	bool mIgnoreAllNotifications;
 
+	boost::scoped_ptr<LLNotificationsListener> mListener;
+
 	std::vector<LLNotificationChannelPtr> mDefaultChannels;
 };
 
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9e8e943ee63de24970f91a5772f8e35c812a22e5
--- /dev/null
+++ b/indra/llui/llnotificationslistener.cpp
@@ -0,0 +1,359 @@
+/**
+ * @file   llnotificationslistener.cpp
+ * @author Brad Kittenbrink
+ * @date   2009-07-08
+ * @brief  Implementation for llnotificationslistener.
+ * 
+ * $LicenseInfo:firstyear=2009&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 "linden_common.h"
+#include "llnotificationslistener.h"
+#include "llnotifications.h"
+#include "llnotificationtemplate.h"
+#include "llsd.h"
+#include "llui.h"
+
+LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
+    LLEventAPI("LLNotifications",
+               "LLNotifications listener to (e.g.) pop up a notification"),
+    mNotifications(notifications)
+{
+    add("requestAdd",
+        "Add a notification with specified [\"name\"], [\"substitutions\"] and [\"payload\"].\n"
+        "If optional [\"reply\"] specified, arrange to send user response on that LLEventPump.",
+        &LLNotificationsListener::requestAdd);
+    /*    add("listChannels",
+        "Post to [\"reply\"] a map of info on existing channels",
+        &LLNotificationsListener::listChannels,
+        LLSD().with("reply", LLSD()));
+    */
+    add("listChannelNotifications",
+        "Post to [\"reply\"] an array of info on notifications in channel [\"channel\"]",
+        &LLNotificationsListener::listChannelNotifications,
+        LLSD().with("reply", LLSD()).with("channel", LLSD()));
+    add("respond",
+        "Respond to notification [\"uuid\"] with data in [\"response\"]",
+        &LLNotificationsListener::respond,
+        LLSD().with("uuid", LLSD()));
+    add("cancel",
+        "Cancel notification [\"uuid\"]",
+        &LLNotificationsListener::cancel,
+        LLSD().with("uuid", LLSD()));
+    add("ignore",
+        "Ignore future notification [\"name\"]\n"
+        "(from <notification name= > in notifications.xml)\n"
+        "according to boolean [\"ignore\"].\n"
+        "If [\"name\"] is omitted or undefined, [un]ignore all future notifications.\n"
+        "Note that ignored notifications are not forwarded unless intercepted before\n"
+        "the \"Ignore\" channel.",
+        &LLNotificationsListener::ignore);
+    add("forward",
+        "Forward to [\"pump\"] future notifications on channel [\"channel\"]\n"
+        "according to boolean [\"forward\"]. When enabled, only types matching\n"
+        "[\"types\"] are forwarded, as follows:\n"
+        "omitted or undefined: forward all notifications\n"
+        "string: forward only the specific named [sig]type\n"
+        "array of string: forward any notification matching any named [sig]type.\n"
+        "When boolean [\"respond\"] is true, we auto-respond to each forwarded\n"
+        "notification.",
+        &LLNotificationsListener::forward,
+        LLSD().with("channel", LLSD()));
+}
+
+// This is here in the .cpp file so we don't need the definition of class
+// Forwarder in the header file.
+LLNotificationsListener::~LLNotificationsListener()
+{
+}
+
+void LLNotificationsListener::requestAdd(const LLSD& event_data) const
+{
+	if(event_data.has("reply"))
+	{
+		mNotifications.add(event_data["name"], 
+						   event_data["substitutions"], 
+						   event_data["payload"],
+						   boost::bind(&LLNotificationsListener::NotificationResponder, 
+									   this, 
+									   event_data["reply"].asString(), 
+									   _1, _2
+									   )
+						   );
+	}
+	else
+	{
+		mNotifications.add(event_data["name"], 
+						   event_data["substitutions"], 
+						   event_data["payload"]);
+	}
+}
+
+void LLNotificationsListener::NotificationResponder(const std::string& reply_pump, 
+										const LLSD& notification, 
+										const LLSD& response) const
+{
+	LLSD reponse_event;
+	reponse_event["notification"] = notification;
+	reponse_event["response"] = response;
+	LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
+}
+/*
+void LLNotificationsListener::listChannels(const LLSD& params) const
+{
+    LLReqID reqID(params);
+    LLSD response(reqID.makeResponse());
+    for (LLNotifications::
+
+
+
+    for (LLNotifications::ChannelMap::const_iterator cmi(mNotifications.mChannels.begin()),
+                                                     cmend(mNotifications.mChannels.end());
+         cmi != cmend; ++cmi)
+    {
+        LLSD channelInfo;
+        channelInfo["parent"] = cmi->second->getParentChannelName();
+        response[cmi->first] = channelInfo;
+    }
+    LLEventPumps::instance().obtain(params["reply"]).post(response);
+}
+*/
+void LLNotificationsListener::listChannelNotifications(const LLSD& params) const
+{
+    LLReqID reqID(params);
+    LLSD response(reqID.makeResponse());
+    LLNotificationChannelPtr channel(mNotifications.getChannel(params["channel"]));
+    if (channel)
+    {
+        LLSD notifications(LLSD::emptyArray());
+        for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end());
+             ni != nend; ++ni)
+        {
+            notifications.append(asLLSD(*ni));
+        }
+        response["notifications"] = notifications;
+    }
+    LLEventPumps::instance().obtain(params["reply"]).post(response);
+}
+
+void LLNotificationsListener::respond(const LLSD& params) const
+{
+    LLNotificationPtr notification(mNotifications.find(params["uuid"]));
+    if (notification)
+    {
+        notification->respond(params["response"]);
+    }
+}
+
+void LLNotificationsListener::cancel(const LLSD& params) const
+{
+    LLNotificationPtr notification(mNotifications.find(params["uuid"]));
+    if (notification)
+    {
+        mNotifications.cancel(notification);
+    }
+}
+
+void LLNotificationsListener::ignore(const LLSD& params) const
+{
+    // Calling a method named "ignore", but omitting its "ignore" Boolean
+    // argument, should by default cause something to be ignored. Explicitly
+    // pass ["ignore"] = false to cancel ignore.
+    bool ignore = true;
+    if (params.has("ignore"))
+    {
+        ignore = params["ignore"].asBoolean();
+    }
+    // This method can be used to affect either a single notification name or
+    // all future notifications. The two use substantially different mechanisms.
+    if (params["name"].isDefined())
+    {
+        // ["name"] was passed: ignore just that notification
+		LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]);
+		if (templatep)
+		{
+			templatep->mForm->setIgnored(ignore);
+		}
+    }
+    else
+    {
+        // no ["name"]: ignore all future notifications
+        mNotifications.setIgnoreAllNotifications(ignore);
+    }
+}
+
+class LLNotificationsListener::Forwarder: public LLEventTrackable
+{
+    LOG_CLASS(LLNotificationsListener::Forwarder);
+public:
+    Forwarder(LLNotifications& llnotifications, const std::string& channel):
+        mNotifications(llnotifications),
+        mRespond(false)
+    {
+        // Connect to the specified channel on construction. Because
+        // LLEventTrackable is a base, we should automatically disconnect when
+        // destroyed.
+        LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel));
+        if (channelptr)
+        {
+            // Insert our processing as a "passed filter" listener. This way
+            // we get to run before all the "changed" listeners, and we get to
+            // swipe it (hide it from the other listeners) if desired.
+            channelptr->connectPassedFilter(boost::bind(&Forwarder::handle, this, _1));
+        }
+    }
+
+    void setPumpName(const std::string& name) { mPumpName = name; }
+    void setTypes(const LLSD& types) { mTypes = types; }
+    void setRespond(bool respond) { mRespond = respond; }
+
+private:
+    bool handle(const LLSD& notification) const;
+    bool matchType(const LLSD& filter, const std::string& type) const;
+
+    LLNotifications& mNotifications;
+    std::string mPumpName;
+    LLSD mTypes;
+    bool mRespond;
+};
+
+void LLNotificationsListener::forward(const LLSD& params)
+{
+    std::string channel(params["channel"]);
+    // First decide whether we're supposed to start forwarding or stop it.
+    // Default to true.
+    bool forward = true;
+    if (params.has("forward"))
+    {
+        forward = params["forward"].asBoolean();
+    }
+    if (! forward)
+    {
+        // This is a request to stop forwarding notifications on the specified
+        // channel. The rest of the params don't matter.
+        // Because mForwarders contains scoped_ptrs, erasing the map entry
+        // DOES delete the heap Forwarder object. Because Forwarder derives
+        // from LLEventTrackable, destroying it disconnects it from the
+        // channel.
+        mForwarders.erase(channel);
+        return;
+    }
+    // From here on, we know we're being asked to start (or modify) forwarding
+    // on the specified channel. Find or create an appropriate Forwarder.
+    ForwarderMap::iterator
+        entry(mForwarders.insert(ForwarderMap::value_type(channel, ForwarderMap::mapped_type())).first);
+    if (! entry->second)
+    {
+        entry->second.reset(new Forwarder(mNotifications, channel));
+    }
+    // Now, whether this Forwarder is brand-new or not, update it with the new
+    // request info.
+    Forwarder& fwd(*entry->second);
+    fwd.setPumpName(params["pump"]);
+    fwd.setTypes(params["types"]);
+    fwd.setRespond(params["respond"]);
+}
+
+bool LLNotificationsListener::Forwarder::handle(const LLSD& notification) const
+{
+    LL_INFOS("LLNotificationsListener") << "handle(" << notification << ")" << LL_ENDL;
+    if (notification["sigtype"].asString() == "delete")
+    {
+        LL_INFOS("LLNotificationsListener") << "ignoring delete" << LL_ENDL;
+        // let other listeners see the "delete" operation
+        return false;
+    }
+    LLNotificationPtr note(mNotifications.find(notification["id"]));
+    if (! note)
+    {
+        LL_INFOS("LLNotificationsListener") << notification["id"] << " not found" << LL_ENDL;
+        return false;
+    }
+    if (! matchType(mTypes, note->getType()))
+    {
+        LL_INFOS("LLNotificationsListener") << "didn't match types " << mTypes << LL_ENDL;
+        // We're not supposed to intercept this particular notification. Let
+        // other listeners process it.
+        return false;
+    }
+    LL_INFOS("LLNotificationsListener") << "sending via '" << mPumpName << "'" << LL_ENDL;
+    // This is a notification we care about. Forward it through specified
+    // LLEventPump.
+    LLEventPumps::instance().obtain(mPumpName).post(asLLSD(note));
+    // Are we also being asked to auto-respond?
+    if (mRespond)
+    {
+        LL_INFOS("LLNotificationsListener") << "should respond" << LL_ENDL;
+        note->respond(LLSD::emptyMap());
+        // Did that succeed in removing the notification? Only cancel() if
+        // it's still around -- otherwise we get an LL_ERRS crash!
+        note = mNotifications.find(notification["id"]);
+        if (note)
+        {
+            LL_INFOS("LLNotificationsListener") << "respond() didn't clear, canceling" << LL_ENDL;
+            mNotifications.cancel(note);
+        }
+    }
+    // If we've auto-responded to this notification, then it's going to be
+    // deleted. Other listeners would get the change operation, try to look it
+    // up and be baffled by lookup failure. So when we auto-respond, suppress
+    // this notification: don't pass it to other listeners.
+    return mRespond;
+}
+
+bool LLNotificationsListener::Forwarder::matchType(const LLSD& filter, const std::string& type) const
+{
+    // Decide whether this notification matches filter:
+    // undefined: forward all notifications
+    if (filter.isUndefined())
+    {
+        return true;
+    }
+    // array of string: forward any notification matching any named type
+    if (filter.isArray())
+    {
+        for (LLSD::array_const_iterator ti(filter.beginArray()), tend(filter.endArray());
+             ti != tend; ++ti)
+        {
+            if (ti->asString() == type)
+            {
+                return true;
+            }
+        }
+        // Didn't match any entry in the array
+        return false;
+    }
+    // string: forward only the specific named type
+    return (filter.asString() == type);
+}
+
+LLSD LLNotificationsListener::asLLSD(LLNotificationPtr note)
+{
+    LLSD notificationInfo(note->asLLSD());
+    // For some reason the following aren't included in LLNotification::asLLSD().
+    notificationInfo["summary"] = note->summarize();
+    notificationInfo["id"]      = note->id();
+    notificationInfo["type"]    = note->getType();
+    notificationInfo["message"] = note->getMessage();
+    notificationInfo["label"]   = note->getLabel();
+    return notificationInfo;
+}
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..f9f7641de6c5fb1f8d4d7073a435d73d7348fc5b
--- /dev/null
+++ b/indra/llui/llnotificationslistener.h
@@ -0,0 +1,69 @@
+/**
+ * @file   llnotificationslistener.h
+ * @author Brad Kittenbrink
+ * @date   2009-07-08
+ * @brief  Wrap subset of LLNotifications API in event API for test scripts.
+ * 
+ * $LicenseInfo:firstyear=2009&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_LLNOTIFICATIONSLISTENER_H
+#define LL_LLNOTIFICATIONSLISTENER_H
+
+#include "lleventapi.h"
+#include "llnotificationptr.h"
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <string>
+
+class LLNotifications;
+class LLSD;
+
+class LLNotificationsListener : public LLEventAPI
+{
+public:
+    LLNotificationsListener(LLNotifications & notifications);
+    ~LLNotificationsListener();
+
+private:
+    void requestAdd(LLSD const & event_data) const;
+
+	void NotificationResponder(const std::string& replypump, 
+							   const LLSD& notification, 
+							   const LLSD& response) const;
+
+    void listChannels(const LLSD& params) const;
+    void listChannelNotifications(const LLSD& params) const;
+    void respond(const LLSD& params) const;
+    void cancel(const LLSD& params) const;
+    void ignore(const LLSD& params) const;
+    void forward(const LLSD& params);
+
+    static LLSD asLLSD(LLNotificationPtr);
+
+    class Forwarder;
+    typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap;
+    ForwarderMap mForwarders;
+	LLNotifications & mNotifications;
+};
+
+#endif // LL_LLNOTIFICATIONSLISTENER_H
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index fd981557047697b291af17e4791b04de1d723234..76ba53ec329e600084424a110695f7924edc709b 100755
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -27,7 +27,7 @@
 #include "linden_common.h"
 
 #include "lltabcontainer.h"
-
+#include "llviewereventrecorder.h"
 #include "llfocusmgr.h"
 #include "lllocalcliprect.h"
 #include "llrect.h"
@@ -578,6 +578,11 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
 			tab_button->setFocus(TRUE);
 		}
 	}
+	if (handled) {
+		// Note: May need to also capture local coords right here ?
+		LLViewerEventRecorder::instance().update_xui(getPathname( ));
+	}
+
 	return handled;
 }
 
@@ -629,30 +634,33 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
 	BOOL handled = FALSE;
 	BOOL has_scroll_arrows = (getMaxScrollPos() > 0)  && !getTabsHidden();
 
+	S32 local_x = x - getRect().mLeft;
+	S32 local_y = y - getRect().mBottom;
+
 	if (has_scroll_arrows)
 	{
 		if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
 		{
-			S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
-			S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
+			local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
+			local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
 			handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
 		}
 		else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x,	y))
 		{
-			S32	local_x	= x	- mJumpNextArrowBtn->getRect().mLeft;
-			S32	local_y	= y	- mJumpNextArrowBtn->getRect().mBottom;
+			local_x	= x	- mJumpNextArrowBtn->getRect().mLeft;
+			local_y	= y	- mJumpNextArrowBtn->getRect().mBottom;
 			handled = mJumpNextArrowBtn->handleMouseUp(local_x,	local_y, mask);
 		}
 		else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
 		{
-			S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
-			S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
+			local_x = x - mPrevArrowBtn->getRect().mLeft;
+			local_y = y - mPrevArrowBtn->getRect().mBottom;
 			handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
 		}
 		else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
 		{
-			S32 local_x = x - mNextArrowBtn->getRect().mLeft;
-			S32 local_y = y - mNextArrowBtn->getRect().mBottom;
+			local_x = x - mNextArrowBtn->getRect().mLeft;
+			local_y = y - mNextArrowBtn->getRect().mBottom;
 			handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
 		}
 	}
@@ -676,6 +684,10 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
 		}
 		gFocusMgr.setMouseCapture(NULL);
 	}
+	if (handled) {
+		// Note: may need to capture local coords here
+		LLViewerEventRecorder::instance().update_xui(getPathname( ));
+	}
 	return handled;
 }
 
@@ -1059,21 +1071,21 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
 		
 		if (mIsVertical)
 		{
-			p.name(std::string("vert tab button"));
-			p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
-			p.image_selected(mMiddleTabParams.tab_left_image_selected);
-			p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
+		  p.name("vtab_"+std::string(child->getName()));
+		  p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
+		  p.image_selected(mMiddleTabParams.tab_left_image_selected);
+		  p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
 		}
 		else
-		{
-			p.name(std::string(child->getName()) + " tab");
-			p.visible(false);
-			p.image_unselected(tab_img);
-			p.image_selected(tab_selected_img);
-			p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
-			// Try to squeeze in a bit more text
-			p.pad_left( mLabelPadLeft );
-			p.pad_right(2);
+		  { 
+		    p.name("htab_"+std::string(child->getName()));
+		    p.visible(false);
+		    p.image_unselected(tab_img);
+		    p.image_selected(tab_selected_img);
+		    p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
+		    // Try to squeeze in a bit more text
+		    p.pad_left( mLabelPadLeft );
+		    p.pad_right(2);
 		}
 		
 		// *TODO : It seems wrong not to use p in both cases considering the way p is initialized
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index b9c843e931c4aa657eec7a3f3bed2d127870b230..1722bf27bddcda5937d681f7ebff1d22b1bb2383 100755
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -29,7 +29,7 @@
 
 #define LLUICTRL_CPP
 #include "lluictrl.h"
-
+#include "llviewereventrecorder.h"
 #include "llfocusmgr.h"
 #include "llpanel.h"
 #include "lluictrlfactory.h"
@@ -308,22 +308,40 @@ void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask)
 //virtual 
 BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask)
 {
+
+	lldebugs << "LLUICtrl::handleMouseDown calling	LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << llendl;
+  
 	BOOL handled  = LLView::handleMouseDown(x,y,mask);
+	
 	if (mMouseDownSignal)
 	{
 		(*mMouseDownSignal)(this,x,y,mask);
 	}
+	lldebugs << "LLUICtrl::handleMousedown - handled is returning as: " << handled << "	  " << llendl;
+	
+	if (handled) {
+		LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
+	}
 	return handled;
 }
 
 //virtual
 BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask)
 {
+
+	lldebugs << "LLUICtrl::handleMouseUp calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << llendl;
+
 	BOOL handled  = LLView::handleMouseUp(x,y,mask);
+	if (handled) {
+		LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname()); 
+	}
 	if (mMouseUpSignal)
 	{
 		(*mMouseUpSignal)(this,x,y,mask);
 	}
+
+	lldebugs << "LLUICtrl::handleMouseUp - handled for xui " << getPathname() << "  -  is returning as: " << handled << "   " << llendl;
+
 	return handled;
 }
 
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 3613a40e2c6c8021fce9c8fb8997f31eef03eaf0..20015dca1af7295982a27d0f474b94f46a7698bc 100755
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -48,7 +48,9 @@
 #include "lluictrlfactory.h"
 #include "lltooltip.h"
 #include "llsdutil.h"
-
+#include "llsdserialize.h"
+#include "llviewereventrecorder.h"
+#include "llkeyboard.h"
 // for ui edit hack
 #include "llbutton.h"
 #include "lllineeditor.h"
@@ -642,13 +644,27 @@ void LLView::setVisible(BOOL visible)
 // virtual
 void LLView::handleVisibilityChange ( BOOL new_visibility )
 {
+	BOOL old_visibility;
 	BOOST_FOREACH(LLView* viewp, mChildList)
 	{
 		// only views that are themselves visible will have their overall visibility affected by their ancestors
-		if (viewp->getVisible())
+		old_visibility=viewp->getVisible();
+
+		if (old_visibility!=new_visibility)
+		{
+			LLViewerEventRecorder::instance().logVisibilityChange( viewp->getPathname(), viewp->getName(), new_visibility,"widget");
+		}
+
+		if (old_visibility)
 		{
 			viewp->handleVisibilityChange ( new_visibility );
 		}
+
+		// Consider changing returns to confirm success and know which widget grabbed it
+		// For now assume success and log at highest xui possible 
+		// NOTE we log actual state - which may differ if it somehow failed to set visibility
+		lldebugs << "LLView::handleVisibilityChange	 - now: " << getVisible()  << " xui: " << viewp->getPathname() << " name: " << viewp->getName() << llendl;
+		
 	}
 }
 
@@ -697,6 +713,7 @@ bool LLView::visibleEnabledAndContains(S32 local_x, S32 local_y)
 		&& getEnabled();
 }
 
+// This is NOT event recording related
 void LLView::logMouseEvent()
 {
 	if (sDebugMouseHandling)
@@ -743,7 +760,14 @@ LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDA
 		if ((viewp->*method)( local_x, local_y, extra )
 			|| (allow_mouse_block && viewp->blockMouseEvent( local_x, local_y )))
 		{
+			lldebugs << "LLView::childrenHandleMouseEvent calling updatemouseeventinfo - local_x|global x  "<< local_x << " " << x	<< "local/global y " << local_y << " " << y << llendl;
+			lldebugs << "LLView::childrenHandleMouseEvent  getPathname for viewp result: " << viewp->getPathname() << "for this view: " << getPathname() << llendl;
+
+			LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); 
+
+			// This is NOT event recording related
 			viewp->logMouseEvent();
+
 			return viewp;
 		}
 	}
@@ -766,6 +790,7 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
 		if (viewp->handleToolTip(local_x, local_y, mask) 
 			|| viewp->blockMouseEvent(local_x, local_y))
 		{
+			// This is NOT event recording related
 			viewp->logMouseEvent();
 			return viewp;
 		}
@@ -824,6 +849,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
 		if (viewp->handleHover(local_x, local_y, mask)
 			|| viewp->blockMouseEvent(local_x, local_y))
 		{
+			// This is NOT event recording related
 			viewp->logMouseEvent();
 			return viewp;
 		}
@@ -907,10 +933,12 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 
 		if (!handled)
 		{
+			// For event logging we don't care which widget handles it
+			// So we capture the key at the end of this function once we know if it was handled
 			handled = handleKeyHere( key, mask );
-			if (handled && LLView::sDebugKeys)
+			if (handled)
 			{
-				llinfos << "Key handled by " << getName() << llendl;
+				llwarns << "Key handled by " << getName() << llendl;
 			}
 		}
 	}
@@ -958,6 +986,11 @@ BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 		handled = mParentView->handleUnicodeChar(uni_char, FALSE);
 	}
 
+	if (handled)
+	{
+		LLViewerEventRecorder::instance().logKeyUnicodeEvent(uni_char);
+	}
+	
 	return handled;
 }
 
@@ -987,12 +1020,16 @@ BOOL LLView::hasMouseCapture()
 
 BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	return childrenHandleMouseUp( x, y, mask ) != NULL;
+	LLView* r = childrenHandleMouseUp( x, y, mask );
+
+	return (r!=NULL);
 }
 
 BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
 {
-	return childrenHandleMouseDown( x, y, mask ) != NULL;
+	LLView* r= childrenHandleMouseDown(x, y, mask );
+
+	return (r!=NULL);
 }
 
 BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
@@ -1065,7 +1102,7 @@ LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
 
 LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
 {
-	return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);
+	return	childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);
 }
 
 LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a352f621eb5aab413752a228db731e5ae4e560c1
--- /dev/null
+++ b/indra/llui/llviewereventrecorder.cpp
@@ -0,0 +1,296 @@
+/**
+ * @file llviewereventrecorder.cpp
+ * @brief Viewer event recording and playback support for mouse and keyboard events
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * 
+ * Copyright (c) 2013, 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 "llviewereventrecorder.h"
+#include "llui.h"
+#include "llleap.h"
+
+LLViewerEventRecorder::LLViewerEventRecorder() {
+
+  clear(UNDEFINED);
+
+  // Remove any previous event log file
+  std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old");
+  LLFile::remove(old_log_ui_events_to_llsd_file);
+  
+
+  mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd");
+  LLFile::rename(mLogFilename, old_log_ui_events_to_llsd_file);
+
+}
+
+
+bool LLViewerEventRecorder::displayViewerEventRecorderMenuItems() {
+  return LLUI::sSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems");
+}
+
+
+void LLViewerEventRecorder::setEventLoggingOn() {
+  if (! mLog.is_open()) {
+    mLog.open(mLogFilename, llofstream::out);
+  }
+  logEvents=true; 
+  lldebugs << "LLViewerEventRecorder::setEventLoggingOn event logging turned on" << llendl;
+}
+
+void LLViewerEventRecorder::setEventLoggingOff() {
+  logEvents=false;
+  mLog.flush();
+  mLog.close();
+  lldebugs << "LLViewerEventRecorder::setEventLoggingOff event logging turned off" << llendl;
+}
+
+
+ LLViewerEventRecorder::~LLViewerEventRecorder() {
+  if (mLog.is_open()) {
+      mLog.close();
+    }
+}
+
+void LLViewerEventRecorder::clear_xui() {
+  xui.clear();
+}
+
+void LLViewerEventRecorder::clear(S32 r) {
+
+  xui.clear();
+
+  local_x=r;
+  local_y=r;
+
+  global_x=r;
+  global_y=r;
+    
+
+}
+
+void LLViewerEventRecorder::setMouseLocalCoords(S32 x, S32 y) {
+  local_x=x;
+  local_y=y;
+}
+
+void LLViewerEventRecorder::setMouseGlobalCoords(S32 x, S32 y) {
+  global_x=x;
+  global_y=y;
+}
+
+void LLViewerEventRecorder::updateMouseEventInfo(S32 local_x, S32 local_y, S32 global_x, S32 global_y, std::string mName) {
+
+  LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), xui);
+  if (! target_view) {
+    lldebugs << "LLViewerEventRecorder::updateMouseEventInfo - xui path on file at moment is NOT valid - so DO NOT record these local coords" << llendl;
+    return;
+  }
+  lldebugs << "LLViewerEventRecorder::updateMouseEventInfo b4 updatemouseeventinfo - local_x|global x   "<< this->local_x << " " << this->global_x  << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;
+
+
+  if (this->local_x < 1 && this->local_y<1 && local_x && local_y) {
+    this->local_x=local_x;
+    this->local_y=local_y;
+  }
+  this->global_x=global_x;
+  this->global_y=global_y;
+
+  // ONLY record deepest xui path for hierarchy searches - or first/only xui for floaters/panels reached via mouse captor - and llmousehandler
+  if (mName!="" &&  mName!="/" && xui=="") { 
+    //	xui=std::string("/")+mName+xui; 
+    //xui=mName+xui; 
+    xui = mName; // TODO review confirm we never call with partial path - also cAN REMOVE CHECK FOR "" - ON OTHER HAND IT'S PRETTY HARMLESS
+  }
+
+  lldebugs << "LLViewerEventRecorder::updateMouseEventInfo after updatemouseeventinfo - local_x|global x   "<< this->local_x << " " << this->global_x  << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;
+}
+
+void LLViewerEventRecorder::logVisibilityChange(std::string xui, std::string name, BOOL visibility, std::string event_subtype) {
+
+  LLSD  event=LLSD::emptyMap();
+
+  event.insert("event",LLSD(std::string("visibility")));
+
+  if (visibility) {
+    event.insert("visibility",LLSD(true));
+  } else {
+    event.insert("visibility",LLSD(false));
+  }
+
+  if (event_subtype!="") {
+    event.insert("event_subtype", LLSD(event_subtype));
+  }
+
+  if(name!="") {
+    event.insert("name",LLSD(name));
+  }
+
+  if (xui!="") {
+    event.insert("path",LLSD(xui));
+  }
+
+  event.insert("timestamp",LLSD(LLDate::now().asString())); 
+  recordEvent(event);
+}
+
+
+std::string LLViewerEventRecorder::get_xui() {
+  return xui;
+}
+void LLViewerEventRecorder::update_xui(std::string xui) {
+  if (xui!="" && this->xui=="" ) {
+    lldebugs << "LLViewerEventRecorder::update_xui to " << xui << llendl;
+    this->xui=xui;
+  } else {
+    lldebugs << "LLViewerEventRecorder::update_xui called with empty string" << llendl;
+  }
+}
+
+void LLViewerEventRecorder::logKeyEvent(KEY key, MASK mask) {
+
+  // NOTE: Event recording only logs keydown events - the viewer itself hides keyup events at a fairly low level in the code and does not appear to care about them anywhere
+
+  LLSD event = LLSD::emptyMap();
+
+  event.insert("event",LLSD("type"));
+
+  // keysym ...or
+  // keycode...or
+  // char
+  event.insert("keysym",LLSD(LLKeyboard::stringFromKey(key)));
+
+  // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
+  // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
+  // break the test script and it would be useful to have more context to make these sorts of edits safer
+ 
+  // TODO  replace this with a call which extracts to an array of names of masks (just like vita expects during playback)
+  // This is looking more and more like an object is a good idea, for this part a handy method call to setMask(mask) would be nice :-)
+  // call the func - llkeyboard::llsdStringarrayFromMask
+
+  LLSD key_mask=LLSD::emptyArray();
+
+  if (mask & MASK_CONTROL)     { key_mask.append(LLSD("CTL")); }  // Mac command key - has code of 0x1  in llcommon/indra_contstants
+  if (mask & MASK_ALT)         { key_mask.append(LLSD("ALT")); }
+  if (mask & MASK_SHIFT)       { key_mask.append(LLSD("SHIFT")); }
+  if (mask & MASK_MAC_CONTROL) { key_mask.append(LLSD("MAC_CONTROL")); }
+
+  event.insert("mask",key_mask); 
+  event.insert("timestamp",LLSD(LLDate::now().asString())); 
+
+  // Although vita has keyDown and keyUp requests it does not have type as a high-level concept 
+  // (maybe it should) - instead it has a convenience method that generates the keydown and keyup events 
+  // Here  we will use  "type" as  our event type
+
+  lldebugs << "LLVIewerEventRecorder::logKeyEvent Serialized LLSD for event " << event.asString() << "\n" << llendl;
+
+
+  //lldebugs  << "[VITA] key_name: "  << LLKeyboard::stringFromKey(key) << "mask: "<< mask  << "handled by " << getName() << llendl;
+  lldebugs  << "LLVIewerEventRecorder::logKeyEvent  key_name: "  << LLKeyboard::stringFromKey(key) << "mask: "<< mask  << llendl;
+
+
+  recordEvent(event);
+
+}
+
+void LLViewerEventRecorder::playbackRecording() {
+
+  LLSD LeapCommand;
+
+  // ivita sets this on startup, it also sends commands to the viewer to make start, stop, and playback menu items visible in viewer
+  LeapCommand =LLUI::sSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand");
+  
+  lldebugs << "[VITA] launching playback - leap command is: " << LLSDXMLStreamer(LeapCommand) << llendl;
+  LLLeap::create("", LeapCommand, false); // exception=false
+  
+}
+
+
+void LLViewerEventRecorder::recordEvent(LLSD event) {
+  lldebugs << "LLViewerEventRecorder::recordEvent event written to log: " << LLSDXMLStreamer(event) << llendl;
+  mLog << event << std::endl;
+  
+}
+void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) {
+  if (! logEvents) return;
+
+  // Note: keyUp is not captured since the viewer seems to not care about keyUp events
+
+  LLSD event=LLSD::emptyMap();
+
+  event.insert("timestamp",LLSD(LLDate::now().asString()));
+
+  
+  // keysym ...or
+  // keycode...or
+  // char
+
+  lldebugs << "Wrapped in conversion to wstring " <<  wstring_to_utf8str(LLWString( 1, uni_char)) << "\n" << llendl;
+  
+  event.insert("char",
+	       LLSD(  wstring_to_utf8str(LLWString( 1,uni_char))  )
+	       ); 
+
+  // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
+  // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
+  // break the test script and it would be useful to have more context to make these sorts of edits safer
+
+  // TODO need to consider mask keys too? Doesn't seem possible - at least not easily at this point
+
+  event.insert("event",LLSD("keyDown")); 
+
+  lldebugs  << "[VITA] unicode key: " << uni_char   << llendl;
+  lldebugs  << "[VITA] dumpxml " << LLSDXMLStreamer(event) << "\n" << llendl;
+
+
+  recordEvent(event);
+
+}
+
+void LLViewerEventRecorder::logMouseEvent(std::string button_state,std::string button_name)
+{
+  if (! logEvents) return; 
+
+  LLSD  event=LLSD::emptyMap();
+
+  event.insert("event",LLSD(std::string("mouse"+ button_state)));
+  event.insert("button",LLSD(button_name));
+  if (xui!="") {
+    event.insert("path",LLSD(xui));
+  }
+
+  if (local_x>0 && local_y>0) {
+    event.insert("local_x",LLSD(local_x));
+    event.insert("local_y",LLSD(local_y));
+  }
+
+  if (global_x>0 && global_y>0) {
+    event.insert("global_x",LLSD(global_x));
+    event.insert("global_y",LLSD(global_y));
+  }
+  event.insert("timestamp",LLSD(LLDate::now().asString())); 
+  recordEvent(event);
+
+
+  clear(UNDEFINED);
+   
+
+}
diff --git a/indra/llui/llviewereventrecorder.h b/indra/llui/llviewereventrecorder.h
new file mode 100644
index 0000000000000000000000000000000000000000..72ca643ced027e09501844a374288c3c0d828565
--- /dev/null
+++ b/indra/llui/llviewereventrecorder.h
@@ -0,0 +1,103 @@
+/**
+ * @file llviewereventrecorder.h
+ * @brief Viewer event recording and playback support for mouse and keyboard events
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * 
+ * Copyright (c) 2013, 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_VIEWER_EVENT_RECORDER
+#define LL_VIEWER_EVENT_RECORDER
+
+
+#include "linden_common.h" 
+
+#include "lldir.h" 
+#include "llsd.h"  
+#include "llfile.h"
+#include "llvfile.h"
+#include "lldate.h"
+#include "llsdserialize.h"
+#include "llkeyboard.h"
+#include "llstring.h"
+
+#include <sstream>
+
+#include "llsingleton.h" // includes llerror which we need here so we can skip the include here
+
+class LLViewerEventRecorder : public LLSingleton<LLViewerEventRecorder>
+{
+
+ public:
+
+  LLViewerEventRecorder(); // TODO Protect constructor better if we can (not happy in private section) - could add a factory... - we are singleton
+  ~LLViewerEventRecorder();
+
+
+  void updateMouseEventInfo(S32 local_x,S32 local_y, S32 global_x, S32 global_y,  std::string mName);
+  void setMouseLocalCoords(S32 x,S32 y);
+  void setMouseGlobalCoords(S32 x,S32 y);
+
+  void logMouseEvent(std::string button_state, std::string button_name );
+  void logKeyEvent(KEY key, MASK mask);
+  void logKeyUnicodeEvent(llwchar uni_char);
+
+  void logVisibilityChange(std::string xui, std::string name, BOOL visibility, std::string event_subtype);
+
+  void clear_xui();
+  std::string get_xui();
+  void update_xui(std::string xui);
+
+  bool getLoggingStatus();
+  void setEventLoggingOn();
+  void setEventLoggingOff();
+
+  void playbackRecording();
+
+  bool displayViewerEventRecorderMenuItems();
+
+
+ protected:
+  // On if we wish to log events at the moment - toggle via Develop/Recorder submenu
+  bool logEvents;
+
+  std::string mLogFilename;
+  llofstream  mLog; 
+
+
+ private:
+
+  // Mouse event info 
+  S32 global_x;
+  S32 global_y;
+  S32 local_x;
+  S32 local_y;
+
+  // XUI path of UI element
+  std::string xui;
+
+  // Actually write the event out to llsd log file
+  void recordEvent(LLSD event);
+
+  void clear(S32 r); 
+
+  static const S32 UNDEFINED=-1;
+};
+#endif
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 56472e6b455aa9a302ff98775e5b0a08e08e79b4..d5b62bd3a71d17dc2c50f1811e17afc72cfc4d22 100755
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1300,6 +1300,8 @@ void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& ca
 	OSMessageBox(text, caption, type);
 }
 
+			// Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature 
+			// it is handled at a very low-level
 const char* cursorIDToName(int id)
 {
 	switch (id)
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index 16f22907872f01a7b3fbedc454716285145ee665..97fad7feb0031b4b912e71b426dc3cc33c77b96d 100755
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -391,7 +391,7 @@ LLControlVariable* LLControlGroup::declareControl(const std::string& name, eCont
 		}
 		else
 		{
-			llwarns << "Control named " << name << " already exists, ignoring new declaration." << llendl;
+			LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL;
 		}
  		return existing_control;
 	}
@@ -630,14 +630,14 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
 
 	if (!xml_controls.parseFile(filename))
 	{
-		llwarns << "Unable to open control file " << filename << llendl;
+		LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL;
 		return 0;
 	}
 
 	LLXmlTreeNode* rootp = xml_controls.getRoot();
 	if (!rootp || !rootp->hasAttribute("version"))
 	{
-		llwarns << "No valid settings header found in control file " << filename << llendl;
+		LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL;
 		return 0;
 	}
 
@@ -650,7 +650,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
 	// Check file version
 	if (version != CURRENT_VERSION)
 	{
-		llinfos << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << llendl;
+		LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL;
 		return 0;
 	}
 
@@ -668,7 +668,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
 			if (!name.empty())
 			{
 				//read in to end of line
-				llwarns << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << llendl;
+				LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL;
 			}
 			child_nodep = rootp->getNextChild();
 			continue;
@@ -822,7 +822,7 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
 		LLControlVariable* control = iter->second;
 		if (!control)
 		{
-			llwarns << "Tried to save invalid control: " << iter->first << llendl;
+			LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL;
 		}
 		else if( control->shouldSave(nondefault_only) )
 		{
@@ -838,12 +838,12 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
 	{
 		LLSDSerialize::toPrettyXML(settings, file);
 		file.close();
-		llinfos << "Saved to " << filename << llendl;
+		LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL;
 	}
 	else
 	{
         // This is a warning because sometime we want to use settings files which can't be written...
-		llwarns << "Unable to open settings file: " << filename << llendl;
+		LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL;
 		return 0;
 	}
 	return num_saved;
@@ -856,14 +856,14 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
 	infile.open(filename);
 	if(!infile.is_open())
 	{
-		llwarns << "Cannot find file " << filename << " to load." << llendl;
+		LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL;
 		return 0;
 	}
 
 	if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile))
 	{
 		infile.close();
-		llwarns << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << llendl;
+		LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL;
 		return loadFromFileLegacy(filename, TRUE, TYPE_STRING);
 	}
 
@@ -976,6 +976,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
 		++validitems;
 	}
 
+	LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL;
 	return validitems;
 }
 
@@ -1012,7 +1013,7 @@ void main()
 	BOOL_CONTROL baz;
 
 	U32 count = gGlobals.loadFromFile("controls.ini");
-	llinfos << "Loaded " << count << " controls" << llendl;
+	LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL;
 
 	// test insertion
 	foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f);
@@ -1273,19 +1274,19 @@ LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const st
 		LLColor4 color(sd);
 		if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
 		{
-			llwarns << "Color " << control_name << " red value out of range: " << color << llendl;
+			LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL;
 		}
 		else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
 		{
-			llwarns << "Color " << control_name << " green value out of range: " << color << llendl;
+			LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL;
 		}
 		else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
 		{
-			llwarns << "Color " << control_name << " blue value out of range: " << color << llendl;
+			LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL;
 		}
 		else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
 		{
-			llwarns << "Color " << control_name << " alpha value out of range: " << color << llendl;
+			LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL;
 		}
 
 		return LLColor4(sd);
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 458ec591dca66e148c582af5d1f98dcc76fbf5a4..41aac583d7661a270e4de4287efac459473dc1cd 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4941,6 +4941,16 @@
       <key>Value</key>
       <array />
     </map>
+    <key>LeapPlaybackEventsCommand</key>
+    <map>
+      <key>Comment</key>
+      <string>Command line to use leap to launch playback of event recordings</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>LLSD</string>
+      <key>Value</key>
+    </map>
     <key>LSLFindCaseInsensitivity</key>
         <map>
         <key>Comment</key>
@@ -10444,6 +10454,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>ShowEventRecorderMenuItems</key>
+    <map>
+      <key>Comment</key>
+      <string>Whether or not Event Recorder menu choices - Start / Stop event recording should appear in the (currently) Develop menu</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>ShowGestureButton</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5e8958d7d8d0796bbc3b0d3baacb6b88be90b9e1..539d186441030cd76bae280490ac785472205988 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -223,6 +223,10 @@
 #include "llmachineid.h"
 #include "llmainlooprepeater.h"
 
+
+#include "llviewereventrecorder.h"
+
+
 // *FIX: These extern globals should be cleaned up.
 // The globals either represent state/config/resource-storage of either 
 // this app, or another 'component' of the viewer. App globals should be 
@@ -696,6 +700,7 @@ LLAppViewer::LLAppViewer() :
 LLAppViewer::~LLAppViewer()
 {
 	delete mSettingsLocationList;
+	LLViewerEventRecorder::instance().~LLViewerEventRecorder();
 
 	LLLoginInstance::instance().setUpdaterService(0);
 	
@@ -2250,13 +2255,13 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
 
 		BOOST_FOREACH(const SettingsFile& file, group.files)
 		{
-			llinfos << "Attempting to load settings for the group " << file.name()
-			    << " - from location " << location_key << llendl;
+			LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name()
+			    << " - from location " << location_key << LL_ENDL;
 
 			LLControlGroup* settings_group = LLControlGroup::getInstance(file.name);
 			if(!settings_group)
 			{
-				llwarns << "No matching settings group for name " << file.name() << llendl;
+				LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL;
 				continue;
 			}
 
@@ -2285,7 +2290,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
 
 			if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent))
 			{	// success!
-				llinfos << "Loaded settings file " << full_settings_path << llendl;
+				LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL;
 			}
 			else
 			{	// failed to load
@@ -2299,7 +2304,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
 					// only complain if we actually have a filename at this point
 					if (!full_settings_path.empty())
 					{
-						llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
+						LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL;
 					}
 				}
 			}
@@ -2395,8 +2400,6 @@ bool LLAppViewer::initConfiguration()
 	gSavedSettings.setString("ClientSettingsFile", 
         gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
 
-	gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel());
-
 #ifndef	LL_RELEASE_FOR_DOWNLOAD
 	// provide developer build only overrides for these control variables that are not
 	// persisted to settings.xml
@@ -2460,8 +2463,8 @@ bool LLAppViewer::initConfiguration()
 			gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, 
 										   clp.getOption("settings")[0]);		
 		gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
-		llinfos	<< "Using command line specified settings filename: " 
-			<< user_settings_filename << llendl;
+		LL_INFOS("Settings")	<< "Using command line specified settings filename: " 
+			<< user_settings_filename << LL_ENDL;
 	}
 
 	// - load overrides from user_settings 
@@ -2477,8 +2480,8 @@ bool LLAppViewer::initConfiguration()
 	{
 		std::string session_settings_filename = clp.getOption("sessionsettings")[0];		
 		gSavedSettings.setString("SessionSettingsFile", session_settings_filename);
-		llinfos	<< "Using session settings filename: " 
-			<< session_settings_filename << llendl;
+		LL_INFOS("Settings")	<< "Using session settings filename: " 
+			<< session_settings_filename << LL_ENDL;
 	}
 	loadSettingsFromDirectory("Session");
 
@@ -2486,8 +2489,8 @@ bool LLAppViewer::initConfiguration()
 	{
 		std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0];		
 		gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename);
-		llinfos	<< "Using user session settings filename: " 
-			<< user_session_settings_filename << llendl;
+		LL_INFOS("Settings") << "Using user session settings filename: " 
+			<< user_session_settings_filename << LL_ENDL;
 
 	}
 	loadSettingsFromDirectory("UserSession");
@@ -2575,6 +2578,10 @@ bool LLAppViewer::initConfiguration()
         }
     }
 
+    if  (clp.hasOption("logevents")) {
+	LLViewerEventRecorder::instance().setEventLoggingOn();
+    }
+
 	std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel"));
 	if(! CmdLineChannel.empty())
     {
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 3cf3c739d942b27a3205027018ce8526bcae6491..80a80f42989bc155bbd758064a66005a5dafb346 100755
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -172,21 +172,20 @@ void ll_nvapi_init(NvDRSSessionHandle hSession)
 			nvapi_error(status);
 			return;
 		}
+
+        // (5) Now we apply (or save) our changes to the system
+        status = NvAPI_DRS_SaveSettings(hSession);
+        if (status != NVAPI_OK) 
+        {
+            nvapi_error(status);
+            return;
+        }
 	}
 	else if (status != NVAPI_OK)
 	{
 		nvapi_error(status);
 		return;
 	}
-
-	
-
-	// (5) Now we apply (or save) our changes to the system
-	status = NvAPI_DRS_SaveSettings(hSession);
-	if (status != NVAPI_OK) 
-	{
-		nvapi_error(status);
-	}
 }
 
 //#define DEBUGGING_SEH_FILTER 1
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index b513a52ff7c56c360c3f04af6edfdd900bb16201..70cc48f12b8fddef99008917a2e341295eee5e3f 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -73,6 +73,8 @@
 #include "llcallingcard.h"
 #include "llslurl.h"			// IDEVO
 #include "llsidepanelinventory.h"
+#include "llavatarname.h"
+#include "llagentui.h"
 
 // static
 void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name)
@@ -391,6 +393,72 @@ void LLAvatarActions::pay(const LLUUID& id)
 	}
 }
 
+void LLAvatarActions::teleport_request_callback(const LLSD& notification, const LLSD& response)
+{
+	S32 option;
+	if (response.isInteger()) 
+	{
+		option = response.asInteger();
+	}
+	else
+	{
+		option = LLNotificationsUtil::getSelectedOption(notification, response);
+	}
+
+	if (0 == option)
+	{
+		LLMessageSystem* msg = gMessageSystem;
+
+		msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
+		msg->nextBlockFast(_PREHASH_AgentData);
+		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+		msg->nextBlockFast(_PREHASH_MessageBlock);
+		msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
+		msg->addUUIDFast(_PREHASH_ToAgentID, notification["substitutions"]["uuid"] );
+		msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
+		msg->addU8Fast(_PREHASH_Dialog, IM_TELEPORT_REQUEST);
+		msg->addUUIDFast(_PREHASH_ID, LLUUID::null);
+		msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
+
+		std::string name;
+		LLAgentUI::buildFullname(name);
+
+		msg->addStringFast(_PREHASH_FromAgentName, name);
+		msg->addStringFast(_PREHASH_Message, response["message"]);
+		msg->addU32Fast(_PREHASH_ParentEstateID, 0);
+		msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
+		msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
+
+		gMessageSystem->addBinaryDataFast(
+				_PREHASH_BinaryBucket,
+				EMPTY_BINARY_BUCKET,
+				EMPTY_BINARY_BUCKET_SIZE);
+
+		gAgent.sendReliableMessage();
+	}
+}
+
+// static
+void LLAvatarActions::teleportRequest(const LLUUID& id)
+{
+	LLSD notification;
+	notification["uuid"] = id;
+	LLAvatarName av_name;
+	if (!LLAvatarNameCache::get(id, &av_name))
+	{
+		// unlikely ... they just picked this name from somewhere...
+		LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id));
+		return; // reinvoke this when the name resolves
+	}
+	notification["NAME"] = av_name.getCompleteName();
+
+	LLSD payload;
+
+	LLNotificationsUtil::add("TeleportRequestPrompt", notification, payload, teleport_request_callback);
+}
+
 // static
 void LLAvatarActions::kick(const LLUUID& id)
 {
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 6e1198cd09885b89f2b3d6c268f74558b410eef4..403414558e22943fa06bd92ac8beaf18db31b0a0 100755
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -110,6 +110,12 @@ class LLAvatarActions
 	 */
 	static void pay(const LLUUID& id);
 
+	/**
+	 * Request teleport from other avatar
+	 */
+	static void teleportRequest(const LLUUID& id);
+	static void teleport_request_callback(const LLSD& notification, const LLSD& response);
+
 	/**
 	 * Share items with the avatar.
 	 */
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 88884042d4d0c482f65a1c1e5c1d84d3e483c6fb..131aea9da3890ce3ce24df217ab59b9dd5135dcd 100755
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -220,18 +220,25 @@ void LLNotificationChiclet::setCounter(S32 counter)
 
 bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNotificationPtr notification )
 {
-	if (notification->getName() == "ScriptDialog")
+	bool displayNotification;
+	if (   (notification->getName() == "ScriptDialog") // special case for scripts
+		// if there is no toast window for the notification, filter it
+		|| (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
+		)
 	{
-		return false;
+		displayNotification = false;
 	}
-
-	if( !(notification->canLogToIM() && notification->hasFormElements())
-		&& (!notification->getPayload().has("give_inventory_notification")
-			|| notification->getPayload()["give_inventory_notification"]))
+	else if( !(notification->canLogToIM() && notification->hasFormElements())
+			&& (!notification->getPayload().has("give_inventory_notification")
+				|| notification->getPayload()["give_inventory_notification"]))
 	{
-		return true;
+		displayNotification = true;
 	}
-	return false;
+	else
+	{
+		displayNotification = false;
+	}
+	return displayNotification;
 }
 
 //////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp
index 5ab108b39fbc3279120a71c3933d9bdcd2c44ca2..44212298cf5cb73ac73f525ca3dc9aa9e54d1691 100755
--- a/indra/newview/llconversationloglist.cpp
+++ b/indra/newview/llconversationloglist.cpp
@@ -313,6 +313,10 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata)
 	{
 		LLAvatarActions::offerTeleport(selected_conversation_participant_id);
 	}
+	else if ("request_teleport" == command_name)
+	{
+		LLAvatarActions::teleportRequest(selected_conversation_participant_id);
+	}
 	else if("add_friend" == command_name)
 	{
 		if (!LLAvatarActions::isFriend(selected_conversation_participant_id))
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 192a594c9dfae0e5da55269df1902fd7bb980191..affa24f78cb0c641b77c15295939f48291a031da 100755
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -132,6 +132,7 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32
 		items.push_back(std::string("view_profile"));
 		items.push_back(std::string("im"));
 		items.push_back(std::string("offer_teleport"));
+		items.push_back(std::string("request_teleport"));
 		items.push_back(std::string("voice_call"));
 		items.push_back(std::string("chat_history"));
 		items.push_back(std::string("separator_chat_history"));
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 21bc747648540ef5b4775861961537695f04d42c..90b4490e1dcac0fb893fb6405e7cedecaf98d3d7 100755
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -1080,6 +1080,10 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec
 		{
 			LLAvatarActions::offerTeleport(selectedIDS);
 		}
+		else if ("request_teleport" == command)
+		{
+			LLAvatarActions::teleportRequest(selectedIDS.front());
+		}
 		else if ("voice_call" == command)
 		{
 			LLAvatarActions::startCall(userID);
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 6ef4d8717d75cecba8399d52959ab1dd2c7731a4..8f20d4e0823ad7854f00294d9aeac3b77c70cb23 100755
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -2097,7 +2097,6 @@ void LLPanelLandOptions::refresh()
 // virtual
 void LLPanelLandOptions::draw()
 {
-	refreshSearch();	// Is this necessary?  JC
 	LLPanel::draw();
 }
 
@@ -2111,9 +2110,8 @@ void LLPanelLandOptions::refreshSearch()
 		mCheckShowDirectory->set(FALSE);
 		mCheckShowDirectory->setEnabled(FALSE);
 
-		// *TODO:Translate
-		const std::string& none_string = LLParcel::getCategoryUIString(LLParcel::C_NONE);
-		mCategoryCombo->setSimple(none_string);
+		const std::string& none_string = LLParcel::getCategoryString(LLParcel::C_NONE);
+		mCategoryCombo->setValue(none_string);
 		mCategoryCombo->setEnabled(FALSE);
 		return;
 	}
@@ -2140,10 +2138,9 @@ void LLPanelLandOptions::refreshSearch()
 	mCheckShowDirectory	->set(show_directory);
 
 	// Set by string in case the order in UI doesn't match the order by index.
-	// *TODO:Translate
 	LLParcel::ECategory cat = parcel->getCategory();
-	const std::string& category_string = LLParcel::getCategoryUIString(cat);
-	mCategoryCombo->setSimple(category_string);
+	const std::string& category_string = LLParcel::getCategoryString(cat);
+	mCategoryCombo->setValue(category_string);
 
 	std::string tooltip;
 	bool enable_show_directory = false;
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 50c013a49dfa3b479cf8adffada194f5b1a1a2b3..66bf49331b7e06200d56d9909f0ee6941eabf251 100755
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -1734,7 +1734,7 @@ void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)
 			LLSD args;
 			args["NUM_ADDED"] = llformat("%d",ids.size());
 			args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
-			args["LIST_TYPE"] = "Allowed Residents";
+			args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeAllowedAgents");
 			args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS);
 			LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
 			delete change_info;
@@ -1750,7 +1750,7 @@ void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)
 			LLSD args;
 			args["NUM_ADDED"] = llformat("%d",ids.size());
 			args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
-			args["LIST_TYPE"] = "Banned Residents";
+			args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeBannedAgents");
 			args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS);
 			LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
 			delete change_info;
@@ -2815,9 +2815,10 @@ bool LLDispatchSetEstateAccess::operator()(
 		}
 
 
-		std::string msg = llformat("Banned residents: (%d, max %d)",
-									totalBannedAgents,
-									ESTATE_MAX_ACCESS_IDS);
+		LLStringUtil::format_map_t args;
+		args["[BANNEDAGENTS]"] = llformat("%d", totalBannedAgents);
+		args["[MAXBANNED]"] = llformat("%d", ESTATE_MAX_ACCESS_IDS);
+		std::string msg = LLTrans::getString("RegionInfoBannedResidents", args);
 		panel->getChild<LLUICtrl>("ban_resident_label")->setValue(LLSD(msg));
 
 		if (banned_agent_name_list)
@@ -2837,9 +2838,10 @@ bool LLDispatchSetEstateAccess::operator()(
 
 	if (access_flags & ESTATE_ACCESS_MANAGERS)
 	{
-		std::string msg = llformat("Estate Managers: (%d, max %d)",
-									num_estate_managers,
-									ESTATE_MAX_MANAGERS);
+		LLStringUtil::format_map_t args;
+		args["[ESTATEMANAGERS]"] = llformat("%d", num_estate_managers);
+		args["[MAXMANAGERS]"] = llformat("%d", ESTATE_MAX_MANAGERS);
+		std::string msg = LLTrans::getString("RegionInfoEstateManagers", args);
 		panel->getChild<LLUICtrl>("estate_manager_label")->setValue(LLSD(msg));
 
 		LLNameListCtrl* estate_manager_name_list =
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index e4fc469bb7d489108aeaada6cc88745c566f132f..80ef506272c31337945466c4433ec18d9cf42929 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -4739,6 +4739,16 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act
 			LLAvatarActions::offerTeleport(item->getCreatorUUID());
 		}
 	}
+	else if ("request_lure" == action)
+	{
+		LLViewerInventoryItem *item = getItem();
+		if (item && (item->getCreatorUUID() != gAgent.getID()) &&
+			(!item->getCreatorUUID().isNull()))
+		{
+			LLAvatarActions::teleportRequest(item->getCreatorUUID());
+		}
+	}
+
 	else LLItemBridge::performAction(model, action);
 }
 
@@ -4825,6 +4835,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 		items.push_back(std::string("Send Instant Message Separator"));
 		items.push_back(std::string("Send Instant Message"));
 		items.push_back(std::string("Offer Teleport..."));
+		items.push_back(std::string("Request Teleport..."));
 		items.push_back(std::string("Conference Chat"));
 
 		if (!good_card)
@@ -4834,6 +4845,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 		if (!good_card || !user_online)
 		{
 			disabled_items.push_back(std::string("Offer Teleport..."));
+			disabled_items.push_back(std::string("Request Teleport..."));
 			disabled_items.push_back(std::string("Conference Chat"));
 		}
 	}
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index dea90b90426f1ee72360ecf39418b8a2667e9e04..08b5eaedbbe9d5d899324b90a8ab3fc00de98081 100755
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -343,8 +343,11 @@ void LLNetMap::draw()
 		// Draw avatars
 		for (U32 i = 0; i < avatar_ids.size(); i++)
 		{
-			pos_map = globalPosToView(positions[i]);
 			LLUUID uuid = avatar_ids[i];
+			// Skip self, we'll draw it later
+			if (uuid == gAgent.getID()) continue;
+
+			pos_map = globalPosToView(positions[i]);
 
 			bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
 
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index 28549629227020abe86c389c68e6f86a3ce6956e..a3b15931c673f349ebcd7e3619c1caeca8830f0f 100755
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -90,7 +90,7 @@ bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
 	{
 		LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID());
 	}
-	else
+	else if (notification->canShowToast())
 	{
 		LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
 
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 313056f06acf209266013e8f9466e63ecb08c25d..6979ae06e05187d27cd0d38c092c32ed0207d0b7 100755
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -75,6 +75,7 @@ LLContextMenu* PeopleContextMenu::createMenu()
 		registrar.add("Avatar.Pay",				boost::bind(&LLAvatarActions::pay,						id));
 		registrar.add("Avatar.BlockUnblock",	boost::bind(&LLAvatarActions::toggleBlock,				id));
 		registrar.add("Avatar.InviteToGroup",	boost::bind(&LLAvatarActions::inviteToGroup,			id));
+		registrar.add("Avatar.TeleportRequest",	boost::bind(&PeopleContextMenu::requestTeleport,		this));
 		registrar.add("Avatar.Calllog",			boost::bind(&LLAvatarActions::viewChatHistory,			id));
 
 		enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2));
@@ -126,6 +127,7 @@ void PeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
 		items.push_back(std::string("view_profile"));
 		items.push_back(std::string("im"));
 		items.push_back(std::string("offer_teleport"));
+		items.push_back(std::string("request_teleport"));
 		items.push_back(std::string("voice_call"));
 		items.push_back(std::string("chat_history"));
 		items.push_back(std::string("separator_chat_history"));
@@ -256,6 +258,13 @@ bool PeopleContextMenu::checkContextMenuItem(const LLSD& userdata)
 	return false;
 }
 
+void PeopleContextMenu::requestTeleport()
+{
+	// boost::bind cannot recognize overloaded method LLAvatarActions::teleportRequest(),
+	// so we have to use a wrapper.
+	LLAvatarActions::teleportRequest(mUUIDs.front());
+}
+
 void PeopleContextMenu::offerTeleport()
 {
 	// boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(),
@@ -285,6 +294,7 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
 		items.push_back(std::string("view_profile"));
 		items.push_back(std::string("im"));
 		items.push_back(std::string("offer_teleport"));
+		items.push_back(std::string("request_teleport"));
 		items.push_back(std::string("voice_call"));
 		items.push_back(std::string("chat_history"));
 		items.push_back(std::string("separator_chat_history"));
diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h
index 5367eca0d39375b6b5505bead33f8d894030c9a1..945382ebc51e7f2cde6dd050c73b3fcd56ec1938 100755
--- a/indra/newview/llpanelpeoplemenus.h
+++ b/indra/newview/llpanelpeoplemenus.h
@@ -47,6 +47,7 @@ class PeopleContextMenu : public LLListContextMenu
 	bool enableContextMenuItem(const LLSD& userdata);
 	bool checkContextMenuItem(const LLSD& userdata);
 	void offerTeleport();
+	void requestTeleport();
 };
 
 /**
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 928d26646b2b777f5e45213117ddb425f6f324da..c4d5450e2bd90bd40c812645b24df057f3bb297a 100755
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -207,6 +207,7 @@ LLSD _basic_constraints_ext(X509* cert)
 			}
 		}
 
+		BASIC_CONSTRAINTS_free( bs );
 	}
 	return result;
 }
@@ -268,6 +269,8 @@ LLSD _ext_key_usage_ext(X509* cert)
 				ASN1_OBJECT_free(usage);
 			}
 		}
+
+		EXTENDED_KEY_USAGE_free( eku );
 	}
 	return result;
 }
@@ -280,6 +283,8 @@ LLSD _subject_key_identifier_ext(X509 *cert)
 	if(skeyid)
 	{
 		result = cert_string_from_octet_string(skeyid);
+
+		ASN1_OCTET_STRING_free( skeyid );
 	}
 	return result;
 }
@@ -300,6 +305,9 @@ LLSD _authority_key_identifier_ext(X509* cert)
 		{
 			result[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL] = cert_string_from_asn1_integer(akeyid->serial);
 		}	
+
+
+		AUTHORITY_KEYID_free( akeyid );
 	}
 	
 	// we ignore the issuer name in the authority key identifier, we check the issue name via
@@ -1049,6 +1057,8 @@ void LLBasicCertificateStore::validate(int validation_policy,
 		throw LLInvalidCertificate((*current_cert));			
 	}
 	std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH);
+	X509_free( cert_x509 );
+	cert_x509 = NULL;
 	t_cert_cache::iterator cache_entry = mTrustedCertCache.find(sha1_hash);
 	if(cache_entry != mTrustedCertCache.end())
 	{
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index 1a3add2bfb1ded9b61ee32f466ef8d31939d24f9..626d69aca44387fbf369f05c6fb0c1ef9e881dab 100755
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -118,6 +118,11 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id)
 	}
 }
 
+ LLPanel * LLSysWellWindow::findItemByID(const LLUUID& id)
+{
+       return mMessageList->getItemByValue(id);
+}
+
 //---------------------------------------------------------------------------------
 //---------------------------------------------------------------------------------
 void LLSysWellWindow::initChannel() 
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index cc5c057d8b395c8dd5ef17e260668eb12df72026..71b41476f53f62fa0b54afa5b814bcd22c023ff4 100755
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -55,6 +55,7 @@ class LLSysWellWindow : public LLTransientDockableFloater
 
 	// Operating with items
 	void removeItemByID(const LLUUID& id);
+	LLPanel * findItemByID(const LLUUID& id);
 
 	// Operating with outfit
 	virtual void setVisible(BOOL visible);
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index 2fbb3bf8688f2c968dfbdbb9dfb3c74809e046e3..aa9de076b87f46adee7fa15fae458fe0b90528eb 100755
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -687,7 +687,10 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL
 	{
 		// it is sufficient to set this value once per call to handlekey
 		// without clearing it, as it is only used in the subsequent call to scanKey
-		mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask);
+		mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); 
+		// mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
+		// NOT whether some UI shortcut wishes to handle the keypress
+	  
 	}
 	return mKeyHandledByUI[translated_key];
 }
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index c096ef3f54588d5d50539bda51061bc242e2ca2a..ac2940fcfccf6652f21f620ec7cda53563118182 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -40,6 +40,7 @@
 #include "llinventorypanel.h"
 #include "llnotifications.h"
 #include "llnotificationsutil.h"
+#include "llviewereventrecorder.h"
 
 // newview includes
 #include "llagent.h"
@@ -1954,6 +1955,43 @@ class LLAdvancedDropPacket : public view_listener_t
 };
 
 
+////////////////////
+// EVENT Recorder //
+///////////////////
+
+
+class LLAdvancedViewerEventRecorder : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		std::string command = userdata.asString();
+		if ("start playback" == command)
+		{
+			llinfos << "Event Playback starting" << llendl;
+			LLViewerEventRecorder::instance().playbackRecording();
+			llinfos << "Event Playback completed" << llendl;
+		}
+		else if ("stop playback" == command)
+		{
+			// Future
+		}
+		else if ("start recording" == command)
+		{
+			LLViewerEventRecorder::instance().setEventLoggingOn();
+			llinfos << "Event recording started" << llendl;
+		}
+		else if ("stop recording" == command)
+		{
+			LLViewerEventRecorder::instance().setEventLoggingOff();
+			llinfos << "Event recording stopped" << llendl;
+		} 
+
+		return true;
+	}		
+};
+
+
+
 
 /////////////////
 // AGENT PILOT //
@@ -8422,6 +8460,8 @@ void initialize_menus()
 	// Don't prepend MenuName.Foo because these can be used in any menu.
 	enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
 
+	enable.add("displayViewerEventRecorderMenuItems",boost::bind(&LLViewerEventRecorder::displayViewerEventRecorderMenuItems,&LLViewerEventRecorder::instance()));
+
 	view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
 
 	enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed));
@@ -8680,6 +8720,7 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
 	view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
 	view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop");
+	view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder");
 
 	// Advanced > Debugging
 	view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index c38af1f990b733346b83ed6fa2773d79cfaa770e..ab9ea5618e87230640d52639022b1ef55c8c154f 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2220,7 +2220,7 @@ static std::string clean_name_from_im(const std::string& name, EInstantMessage t
 	case IM_LURE_ACCEPTED:
 	case IM_LURE_DECLINED:
 	case IM_GODLIKE_LURE_USER:
-	case IM_YET_TO_BE_USED:
+	case IM_TELEPORT_REQUEST:
 	case IM_GROUP_ELECTION_DEPRECATED:
 	//IM_GOTO_URL
 	//IM_FROM_TASK_AS_ALERT
@@ -2988,6 +2988,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 		break;
 		
 	case IM_LURE_USER:
+	case IM_TELEPORT_REQUEST:
 		{
 			if (is_muted)
 			{ 
@@ -3010,7 +3011,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				bool canUserAccessDstRegion = true;
 				bool doesUserRequireMaturityIncrease = false;
 
-				if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access))
+				// Do not parse the (empty) lure bucket for TELEPORT_REQUEST
+				if (IM_TELEPORT_REQUEST != dialog && parse_lure_bucket(region_info, region_handle, pos, look_at, region_access))
 				{
 					region_access_str = LLViewerRegion::accessToString(region_access);
 					region_access_icn = LLViewerRegion::getAccessIcon(region_access);
@@ -3082,12 +3084,22 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				}
 				else
 				{
-			    LLNotification::Params params("TeleportOffered");
+					LLNotification::Params params;
+					if (IM_LURE_USER == dialog)
+					{
+						params.name = "TeleportOffered";
+						params.functor.name = "TeleportOffered";
+					}
+					else if (IM_TELEPORT_REQUEST == dialog)
+					{
+						params.name = "TeleportRequest";
+						params.functor.name = "TeleportRequest";
+					}
+
 			    params.substitutions = args;
 			    params.payload = payload;
 			    LLPostponedNotification::add<LLPostponedOfferNotification>(	params, from_id, false);
 			}
-
 			}
 		}
 		break;
@@ -6873,6 +6885,51 @@ void send_group_notice(const LLUUID& group_id,
 			bin_bucket_size);
 }
 
+void send_lures(const LLSD& notification, const LLSD& response)
+{
+	std::string text = response["message"].asString();
+	LLSLURL slurl;
+	LLAgentUI::buildSLURL(slurl);
+	text.append("\r\n").append(slurl.getSLURLString());
+
+	LLMessageSystem* msg = gMessageSystem;
+	msg->newMessageFast(_PREHASH_StartLure);
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	msg->nextBlockFast(_PREHASH_Info);
+	msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in.
+	msg->addStringFast(_PREHASH_Message, text);
+	for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray();
+		it != notification["payload"]["ids"].endArray();
+		++it)
+	{
+		LLUUID target_id = it->asUUID();
+
+		msg->nextBlockFast(_PREHASH_TargetData);
+		msg->addUUIDFast(_PREHASH_TargetID, target_id);
+
+		// Record the offer.
+		{
+			std::string target_name;
+			gCacheName->getFullName(target_id, target_name);  // for im log filenames
+			LLSD args;
+			args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
+	
+			LLSD payload;
+				
+			//*TODO please rewrite all keys to the same case, lower or upper
+			payload["from_id"] = target_id;
+			payload["SUPPRESS_TOAST"] = true;
+			LLNotificationsUtil::add("TeleportOfferSent", args, payload);
+
+			// Add the recepient to the recent people list.
+			LLRecentPeople::instance().add(target_id);
+		}
+	}
+	gAgent.sendReliableMessage();
+}
+
 bool handle_lure_callback(const LLSD& notification, const LLSD& response)
 {
 	static const unsigned OFFER_RECIPIENT_LIMIT = 250;
@@ -6886,50 +6943,12 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
 		LLNotificationsUtil::add("TooManyTeleportOffers", args);
 		return false;
 	}
-	
-	std::string text = response["message"].asString();
-	LLSLURL slurl;
-	LLAgentUI::buildSLURL(slurl);
-	text.append("\r\n").append(slurl.getSLURLString());
+
 	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 
 	if(0 == option)
 	{
-		LLMessageSystem* msg = gMessageSystem;
-		msg->newMessageFast(_PREHASH_StartLure);
-		msg->nextBlockFast(_PREHASH_AgentData);
-		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-		msg->nextBlockFast(_PREHASH_Info);
-		msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in.
-		msg->addStringFast(_PREHASH_Message, text);
-		for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray();
-			it != notification["payload"]["ids"].endArray();
-			++it)
-		{
-			LLUUID target_id = it->asUUID();
-
-			msg->nextBlockFast(_PREHASH_TargetData);
-			msg->addUUIDFast(_PREHASH_TargetID, target_id);
-
-			// Record the offer.
-			{
-				std::string target_name;
-				gCacheName->getFullName(target_id, target_name);  // for im log filenames
-				LLSD args;
-				args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
-	
-				LLSD payload;
-				
-				//*TODO please rewrite all keys to the same case, lower or upper
-				payload["from_id"] = target_id;
-				LLNotificationsUtil::add("TeleportOfferSent", args, payload);
-
-				// Add the recepient to the recent people list.
-				LLRecentPeople::instance().add(target_id);
-			}
-		}
-		gAgent.sendReliableMessage();
+		send_lures(notification, response);
 	}
 
 	return false;
@@ -6969,6 +6988,58 @@ void handle_lure(const uuid_vec_t& ids)
 	}
 }
 
+bool teleport_request_callback(const LLSD& notification, const LLSD& response)
+{
+	LLUUID from_id = notification["payload"]["from_id"].asUUID();
+	if(from_id.isNull())
+	{
+		llwarns << "from_id is NULL" << llendl;
+		return false;
+	}
+
+	std::string from_name;
+	gCacheName->getFullName(from_id, from_name);
+
+	if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name))
+	{
+		return false;
+	}
+
+	S32 option = 0;
+	if (response.isInteger()) 
+	{
+		option = response.asInteger();
+	}
+	else
+	{
+		option = LLNotificationsUtil::getSelectedOption(notification, response);
+	}
+
+	switch(option)
+	{
+	// Yes
+	case 0:
+		{
+			LLSD dummy_notification;
+			dummy_notification["payload"]["ids"][0] = from_id;
+
+			LLSD dummy_response;
+			dummy_response["message"] = response["message"];
+
+			send_lures(dummy_notification, dummy_response);
+		}
+		break;
+
+	// No
+	case 1:
+	default:
+		break;
+	}
+
+	return false;
+}
+
+static LLNotificationFunctorRegistration teleport_request_callback_reg("TeleportRequest", teleport_request_callback);
 
 void send_improved_im(const LLUUID& to_id,
 							const std::string& name,
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 66615657d82a723d433c96b4e1fbeb1c688a5686..b4e287c446775197f2900e400f6b8e35f8d50df1 100755
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -954,15 +954,17 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 			objectp = *idle_iter;
 			llassert(objectp->isActive());
 			objectp->idleUpdate(agent, world, frame_time);
-
-			}
+		}
 
 		//update flexible objects
 		LLVolumeImplFlexible::updateClass();
 
 		//update animated textures
-		LLViewerTextureAnim::updateClass();
-			}
+		if (gAnimateTextures)
+		{
+			LLViewerTextureAnim::updateClass();
+		}
+	}
 
 
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index bf11bce3da2860993963675ff1e4a92853e6183c..ff7642a773a4cc7a670fc78e21be57b10017a9ee 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -198,6 +198,8 @@
 #include "llagentui.h"
 #include "llwearablelist.h"
 
+#include "llviewereventrecorder.h"
+
 #include "llnotifications.h"
 #include "llnotificationsutil.h"
 #include "llnotificationmanager.h"
@@ -954,27 +956,18 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window,  LLCoordGL pos, MASK
 			{
 				llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
 			}
-			return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
-		}
 
-		// Topmost view gets a chance before the hierarchy
-		//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
-		//if (top_ctrl)
-		//{
-		//	S32 local_x, local_y;
-		//	top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
-		//		if (top_ctrl->pointInView(local_x, local_y))
-		//		{
-		//			return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down)	;
-		//		}
-		//		else
-		//		{
-		//		if (down)
-		//		{
-		//			gFocusMgr.setTopCtrl(NULL);
-		//		}
-		//	}
-		//}
+			BOOL r = mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down); 
+			if (r) {
+
+				lldebugs << "LLViewerWindow::handleAnyMouseClick viewer with mousecaptor calling updatemouseeventinfo - local_x|global x  "<< local_x << " " << x  << "local/global y " << local_y << " " << y << llendl;
+
+				LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
+				LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname)); 
+
+			}
+			return r;
+		}
 
 		// Mark the click as handled and return if we aren't within the root view to avoid spurious bugs
 		if( !mRootView->pointInView(x, y) )
@@ -982,27 +975,44 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window,  LLCoordGL pos, MASK
 			return TRUE;
 		}
 		// Give the UI views a chance to process the click
-		if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
+
+		BOOL r= mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ;
+		if (r) 
 		{
+
+			lldebugs << "LLViewerWindow::handleAnyMouseClick calling updatemouseeventinfo - global x  "<< " " << x	<< "global y " << y	 << "buttonstate: " << buttonstatestr << " buttonname " << buttonname << llendl;
+
+			LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
+
+			// Clear local coords - this was a click on root window so these are not needed
+			// By not including them, this allows the test skeleton generation tool to be smarter when generating code
+			// the code generator can be smarter because when local coords are present it can try the xui path with local coords
+			// and fallback to global coordinates only if needed. 
+			// The drawback to this approach is sometimes a valid xui path will appear to work fine, but NOT interact with the UI element
+			// (VITA support not implemented yet or not visible to VITA due to widget further up xui path not being visible to VITA)
+			// For this reason it's best to provide hints where possible here by leaving out local coordinates
+			LLViewerEventRecorder::instance().setMouseLocalCoords(-1,-1);
+			LLViewerEventRecorder::instance().logMouseEvent(buttonstatestr,buttonname); 
+
 			if (LLView::sDebugMouseHandling)
 			{
-				llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
-			}
+				llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLViewerEventRecorder::instance().get_xui()	<< llendl;
+			} 
 			return TRUE;
-		}
-		else if (LLView::sDebugMouseHandling)
-		{
-			llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
-		}
+		} else if (LLView::sDebugMouseHandling)
+			{
+				llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
+			}
 	}
 
 	// Do not allow tool manager to handle mouseclicks if we have disconnected	
 	if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
 	{
+		LLViewerEventRecorder::instance().clear_xui(); 
 		return TRUE;
 	}
-	
 
+	
 	// If we got this far on a down-click, it wasn't handled.
 	// Up-clicks, though, are always handled as far as the OS is concerned.
 	BOOL default_rtn = !down;
@@ -1373,7 +1383,8 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 {
 	LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
-	return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
+	gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
+	return; // Be clear this function returns nothing
 }
 
 
@@ -2519,6 +2530,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 		||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE))
 		||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)))
 	{
+		lldebugs << "LLviewerWindow::handleKey handle nav keys for nav" << llendl;
+		LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 		return TRUE;
 	}
 
@@ -2533,12 +2546,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 			&& keyboard_focus 
 			&& keyboard_focus->handleKey(key,mask,FALSE))
 		{
+			LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 			return TRUE;
 		}
 
 		if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
 			||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
 		{
+			LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 			return TRUE;
 		}
 	}
@@ -2548,6 +2563,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	// if nothing has focus, go to first or last UI element as appropriate
 	if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL))
 	{
+		llwarns << "LLviewerWindow::handleKey give floaters first chance at tab key " << llendl;
 		if (gMenuHolder) gMenuHolder->hideMenus();
 
 		// if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
@@ -2562,11 +2578,13 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 		{
 			mRootView->focusNextRoot();
 		}
+		LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 		return TRUE;
 	}
 	// hidden edit menu for cut/copy/paste
 	if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
 	{
+		LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 		return TRUE;
 	}
 
@@ -2606,18 +2624,27 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 
 		if (keyboard_focus->handleKey(key, mask, FALSE))
 		{
+
+			lldebugs << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned true" << llendl;
+			LLViewerEventRecorder::instance().logKeyEvent(key,mask); 
 			return TRUE;
+		} else {
+			lldebugs << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned FALSE" << llendl;
 		}
 	}
 
 	if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
 	{
+		lldebugs << "LLviewerWindow::handleKey toolbar handling?" << llendl;
+		LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 		return TRUE;
 	}
 
 	// Try for a new-format gesture
 	if (LLGestureMgr::instance().triggerGesture(key, mask))
 	{
+		lldebugs << "LLviewerWindow::handleKey new gesture feature" << llendl;
+		LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 		return TRUE;
 	}
 
@@ -2625,6 +2652,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	// don't pass it down to the menus.
 	if (gGestureList.trigger(key, mask))
 	{
+		lldebugs << "LLviewerWindow::handleKey check gesture trigger" << llendl;
+		LLViewerEventRecorder::instance().logKeyEvent(key,mask);
 		return TRUE;
 	}
 
@@ -2673,7 +2702,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 	// HACK: Numeric keypad <enter> on Mac is Unicode 3
 	// HACK: Control-M on Windows is Unicode 13
 	if ((uni_char == 13 && mask != MASK_CONTROL)
-		|| (uni_char == 3 && mask == MASK_NONE))
+	    || (uni_char == 3 && mask == MASK_NONE) )
 	{
 		if (mask != MASK_ALT)
 		{
@@ -2696,14 +2725,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 			return TRUE;
 		}
 
-		//// Topmost view gets a chance before the hierarchy
-		//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
-		//if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
-		//{
-		//	return TRUE;
-		//}
-
-		return TRUE;
+        return TRUE;
 	}
 
 	return FALSE;
@@ -2712,8 +2734,6 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 
 void LLViewerWindow::handleScrollWheel(S32 clicks)
 {
-	LLView::sMouseHandlerMessage.clear();
-
 	LLUI::resetMouseIdleTimer();
 	
 	LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp
index 28f959eb7190eda9641da4cd38b3c71ec72691f3..a8e06511d725d64d1b865e476322516df3c00490 100755
--- a/indra/newview/llwindowlistener.cpp
+++ b/indra/newview/llwindowlistener.cpp
@@ -265,7 +265,9 @@ void LLWindowListener::getPaths(LLSD const & request)
 void LLWindowListener::keyDown(LLSD const & evt)
 {
 	Response response(LLSD(), evt);
-	
+	KEY key = getKEY(evt);
+	MASK mask = getMask(evt);
+
 	if (evt.has("path"))
 	{
 		std::string path(evt["path"]);
@@ -280,8 +282,6 @@ void LLWindowListener::keyDown(LLSD const & evt)
 			response.setResponse(target_view->getInfo());
 			
 			gFocusMgr.setKeyboardFocus(target_view);
-			KEY key = getKEY(evt);
-			MASK mask = getMask(evt);
 			gViewerKeyboard.handleKey(key, mask, false);
 			if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
 		}
@@ -294,7 +294,8 @@ void LLWindowListener::keyDown(LLSD const & evt)
 	}
 	else 
 	{
-		mKbGetter()->handleTranslatedKeyDown(getKEY(evt), getMask(evt));
+		gViewerKeyboard.handleKey(key, mask, false); 
+		if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
 	}
 }
 
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index 5fa380e0e3a920e8ef6a726a4d5b196e089c38d0..bfae142812f7e97fd690d500648903aea3961032 100755
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -522,6 +522,17 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID&
 
 			tooltip_fmt.setArg("[AREA]",  llformat("%d", extra));
 			tooltip_fmt.setArg("[PRICE]", llformat("%d", extra2));
+
+			// Check for division by zero
+			if (extra != 0)
+			{
+				tooltip_fmt.setArg("[SQMPRICE]", llformat("%.1f", (F32)extra2 / (F32)extra));
+			}
+			else
+			{
+				tooltip_fmt.setArg("[SQMPRICE]",  LLTrans::getString("Unknown"));
+			}
+
 			new_item.setTooltip(tooltip_fmt.getString());
 
 			if (type == MAP_ITEM_LAND_FOR_SALE)
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index 793a6e6fa1ef6687508c6b3311fa7745af5a5392..a660e812ccf0bb966d61d34711af1928bc6abbd8 100755
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -1365,7 +1365,7 @@ Only large parcels can be listed in search.
                 <combo_box.item
                  label="Any Category"
                  name="item0"
-                 value="any" />
+                 value="none" />
                 <combo_box.item
                  label="Linden Location"
                  name="item1"
diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml
index b3d28788da19817eec2ba77ab4b84e82fabcef0b..31b1d091eef1be5d8e80b57883ab7695790ec6bc 100755
--- a/indra/newview/skins/default/xui/en/menu_conversation.xml
+++ b/indra/newview/skins/default/xui/en/menu_conversation.xml
@@ -52,6 +52,13 @@
         <on_click function="Avatar.DoToSelected" parameter="offer_teleport"/>
         <on_enable function="Avatar.EnableItem" parameter="can_offer_teleport"/>
     </menu_item_call>
+    <menu_item_call
+     label="Request teleport"
+     layout="topleft"
+     name="request_teleport">
+        <on_click function="Avatar.DoToSelected" parameter="request_teleport"/>
+        <on_enable function="Avatar.EnableItem" parameter="can_offer_teleport"/>
+    </menu_item_call>
     <menu_item_call
      label="Voice call"
      layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_conversation_log_gear.xml b/indra/newview/skins/default/xui/en/menu_conversation_log_gear.xml
index 8796b87955fb99aa096cebd76fec0bf38118fed6..a1a3afbf6820d2786a55f5dd920ac82fef5f5696 100755
--- a/indra/newview/skins/default/xui/en/menu_conversation_log_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_conversation_log_gear.xml
@@ -56,6 +56,16 @@
       function="Calllog.Enable"
       parameter="can_offer_teleport"/>
     </menu_item_call>
+    <menu_item_call
+    label="Request Teleport"
+    name="request_teleport">
+      <on_click
+       function="Calllog.Action"
+       parameter="request_teleport"/>
+      <on_enable
+      function="Calllog.Enable"
+      parameter="can_offer_teleport"/>
+    </menu_item_call>
     <menu_item_separator />
     <menu_item_call
      label="Add Friend"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 13dc0b941ad36df6026eea6e2e02b26792f60206..512205ba43c3de94448cb835189110039612fe57 100755
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -590,6 +590,14 @@
          function="Inventory.DoToSelected"
          parameter="lure" />
     </menu_item_call>
+    <menu_item_call
+     label="Request Teleport..."
+     layout="topleft"
+     name="Request Teleport...">
+        <menu_item_call.on_click
+        function="Inventory.DoToSelected"
+        parameter="request_lure" />
+    </menu_item_call>
     <menu_item_call
      label="Start Conference Chat"
      layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby.xml b/indra/newview/skins/default/xui/en/menu_people_nearby.xml
index 3abb5f7bc8ca3a8a142da8c254d20a47e0de3475..f12226ebeb48964ce71848a398bcecbd2e42394a 100755
--- a/indra/newview/skins/default/xui/en/menu_people_nearby.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_nearby.xml
@@ -28,6 +28,15 @@
       function="Avatar.EnableItem"
       parameter="can_offer_teleport"/>
     </menu_item_call>
+    <menu_item_call
+    label="Request Teleport"
+    name="request_teleport">
+      <menu_item_call.on_click
+       function="Avatar.TeleportRequest"/>
+      <menu_item_call.on_enable
+      function="Avatar.EnableItem"
+      parameter="can_offer_teleport"/>
+    </menu_item_call>
     <menu_item_call
      label="Voice call"
      layout="topleft"
@@ -134,5 +143,4 @@
          function="Avatar.EnableItem"
          parameter="can_block" />
     </menu_item_check>
-    <menu_item_separator />
 </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 a131d4b8e0ece2b83fa1d94a69df1fff29fef20c..da3ea9bd4c33224c4b22c06e0d69f62f2a10926a 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2955,6 +2955,34 @@
          label="Recorder"
          name="Recorder"
          tear_off="true">
+            <menu_item_call visible="false"
+             label="Start event recording"
+             name="Start event recording">
+	      <menu_item_call.on_visible
+		 function="displayViewerEventRecorderMenuItems" />
+                <menu_item_call.on_click
+                 function="Advanced.EventRecorder"
+                 parameter="start recording" />
+            </menu_item_call>
+            <menu_item_call visible="false"
+             label="Stop event recording"
+             name="Stop event recording">
+	      <menu_item_call.on_visible
+		 function="displayViewerEventRecorderMenuItems" />
+                <menu_item_call.on_click
+                 function="Advanced.EventRecorder"
+                 parameter="stop recording" />
+            </menu_item_call>
+            <menu_item_call visible="false"
+             label="Playback event recording"
+             name="Playback event recording">
+	      <menu_item_call.on_visible
+		 function="displayViewerEventRecorderMenuItems" />
+                <menu_item_call.on_click
+                 function="Advanced.EventRecorder"
+                 parameter="start playback" />
+            </menu_item_call>
+
             <menu_item_call
              label="Start Playback"
              name="Start Playback">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index dff8335efcab640a2bdc1cc67b6c7974f07e3dda..e7c89db06907e31966b1eab3297c69c85208a2bc 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -4069,6 +4069,27 @@ Join me in [REGION]
     </form>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="TeleportRequestPrompt"
+   type="alertmodal">
+Request a teleport to [NAME] with the following message
+    <tag>confirm</tag>
+    <form name="form">
+      <input name="message" type="text">
+
+      </input>
+      <button
+       default="true"
+       index="0"
+       name="OK"
+       text="OK"/>
+      <button
+       index="1"
+       name="Cancel"
+       text="Cancel"/>
+    </form>
+  </notification>
   <notification
    icon="alertmodal.tga"
    name="TooManyTeleportOffers"
@@ -6644,7 +6665,7 @@ Your object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; has given you th
    sound="UISndNewIncomingIMSession">
 [NAME_SLURL] has offered to teleport you to their location:
 
-“[MESSAGE]”
+"[MESSAGE]”
 &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt; - [MATURITY_STR]
     <tag>confirm</tag>
     <form name="form">
@@ -6709,6 +6730,27 @@ However, this region contains content accessible to adults only.
 	Teleport offer sent to [TO_NAME]
   </notification>
 
+  <notification
+   icon="notify.tga"
+   name="TeleportRequest"
+   log_to_im="true"
+   type="offer">
+[NAME_SLURL] is requesting to be teleported to your location.
+[MESSAGE]
+
+Offer a teleport?
+    <tag>confirm</tag>
+    <form name="form">
+      <button
+       index="0"
+       name="Yes"
+       text="Yes"/>
+      <button
+       index="1"
+       name="No"
+       text="No"/>
+    </form>
+  </notification>
 
   <notification
    icon="notify.tga"
@@ -6757,7 +6799,6 @@ However, this region contains content accessible to adults only.
    icon="notify.tga"
    name="FriendshipOffered"
    log_to_im="true"   
-   show_toast="false"   
    type="notify">
     <tag>friendship</tag>
 	You have offered friendship to [TO_NAME]
@@ -6807,7 +6848,6 @@ However, this region contains content accessible to adults only.
    icon="notify.tga"
    name="FriendshipAcceptedByMe"
    log_to_im="true"   
-   show_toast="false"
    type="notify">
     <tag>friendship</tag>
 Friendship offer accepted.
@@ -6817,7 +6857,6 @@ Friendship offer accepted.
    icon="notify.tga"
    name="FriendshipDeclinedByMe"
    log_to_im="true"   
-   show_toast="false"   
    type="notify">
     <tag>friendship</tag>
 Friendship offer declined.
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index dd2a0c6627aa9405c16037c4247eecc69a19114f..064ece6e4be5e9ae81c79a67d39d72498dbb1c35 100755
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -113,7 +113,7 @@
      image_pressed="Pause_Press"
      image_pressed_selected="Play_Press"
      is_toggle="true"
-     left_pad="15"
+     left_pad="5"
      top="1"
      name="media_toggle_btn"
      tool_tip="Start/Stop All Media (Music, Video, Web pages)"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 5c23ffa1dfab04dfcfa40b0619ea11805eb38c43..4d7daa1b516aa63e1d9a9992832578ca4fd78350 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -387,7 +387,7 @@ Please try logging in again in a minute.</string>
 	<!-- world map -->
 	<string name="texture_loading">Loading...</string>
 	<string name="worldmap_offline">Offline</string>
-	<string name="worldmap_item_tooltip_format">[AREA] m² L$[PRICE]</string>
+	<string name="worldmap_item_tooltip_format">[AREA] m² L$[PRICE] ([SQMPRICE] L$/m²)</string>
 	<string name="worldmap_results_none_found">None found.</string>
 
 	<!-- animations uploading status codes -->
@@ -2472,7 +2472,11 @@ Drag folders to this area and click "Send to Marketplace" to list them for sale
 		all estates that you manage for [OWNER]
 	</string>
 	<string name="RegionInfoAllowedResidents">Allowed Residents: ([ALLOWEDAGENTS], max [MAXACCESS])</string>
-	<string name="RegionInfoAllowedGroups">Allowed groups: ([ALLOWEDGROUPS], max [MAXACCESS])</string>
+	<string name="RegionInfoAllowedGroups">Allowed Groups: ([ALLOWEDGROUPS], max [MAXACCESS])</string>
+	<string name="RegionInfoEstateManagers">Estate Managers: ([ESTATEMANAGERS], max [MAXMANAGERS])</string>
+	<string name="RegionInfoBannedResidents">Banned Residents: ([BANNEDAGENTS], max [MAXBANNED])</string>
+	<string name="RegionInfoListTypeAllowedAgents">Allowed Residents</string>
+	<string name="RegionInfoListTypeBannedAgents">Banned Residents</string>
 
 	<!-- script limits floater -->
 	<string name="ScriptLimitsParcelScriptMemory">Parcel Script Memory</string>
diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp
index d6e06e5316adf502f3cbd418f8c22394d5f5f115..dc8ff2f64476517cbbb573556a1ff6141739cdb9 100755
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -79,7 +79,6 @@ void LLUpdateChecker::checkVersion(std::string const & urlBase,
 //-----------------------------------------------------------------------------
 
 
-const char * LLUpdateChecker::Implementation::sLegacyProtocolVersion = "v1.0";
 const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.1";
 
 
@@ -150,40 +149,11 @@ void LLUpdateChecker::Implementation::completed(U32 status,
 			server_error += content["error_text"].asString();
 		}
 
-		if (status == 404)
-		{
-			if (mProtocol == sProtocolVersion)
-			{
-				mProtocol = sLegacyProtocolVersion;
-				std::string retryUrl = buildUrl(mUrlBase, mChannel, mVersion, mPlatform, mPlatformVersion, mUniqueId, mWillingToTest);
-
-				LL_WARNS("UpdaterService")
-					<< "update response using " << sProtocolVersion
-					<< " was HTTP 404 (" << server_error
-					<< "); retry with legacy protocol " << mProtocol
-					<< "\n at " << retryUrl
-					<< LL_ENDL;
-	
-				mHttpClient.get(retryUrl, this);
-			}
-			else
-			{
-				LL_WARNS("UpdaterService")
-					<< "update response using " << sLegacyProtocolVersion
-					<< " was 404 (" << server_error
-					<< "); request failed"
-					<< LL_ENDL;
-				mClient.error(reason);
-			}
-		}
-		else
-		{
-			LL_WARNS("UpdaterService") << "response error " << status
-									   << " " << reason
-									   << " (" << server_error << ")"
-									   << LL_ENDL;
-			mClient.error(reason);
-		}
+		LL_WARNS("UpdaterService") << "response error " << status
+								   << " " << reason
+								   << " (" << server_error << ")"
+								   << LL_ENDL;
+		mClient.error(reason);
 	}
 	else
 	{
@@ -213,11 +183,8 @@ std::string LLUpdateChecker::Implementation::buildUrl(std::string const & urlBas
 	path.append(channel);
 	path.append(version);
 	path.append(platform);
-	if (mProtocol != sLegacyProtocolVersion)
-	{
-		path.append(platform_version);
-		path.append(willing_to_test ? "testok" : "testno");
-		path.append((char*)uniqueid);
-	}
+	path.append(platform_version);
+	path.append(willing_to_test ? "testok" : "testno");
+	path.append((char*)uniqueid);
 	return LLURI::buildHTTP(urlBase, path).asString();
 }