diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000000000000000000000000000000000000..eeb6d4499676516aae36c0c289854ae7165a8817
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,45 @@
+syntax: glob
+
+*.pyc
+*~
+.*.swp
+LICENSES
+indra/.distcc
+indra/build-darwin-*
+indra/build-vc[0-9]*
+indra/lib/mono/1.0/*.dll
+indra/lib/mono/indra/*.dll
+indra/lib/mono/indra/*.exe
+indra/lib/mono/indra/*.pdb
+indra/lib/python/eventlet/
+indra/llwindow/glh/glh_linear.h
+indra/newview/app_settings/mozilla
+indra/newview/app_settings/mozilla-runtime-*
+indra/newview/app_settings/mozilla_debug
+indra/newview/app_settings/static_*.db2
+indra/newview/browser_profile
+indra/newview/character
+indra/newview/fmod.dll
+indra/newview/mozilla-theme
+indra/newview/mozilla-universal-darwin.tgz
+indra/newview/res-sdl
+indra/newview/skins
+indra/newview/vivox-runtime
+indra/server-linux-*
+indra/test/linden_file.dat
+indra/test_apps/llmediatest/dependencies/i686-win32
+indra/test_apps/terrain_mule/*.dll
+indra/viewer-linux-*
+indra/web/doc/asset-upload/plugins/lsl_compiler/lslc
+indra/web/doc/asset-upload/plugins/verify-notecard
+indra/web/doc/asset-upload/plugins/verify-texture
+installed.xml
+libraries
+tarfile_tmp
+^indra/lib/python/mulib.*
+^web/locale.*
+^web/secondlife.com.*
+^web/config.*
+^indra/web/dataservice/locale.*
+^indra/web/dataservice/lib/shared/vault.*
+^indra/web/dataservice/vendor.*
diff --git a/etc/message.xml b/etc/message.xml
index d2ba9843e4f9fe31198e19f54249b2f4cef9b40d..da08e12aa1bb84a4615fb96994ef49c92b312962 100644
--- a/etc/message.xml
+++ b/etc/message.xml
@@ -669,11 +669,14 @@
 			<key>FetchLib</key>
 			<boolean>true</boolean>
 
-            <key>ObjectMedia</key>
-            <boolean>false</boolean>
+			<key>UploadBakedTexture</key>
+			<boolean>true</boolean>
+			
+			<key>ObjectMedia</key>
+            		<boolean>false</boolean>
                   
-            <key>ObjectMediaNavigate</key>
-            <boolean>false</boolean>
+            		<key>ObjectMediaNavigate</key>
+            		<boolean>false</boolean>
                   
       </map>
 
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 9418dbf271fb21563c5bb3438c62e5ce2c27b6cf..261c0b17e2361a9ac700336e2273322d13441aea 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -66,6 +66,7 @@ if (VIEWER)
   add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
   add_subdirectory(${LIBS_OPEN_PREFIX}llui)
   add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml)
+  add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
 
   # viewer media plugins
   add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 173e650961d179e6066d346e1bfe07da6df08a37..db5495091e5b826eb14cf5433d6ecf2b16d3d650 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -182,11 +182,17 @@ endif (LINUX)
 
 
 if (DARWIN)
-  add_definitions(-DLL_DARWIN=1)
+  # NOTE (per http://lists.apple.com/archives/darwin-dev/2008/Jan/msg00232.html):
+  # > Why the bus error? What am I doing wrong? 
+  # This is a known issue where getcontext(3) is writing past the end of the
+  # ucontext_t struct when _XOPEN_SOURCE is not defined (rdar://problem/5578699 ).
+  # As a workaround, define _XOPEN_SOURCE before including ucontext.h.
+  add_definitions(-DLL_DARWIN=1 -D_XOPEN_SOURCE)
   set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first")
   set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-branch")
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch")
+  set(DARWIN_extra_cstar_flags "-mlong-branch")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags}")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  ${DARWIN_extra_cstar_flags}")
   # NOTE: it's critical that the optimization flag is put in front.
   # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
@@ -195,13 +201,13 @@ endif (DARWIN)
 
 
 if (LINUX OR DARWIN)
-  set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual")
+  set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
 
   if (NOT GCC_DISABLE_FATAL_WARNINGS)
     set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
   endif (NOT GCC_DISABLE_FATAL_WARNINGS)
 
-  set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder")
+  set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
 
   set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
   set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index 0755aeee035d00bb135ad1c47172d964c29ab9d4..f4706dd4f2713ddb1e410da8d76342a13726ecd8 100644
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -13,26 +13,38 @@ if (STANDALONE)
 else (STANDALONE)
   use_prebuilt_binary(apr_suite)
   if (WINDOWS)
+    if (LLCOMMON_LINK_SHARED)
+      set(APR_selector "lib")
+    else (LLCOMMON_LINK_SHARED)
+      set(APR_selector "")
+    endif (LLCOMMON_LINK_SHARED)
     set(APR_LIBRARIES 
-      debug ${ARCH_PREBUILT_DIRS_DEBUG}/apr-1.lib
-      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apr-1.lib
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}apr-1.lib
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apr-1.lib
       )
     set(APRICONV_LIBRARIES 
-      debug ${ARCH_PREBUILT_DIRS_DEBUG}/apriconv-1.lib
-      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apriconv-1.lib
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}apriconv-1.lib
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apriconv-1.lib
       )
     set(APRUTIL_LIBRARIES 
-      debug ${ARCH_PREBUILT_DIRS_DEBUG}/aprutil-1.lib ${APRICONV_LIBRARIES}
-      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib ${APRICONV_LIBRARIES}
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}aprutil-1.lib ${APRICONV_LIBRARIES}
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}aprutil-1.lib ${APRICONV_LIBRARIES}
       )
   elseif (DARWIN)
+    if (LLCOMMON_LINK_SHARED)
+      set(APR_selector     "0.3.7.dylib")
+      set(APRUTIL_selector "0.3.8.dylib")
+    else (LLCOMMON_LINK_SHARED)
+      set(APR_selector     "a")
+      set(APRUTIL_selector "a")
+    endif (LLCOMMON_LINK_SHARED)
     set(APR_LIBRARIES 
-      debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.a
-      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.a
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.${APR_selector}
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.${APR_selector}
       )
     set(APRUTIL_LIBRARIES 
-      debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.a
-      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.a
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.${APRUTIL_selector}
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.${APRUTIL_selector}
       )
     set(APRICONV_LIBRARIES iconv)
   else (WINDOWS)
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 0578ae95ffa7edc027d74c6ef0bab0ba48b0ee3d..efe9ad74d3fe5b11ecf5e3634bd916fbb946a660 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -15,7 +15,7 @@ else (STANDALONE)
   set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 
   if (WINDOWS)
-    set(BOOST_VERSION 1_34_1)
+    set(BOOST_VERSION 1_39)
     if (MSVC71)
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
           optimized libboost_program_options-vc71-mt-s-${BOOST_VERSION}
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 3ce393b659174a57f736aae1d2f00a0ea84945d1..4563b59ad2b5d1fff9e92af864fbae909742ce8b 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -53,6 +53,7 @@ set(cmake_SOURCE_FILES
     LLPrimitive.cmake
     LLRender.cmake
     LLScene.cmake
+    LLTestCommand.cmake
     LLUI.cmake
     LLVFS.cmake
     LLWindow.cmake
@@ -69,7 +70,6 @@ set(cmake_SOURCE_FILES
     PNG.cmake
     Python.cmake
     Prebuilt.cmake
-    RunBuildTest.cmake
     TemplateCheck.cmake
     Tut.cmake
     UI.cmake
diff --git a/indra/cmake/Externals.cmake b/indra/cmake/Externals.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..26f3b5604937a781490838532276b2e67717e8d1
--- /dev/null
+++ b/indra/cmake/Externals.cmake
@@ -0,0 +1,34 @@
+# -*- cmake -*-
+
+include(Python)
+include(FindSVN)
+
+macro (use_svn_external _binary _path _url _rev)
+  if (NOT STANDALONE)
+    if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
+      if(SVN_FOUND)
+        if(DEBUG_EXTERNALS)
+          message("cd ${_path} && ${SVN_EXECUTABLE} checkout -r ${_rev} ${_url} ${_binary}")
+        endif(DEBUG_EXTERNALS)
+        execute_process(COMMAND ${SVN_EXECUTABLE}
+          checkout
+          -r ${_rev}
+          ${_url}
+          ${_binary}
+          WORKING_DIRECTORY ${_path}
+          RESULT_VARIABLE ${_binary}_installed
+          )
+      else(SVN_FOUND)
+        message(FATAL_ERROR "Failed to find SVN_EXECUTABLE")
+      endif(SVN_FOUND)
+      file(WRITE ${CMAKE_BINARY_DIR}/temp/${_binary}_installed "${${_binary}_installed}")
+    else(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
+      set(${_binary}_installed 0)
+    endif(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
+    if(NOT ${_binary}_installed EQUAL 0)
+      message(FATAL_ERROR
+              "Failed to download or unpack prebuilt '${_binary}'."
+              " Process returned ${${_binary}_installed}.")
+    endif (NOT ${_binary}_installed EQUAL 0)
+  endif (NOT STANDALONE)
+endmacro (use_svn_external _binary _path _url _rev)
diff --git a/indra/cmake/FindMono.cmake b/indra/cmake/FindMono.cmake
index c36d7259e895595624eb6dfae881969c586a45d6..d956c48656a51db6a691688e6fcafff91f432560 100644
--- a/indra/cmake/FindMono.cmake
+++ b/indra/cmake/FindMono.cmake
@@ -42,7 +42,7 @@ FIND_PROGRAM (GACUTIL_EXECUTABLE gacutil
              /usr/local/bin
 )
 FIND_PROGRAM (ILASM_EXECUTABLE
-             ilasm
+             NAMES ilasm.bat ilasm
              NO_DEFAULT_PATH
              PATHS "$ENV{PROGRAMFILES}/Mono-1.9.1/bin" "$ENV{PROGRAMFILES}/Mono-1.2.6/bin" /bin /usr/bin /usr/local/bin
 )
diff --git a/indra/cmake/FindSVN.cmake b/indra/cmake/FindSVN.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..3322be4ca9213bffcae36da3922d4ef8e539ecd1
--- /dev/null
+++ b/indra/cmake/FindSVN.cmake
@@ -0,0 +1,34 @@
+# -*- cmake -*-
+#
+# Find the svn executable for exporting old svn:externals.
+#
+# Input variables:
+#   SVN_FIND_REQUIRED - set this if configuration should fail without scp
+#
+# Output variables:
+#
+#   SVN_FOUND - set if svn was found
+#   SVN_EXECUTABLE - path to svn executable
+#   SVN_BATCH_FLAG - how to put svn into batch mode
+
+
+SET(SVN_EXECUTABLE)
+FIND_PROGRAM(SVN_EXECUTABLE NAMES svn svn.exe)
+
+IF (SVN_EXECUTABLE)
+  SET(SVN_FOUND ON)
+ELSE (SVN_EXECUTABLE)
+  SET(SVN_FOUND OFF)
+ENDIF (SVN_EXECUTABLE)
+
+IF (SVN_FOUND)
+  GET_FILENAME_COMPONENT(_svn_name ${SVN_EXECUTABLE} NAME_WE)
+  SET(SVN_BATCH_FLAG --non-interactive)
+ELSE (SVN_FOUND)
+  IF (SVN_FIND_REQUIRED)
+    MESSAGE(FATAL_ERROR "Could not find svn executable")
+  ENDIF (SVN_FIND_REQUIRED)
+ENDIF (SVN_FOUND)
+
+MARK_AS_ADVANCED(SVN_EXECUTABLE SVN_FOUND SVN_BATCH_FLAG)
+
diff --git a/indra/cmake/GoogleMock.cmake b/indra/cmake/GoogleMock.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..ca5a8034ba442082c5881ec4c046ebe4b7a777e9
--- /dev/null
+++ b/indra/cmake/GoogleMock.cmake
@@ -0,0 +1,27 @@
+# -*- cmake -*-
+include(Prebuilt)
+include(Linking)
+
+use_prebuilt_binary(googlemock)
+
+set(GOOGLEMOCK_INCLUDE_DIRS 
+    ${LIBS_PREBUILT_DIR}/include)
+
+if (LINUX)
+    set(GOOGLEMOCK_LIBRARIES 
+        gmock  
+        gtest)
+elseif(WINDOWS)
+    set(GOOGLEMOCK_LIBRARIES 
+        gmock)
+    set(GOOGLEMOCK_INCLUDE_DIRS 
+        ${LIBS_PREBUILT_DIR}/include
+        ${LIBS_PREBUILT_DIR}/include/gmock
+        ${LIBS_PREBUILT_DIR}/include/gmock/boost/tr1/tr1)
+elseif(DARWIN)
+    set(GOOGLEMOCK_LIBRARIES
+        gmock
+        gtest)
+endif(LINUX)
+
+
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 008b277960b7304e7943b475e130068464a443ca..d8f64199cf63abdcd92219d6b21a6e8e282a1a52 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -1,4 +1,6 @@
 # -*- cmake -*-
+include(LLTestCommand)
+include(GoogleMock)
 
 MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
   # Given a project name and a list of sourcefiles (with optional properties on each),
@@ -13,6 +15,8 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
   #
   # WARNING: do NOT modify this code without working with poppy -
   # there is another branch that will conflict heavily with any changes here.
+INCLUDE(GoogleMock)
+
 
   IF(LL_TEST_VERBOSE)
     MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}")
@@ -41,8 +45,10 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
     ${LLMATH_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
     ${LIBS_OPEN_DIR}/test
+    ${GOOGLEMOCK_INCLUDE_DIRS}
     )
   SET(alltest_LIBRARIES
+    ${GOOGLEMOCK_LIBRARIES}
     ${PTHREAD_LIBRARY}
     ${WINDOWS_LIBRARIES}
     )
@@ -51,6 +57,11 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
     ${CMAKE_SOURCE_DIR}/test/test.h
     )
 
+  # Use the default flags
+  if (LINUX)
+    SET(CMAKE_EXE_LINKER_FLAGS "")
+  endif (LINUX)
+
   # start the source test executable definitions
   SET(${project}_TEST_OUTPUT "")
   FOREACH (source ${sources})
@@ -93,9 +104,9 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
       MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}")
     ENDIF(LL_TEST_VERBOSE)
 
+
     # Setup target
     ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES})
-
     #
     # Per-codefile additional / external project dep and lib dep property extraction
     #
@@ -123,16 +134,20 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
     GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION)
     SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt)
     SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR})
-    # daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19
+
+	# daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19
     IF(LL_TEST_VERBOSE)
       MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd  = ${TEST_CMD}")
     ENDIF(LL_TEST_VERBOSE)
-    SET(TEST_SCRIPT_CMD 
-      ${CMAKE_COMMAND} 
-      -DLD_LIBRARY_PATH=${ARCH_PREBUILT_DIRS}:/usr/lib
-      -DTEST_CMD:STRING="${TEST_CMD}" 
-      -P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake
-      )
+    
+    IF(WINDOWS)
+      set(LD_LIBRARY_PATH ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR})
+    ELSE(WINDOWS)
+      set(LD_LIBRARY_PATH ${ARCH_PREBUILT_DIRS}:${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}:/usr/lib)
+    ENDIF(WINDOWS)
+
+    LL_TEST_COMMAND("${LD_LIBRARY_PATH}" ${TEST_CMD})
+    SET(TEST_SCRIPT_CMD ${LL_TEST_COMMAND_value})
     IF(LL_TEST_VERBOSE)
       MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script  = ${TEST_SCRIPT_CMD}")
     ENDIF(LL_TEST_VERBOSE)
@@ -176,6 +191,7 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
 
   SET(libraries
     ${library_dependencies}
+    ${GOOGLEMOCK_LIBRARIES}
     ${PTHREAD_LIBRARY}
     )
 
@@ -212,12 +228,14 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
     LIST(INSERT test_command test_exe_pos "${TEST_EXE}")
   ENDIF (test_exe_pos LESS 0)
 
-  SET(TEST_SCRIPT_CMD 
-    ${CMAKE_COMMAND} 
-    -DLD_LIBRARY_PATH=${ARCH_PREBUILT_DIRS}:/usr/lib
-    -DTEST_CMD:STRING="${test_command}" 
-    -P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake
-    )
+  IF(WINDOWS)
+    set(LD_LIBRARY_PATH ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR})
+  ELSE(WINDOWS)
+    set(LD_LIBRARY_PATH ${ARCH_PREBUILT_DIRS}:${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}:/usr/lib)
+  ENDIF(WINDOWS)
+
+  LL_TEST_COMMAND("${LD_LIBRARY_PATH}" ${test_command})
+  SET(TEST_SCRIPT_CMD ${LL_TEST_COMMAND_value})
 
   if(TEST_DEBUG)
     message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}")
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index ef202dd8796b5ee750aefd092db9160aac541931..d1ab264a413b8a3eaf263ea3bbef32e59ac42e9c 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -17,3 +17,7 @@ set(LLCOMMON_LIBRARIES llcommon)
 
 add_definitions(${TCMALLOC_FLAG})
 
+set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
+if(LLCOMMON_LINK_SHARED)
+  add_definitions(-DLL_COMMON_LINK_SHARED=1)
+endif(LLCOMMON_LINK_SHARED)
diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake
index f103dcf6649326451010bdbaf228710320ccfacb..6b69388896b0527b49b9b009bc934fea8d2ec69d 100644
--- a/indra/cmake/LLKDU.cmake
+++ b/indra/cmake/LLKDU.cmake
@@ -1,7 +1,7 @@
 # -*- cmake -*-
 include(Prebuilt)
 
-if (NOT STANDALONE AND EXISTS ${LIBS_CLOSED_DIR}/llkdu)
+if (INSTALL_PROPRIETARY AND NOT STANDALONE AND EXISTS ${LIBS_CLOSED_DIR}/llkdu)
   use_prebuilt_binary(kdu)
   if (WINDOWS)
     set(KDU_LIBRARY debug kdu_cored optimized kdu_core)
@@ -15,4 +15,4 @@ if (NOT STANDALONE AND EXISTS ${LIBS_CLOSED_DIR}/llkdu)
   set(LLKDU_STATIC_LIBRARY llkdu_static)
   set(LLKDU_LIBRARIES ${LLKDU_LIBRARY})
   set(LLKDU_STATIC_LIBRARIES ${LLKDU_STATIC_LIBRARY})
-endif (NOT STANDALONE AND EXISTS ${LIBS_CLOSED_DIR}/llkdu)
+endif (INSTALL_PROPRIETARY AND NOT STANDALONE AND EXISTS ${LIBS_CLOSED_DIR}/llkdu)
diff --git a/indra/cmake/LLLogin.cmake b/indra/cmake/LLLogin.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..47d171876a00df3fea3bf61a794cb3ff81fcd07b
--- /dev/null
+++ b/indra/cmake/LLLogin.cmake
@@ -0,0 +1,7 @@
+# -*- cmake -*-
+
+set(LLLOGIN_INCLUDE_DIRS
+    ${LIBS_OPEN_DIR}/viewer_components/login
+    )
+
+set(LLLOGIN_LIBRARIES lllogin)
diff --git a/indra/cmake/LLTestCommand.cmake b/indra/cmake/LLTestCommand.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..fae5640493345436507885fd5864885caa9640ab
--- /dev/null
+++ b/indra/cmake/LLTestCommand.cmake
@@ -0,0 +1,13 @@
+MACRO(LL_TEST_COMMAND LD_LIBRARY_PATH)
+  # nat wonders how Kitware can use the term 'function' for a construct that
+  # cannot return a value. And yet, variables you set inside a FUNCTION are
+  # local. Try a MACRO instead.
+  SET(LL_TEST_COMMAND_value
+    ${PYTHON_EXECUTABLE}
+    "${CMAKE_SOURCE_DIR}/cmake/run_build_test.py")
+  IF(LD_LIBRARY_PATH)
+    LIST(APPEND LL_TEST_COMMAND_value "-l${LD_LIBRARY_PATH}")
+  ENDIF(LD_LIBRARY_PATH)
+  LIST(APPEND LL_TEST_COMMAND_value ${ARGN})
+##MESSAGE(STATUS "Will run: ${LL_TEST_COMMAND_value}")
+ENDMACRO(LL_TEST_COMMAND)
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake
index eaa8a6dc2915ce82a4d488e9da155c82ae15a7c1..1f3553539f718b878fead3974b693590ef29f215 100644
--- a/indra/cmake/Linking.cmake
+++ b/indra/cmake/Linking.cmake
@@ -5,6 +5,7 @@ if (NOT STANDALONE)
     set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
     set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
     set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
+    set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged DLLs")
   elseif (LINUX)
     if (VIEWER)
       set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib_release_client)
@@ -13,10 +14,12 @@ if (NOT STANDALONE)
     endif (VIEWER)
     set(ARCH_PREBUILT_DIRS_RELEASE ${ARCH_PREBUILT_DIRS})
     set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS})
+    set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged .sos")
   elseif (DARWIN)
     set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib_release)
     set(ARCH_PREBUILT_DIRS ${ARCH_PREBUILT_DIRS_RELEASE})
     set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS_RELEASE})
+    set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged DLLs")
   endif (WINDOWS)
 endif (NOT STANDALONE)
 
diff --git a/indra/cmake/Pth.cmake b/indra/cmake/Pth.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..a28f6ec696efdbbcaeb8c1ee34dfb7dd7d436421
--- /dev/null
+++ b/indra/cmake/Pth.cmake
@@ -0,0 +1,21 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+set(PTH_FIND_QUIETLY ON)
+set(PTH_FIND_REQUIRED ON)
+
+if (STANDALONE)
+#  ?? How would I construct FindPTH.cmake? This file was cloned from
+#  CURL.cmake, which uses include(FindCURL), but there's no FindCURL.cmake?
+#  include(FindPTH)
+else (STANDALONE)
+  # This library is only needed to support Boost.Coroutine, and only on Mac.
+  if (DARWIN)
+    use_prebuilt_binary(pth)
+    set(PTH_LIBRARIES pth)
+    set(PTH_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
+  else (DARWIN)
+    set(PTH_LIBRARIES)
+    set(PTH_INCLUDE_DIRS)
+  endif (DARWIN)
+endif (STANDALONE)
diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..17bce6f43445792c586a0644880e59ba955b1c8a
--- /dev/null
+++ b/indra/cmake/run_build_test.py
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+"""\
+@file   run_build_test.py
+@author Nat Goodspeed
+@date   2009-09-03
+@brief  Helper script to allow CMake to run some command after setting
+        environment variables.
+
+CMake has commands to run an external program. But remember that each CMake
+command must be backed by multiple build-system implementations. Unfortunately
+it seems CMake can't promise that every target build system can set specified
+environment variables before running the external program of interest.
+
+This helper script is a workaround. It simply sets the requested environment
+variables and then executes the program specified on the rest of its command
+line.
+
+Example:
+
+python run_build_test.py -DFOO=bar myprog somearg otherarg
+
+sets environment variable FOO=bar, then runs:
+myprog somearg otherarg
+
+$LicenseInfo:firstyear=2009&license=internal$
+Copyright (c) 2009, Linden Research, Inc.
+$/LicenseInfo$
+"""
+
+import os
+import sys
+import subprocess
+
+def main(command, libpath=[], vars={}):
+    """Pass:
+    command is a sequence (e.g. a list) of strings. The first item in the list
+    must be the command name, the rest are its arguments.
+
+    libpath is a sequence of directory pathnames. These will be appended to
+    the platform-specific dynamic library search path environment variable.
+
+    vars is a dict of arbitrary (var, value) pairs to be added to the
+    environment before running 'command'.
+
+    This function runs the specified command, waits for it to terminate and
+    returns its return code. This will be negative if the command terminated
+    with a signal, else it will be the process's specified exit code.
+    """
+    # Handle platform-dependent libpath first.
+    if sys.platform == "win32":
+        lpvars = ["PATH"]
+    elif sys.platform == "darwin":
+        lpvars = ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"]
+    elif sys.platform.startswith("linux"):
+        lpvars = ["LD_LIBRARY_PATH"]
+    else:
+        # No idea what the right pathname might be! But only crump if this
+        # feature is requested.
+        if libpath:
+            raise NotImplemented("run_build_test: unknown platform %s" % sys.platform)
+        lpvars = []
+    for var in lpvars:
+        # Split the existing path. Bear in mind that the variable in question
+        # might not exist; instead of KeyError, just use an empty string.
+        dirs = os.environ.get(var, "").split(os.pathsep)
+        # Append the sequence in libpath
+##         print "%s += %r" % (var, libpath)
+        dirs.extend(libpath)
+        # Now rebuild the path string. This way we use a minimum of separators
+        # -- and we avoid adding a pointless separator when libpath is empty.
+        os.environ[var] = os.pathsep.join(dirs)
+    # Now handle arbitrary environment variables. The tricky part is ensuring
+    # that all the keys and values we try to pass are actually strings.
+##     if vars:
+##         print "Setting:"
+##         for key, value in vars.iteritems():
+##             print "%s=%s" % (key, value)
+    os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()]))
+    # Run the child process.
+##     print "Running: %s" % " ".join(command)
+    return subprocess.call(command)
+
+if __name__ == "__main__":
+    from optparse import OptionParser
+    parser = OptionParser(usage="usage: %prog [options] command args...")
+    # We want optparse support for the options we ourselves handle -- but we
+    # DO NOT want it looking at options for the executable we intend to run,
+    # rejecting them as invalid because we don't define them. So configure the
+    # parser to stop looking for options as soon as it sees the first
+    # positional argument (traditional Unix syntax).
+    parser.disable_interspersed_args()
+    parser.add_option("-D", "--define", dest="vars", default=[], action="append",
+                      metavar="VAR=value",
+                      help="Add VAR=value to the env variables defined")
+    parser.add_option("-l", "--libpath", dest="libpath", default=[], action="append",
+                      metavar="DIR",
+                      help="Add DIR to the platform-dependent DLL search path")
+    opts, args = parser.parse_args()
+    # What we have in opts.vars is a list of strings of the form "VAR=value"
+    # or possibly just "VAR". What we want is a dict. We can build that dict by
+    # constructing a list of ["VAR", "value"] pairs -- so split each
+    # "VAR=value" string on the '=' sign (but only once, in case we have
+    # "VAR=some=user=string"). To handle the case of just "VAR", append "" to
+    # the list returned by split(), then slice off anything after the pair we
+    # want.
+    rc = main(command=args, libpath=opts.libpath,
+              vars=dict([(pair.split('=', 1) + [""])[:2] for pair in opts.vars]))
+    if rc not in (None, 0):
+        print >>sys.stderr, "Failure running: %s" % " ".join(args)
+        print >>sys.stderr, "Error: %s" % rc
+    sys.exit((rc < 0) and 255 or rc)
diff --git a/indra/develop.py b/indra/develop.py
index b2b494d1b3d3ee4d0ab772d3c58b6d5ac13c33c5..7836c97473b1f46236e8c6e480d4f1e4cac1501b 100755
--- a/indra/develop.py
+++ b/indra/develop.py
@@ -439,7 +439,6 @@ def cmake_commandline(self, src_dir, build_dir, opts, simple):
             )
         if self.universal == 'ON':
             args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386;ppc\''
-            pass
         #if simple:
         #    return 'cmake %(opts)s %(dir)r' % args
         return ('cmake -G %(generator)r '
diff --git a/indra/lib/python/indra/base/llsd.py b/indra/lib/python/indra/base/llsd.py
index 1190d88663964a6c3dace2c291778ab676d0579e..4527b115f9ad07b6a2f9180090466c2f562112a1 100644
--- a/indra/lib/python/indra/base/llsd.py
+++ b/indra/lib/python/indra/base/llsd.py
@@ -238,7 +238,7 @@ def ARRAY(self, v):
     def MAP(self, v):
         return self.elt(
             'map',
-            ''.join(["%s%s" % (self.elt('key', key), self.generate(value))
+            ''.join(["%s%s" % (self.elt('key', self.xml_esc(str(key))), self.generate(value))
              for key, value in v.items()]))
 
     typeof = type
diff --git a/indra/lib/python/indra/base/lluuid.py b/indra/lib/python/indra/base/lluuid.py
index aceea29cd2082273456e06da21798853ccc5f145..1cdd8e915b996cf6d315339a400260ca677a3135 100644
--- a/indra/lib/python/indra/base/lluuid.py
+++ b/indra/lib/python/indra/base/lluuid.py
@@ -26,8 +26,14 @@
 $/LicenseInfo$
 """
 
-import md5, random, socket, string, time, re
+import random, socket, string, time, re
 import uuid
+try:
+    # Python 2.6
+    from hashlib import md5
+except ImportError:
+    # Python 2.5 and earlier
+    from md5 import new as md5
 
 def _int2binstr(i,l):
     s=''
@@ -196,7 +202,7 @@ def generate(self):
         from c++ implementation for portability reasons.
         Returns self.
         """
-        m = md5.new()
+        m = md5()
         m.update(uuid.uuid1().bytes)
         self._bits = m.digest()
         return self
diff --git a/indra/lib/python/indra/util/llsubprocess.py b/indra/lib/python/indra/util/llsubprocess.py
index c4c40739ec9514180d57f3c75db7259293ba679e..7e0e115d14600f29fe4b855077232a8d10529271 100644
--- a/indra/lib/python/indra/util/llsubprocess.py
+++ b/indra/lib/python/indra/util/llsubprocess.py
@@ -90,6 +90,17 @@ def run(command, args=None, data=None, timeout=None):
                     child.tochild.close()
         result = child.poll()
         if result != -1:
+            # At this point, the child process has exited and result
+            # is the return value from the process. Between the time
+            # we called select() and poll() the process may have
+            # exited so read all the data left on the child process
+            # stdout and stderr.
+            last = child.fromchild.read()
+            if last:
+                out.append(last)
+            last = child.childerr.read()
+            if last:
+                err.append(last)
             child.tochild.close()
             child.fromchild.close()
             child.childerr.close()
diff --git a/indra/lib/python/indra/util/llversion.py b/indra/lib/python/indra/util/llversion.py
index 770b861ddc1604e6dd2d133aa94513560c154455..2718a85f414cb958db30e8035bf21742583a084b 100644
--- a/indra/lib/python/indra/util/llversion.py
+++ b/indra/lib/python/indra/util/llversion.py
@@ -1,7 +1,7 @@
 """@file llversion.py
 @brief Utility for parsing llcommon/llversion${server}.h
        for the version string and channel string
-       Utility that parses svn info for branch and revision
+       Utility that parses hg or svn info for branch and revision
 
 $LicenseInfo:firstyear=2006&license=mit$
 
@@ -79,8 +79,8 @@ def get_svn_status_matching(regular_expression):
     status, output = commands.getstatusoutput('svn info %s' % get_src_root())
     m = regular_expression.search(output)
     if not m:
-        print "Failed to parse svn info output, resultfollows:"
-        print output
+        print >> sys.stderr, "Failed to parse svn info output, result follows:"
+        print >> sys.stderr, output
         raise Exception, "No matching svn status in "+src_root
     return m.group(1)
 
@@ -92,4 +92,35 @@ def get_svn_revision():
     last_rev_re = re.compile('Last Changed Rev: (\d+)')
     return get_svn_status_matching(last_rev_re)
 
-
+def get_hg_repo():
+    status, output = commands.getstatusoutput('hg showconfig paths.default')
+    if status:
+        print >> sys.stderr, output
+        sys.exit(1)
+    if not output:
+        print >> sys.stderr, 'ERROR: cannot find repo we cloned from'
+        sys.exit(1)
+    return output
+
+def get_hg_changeset():
+    # The right thing to do:
+    # status, output = commands.getstatusoutput('hg id -i')
+    # if status:
+    #     print >> sys.stderr, output
+    #    sys.exit(1)
+
+    # The temporary hack:
+    status, output = commands.getstatusoutput('hg parents --template "{rev}"')
+    if status:
+        print >> sys.stderr, output
+        sys.exit(1)
+    lines = output.splitlines()
+    if len(lines) > 1:
+        print >> sys.stderr, 'ERROR: working directory has %d parents' % len(lines)
+    return lines[0]
+
+def using_svn():
+    return os.path.isdir(os.path.join(get_src_root(), '.svn'))
+
+def using_hg():
+    return os.path.isdir(os.path.join(get_src_root(), '.hg'))
diff --git a/indra/lib/python/indra/util/named_query.py b/indra/lib/python/indra/util/named_query.py
index 693b483f792f485d206dbac812865a6fef3d0170..5c19368240afa08b8576f3f16ec01c4b738c5f76 100644
--- a/indra/lib/python/indra/util/named_query.py
+++ b/indra/lib/python/indra/util/named_query.py
@@ -48,8 +48,8 @@
 from indra.base import config
 
 DEBUG = False
-NQ_FILE_SUFFIX = None
-NQ_FILE_SUFFIX_LEN = None
+NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq')
+NQ_FILE_SUFFIX_LEN  = len(NQ_FILE_SUFFIX)
 
 _g_named_manager = None
 
diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py
new file mode 100644
index 0000000000000000000000000000000000000000..0149b9f43a8164860d5c696f31efa3422c3dcc65
--- /dev/null
+++ b/indra/lib/python/indra/util/test_win32_manifest.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+# @file test_win32_manifest.py
+# @brief Test an assembly binding version and uniqueness in a windows dll or exe.  
+#
+# $LicenseInfo:firstyear=2009&license=viewergpl$
+# 
+# Copyright (c) 2009, Linden Research, Inc.
+# 
+# Second Life Viewer Source Code
+# The source code in this file ("Source Code") is provided by Linden Lab
+# to you under the terms of the GNU General Public License, version 2.0
+# ("GPL"), unless you have obtained a separate licensing agreement
+# ("Other License"), formally executed by you and Linden Lab.  Terms of
+# the GPL can be found in doc/GPL-license.txt in this distribution, or
+# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+# 
+# There are special exceptions to the terms and conditions of the GPL as
+# it is applied to this Source Code. View the full text of the exception
+# in the file doc/FLOSS-exception.txt in this software distribution, or
+# online at
+# http://secondlifegrid.net/programs/open_source/licensing/flossexception
+# 
+# By copying, modifying or distributing this software, you acknowledge
+# that you have read and understood your obligations described above,
+# and agree to abide by those obligations.
+# 
+# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+# COMPLETENESS OR PERFORMANCE.
+# $/LicenseInfo$
+
+import sys, os
+import tempfile
+from xml.dom.minidom import parse
+
+class AssemblyTestException(Exception):
+    pass
+
+class NoManifestException(AssemblyTestException):
+    pass
+
+class MultipleBindingsException(AssemblyTestException):
+    pass
+
+class UnexpectedVersionException(AssemblyTestException):
+    pass
+
+class NoMatchingAssemblyException(AssemblyTestException):
+    pass
+
+def get_HKLM_registry_value(key_str, value_str):
+    import _winreg
+    reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
+    key = _winreg.OpenKey(reg, key_str)
+    value = _winreg.QueryValueEx(key, value_str)[0]
+    #print 'Found: %s' % value
+    return value
+        
+def find_vc_dir():
+    supported_versions = (r'8.0', r'9.0')
+    value_str = (r'ProductDir')
+    
+    for version in supported_versions:
+        key_str = (r'SOFTWARE\Microsoft\VisualStudio\%s\Setup\VC' %
+                   version)
+        try:
+            return get_HKLM_registry_value(key_str, value_str)
+        except WindowsError, err:
+            x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' %
+                       version)
+            try:
+                return get_HKLM_registry_value(x64_key_str, value_str)
+            except:
+                print >> sys.stderr, "Didn't find MS VC version %s " % version
+        
+    raise
+
+def find_mt_path():
+    vc_dir = find_vc_dir()
+    mt_path = '\"%sbin\\mt.exe\"' % vc_dir
+    return mt_path
+    
+def test_assembly_binding(src_filename, assembly_name, assembly_ver):
+    print "checking %s dependency %s..." % (src_filename, assembly_name)
+
+    (tmp_file_fd, tmp_file_name) = tempfile.mkstemp(suffix='.xml')
+    tmp_file = os.fdopen(tmp_file_fd)
+    tmp_file.close()
+
+    mt_path = find_mt_path()
+    resource_id = ""
+    if os.path.splitext(src_filename)[1].lower() == ".dll":
+       resource_id = ";#2"
+    system_call = '%s -nologo -inputresource:%s%s -out:%s > NUL' % (mt_path, src_filename, resource_id, tmp_file_name)
+    print "Executing: %s" % system_call
+    mt_result = os.system(system_call)
+    if mt_result == 31:
+        print "No manifest found in %s" % src_filename
+        raise NoManifestException()
+
+    manifest_dom = parse(tmp_file_name)
+    nodes = manifest_dom.getElementsByTagName('assemblyIdentity')
+
+    versions = list()
+    for node in nodes:
+        if node.getAttribute('name') == assembly_name:
+            versions.append(node.getAttribute('version'))
+
+    if len(versions) == 0:
+        print "No matching assemblies found in %s" % src_filename
+        raise NoMatchingAssemblyException()
+        
+    elif len(versions) > 1:
+        print "Multiple bindings to %s found:" % assembly_name
+        print versions
+        print 
+        raise MultipleBindingsException(versions)
+
+    elif versions[0] != assembly_ver:
+        print "Unexpected version found for %s:" % assembly_name
+        print "Wanted %s, found %s" % (assembly_ver, versions[0])
+        print
+        raise UnexpectedVersionException(assembly_ver, versions[0])
+            
+    os.remove(tmp_file_name)
+    
+    print "SUCCESS: %s OK!" % src_filename
+    print
+  
+if __name__ == '__main__':
+
+    print
+    print "Running test_win32_manifest.py..."
+    
+    usage = 'test_win32_manfest <srcFileName> <assemblyName> <assemblyVersion>'
+
+    try:
+        src_filename = sys.argv[1]
+        assembly_name = sys.argv[2]
+        assembly_ver = sys.argv[3]
+    except:
+        print "Usage:"
+        print usage
+        print
+        raise
+    
+    test_assembly_binding(src_filename, assembly_name, assembly_ver)
+
+    
diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp
index 1d42298f4d395adb638efae4713af11a74e45e72..1ae0ddeea0fba8787885b6a247866c0809973a28 100644
--- a/indra/llcharacter/llkeyframestandmotion.cpp
+++ b/indra/llcharacter/llkeyframestandmotion.cpp
@@ -190,7 +190,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)
 	if (dot(mPelvisState->getJoint()->getWorldRotation(), mLastGoodPelvisRotation) < ROTATION_THRESHOLD)
 	{
 		mLastGoodPelvisRotation = mPelvisState->getJoint()->getWorldRotation();
-		mLastGoodPelvisRotation.normQuat();
+		mLastGoodPelvisRotation.normalize();
 		mTrackAnkles = TRUE;
 	}
 	else if ((mCharacter->getCharacterPosition() - mLastGoodPosition).magVecSquared() > POSITION_THRESHOLD)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 7468e3dde46c62bba6e4aeda9ff1104408e0fd07..e7aaf3c984de74f5c3ed45d38b50cdb7931273a6 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -4,12 +4,19 @@ project(llcommon)
 
 include(00-Common)
 include(LLCommon)
+include(Linking)
 include(Boost)
+include (Pth)
+
+if (WINDOWS)
+    include(CopyWinLibs)
+endif (WINDOWS)
 
 include_directories(
     ${EXPAT_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
     ${ZLIB_INCLUDE_DIRS}
+    ${PTH_INCLUDE_DIRS}
     )
 
 # add_executable(lltreeiterators lltreeiterators.cpp)
@@ -26,6 +33,7 @@ set(llcommon_SOURCE_FILES
     llbase32.cpp
     llbase64.cpp
     llcommon.cpp
+    llcoros.cpp
     llcrc.cpp
     llcriticaldamp.cpp
     llcursortypes.cpp
@@ -34,6 +42,9 @@ set(llcommon_SOURCE_FILES
     llerror.cpp
     llerrorthread.cpp
     llevent.cpp
+    lleventcoro.cpp
+    lleventdispatcher.cpp
+    lleventfilter.cpp
     llevents.cpp
     llfasttimer.cpp
     llfile.cpp
@@ -64,6 +75,7 @@ set(llcommon_SOURCE_FILES
     llsdserialize_xml.cpp
     llsdutil.cpp
     llsecondlifeurls.cpp
+    llsingleton.cpp
     llstat.cpp
     llstacktrace.cpp
     llstreamtools.cpp
@@ -106,6 +118,7 @@ set(llcommon_HEADER_FILES
     llchat.h
     llclickaction.h
     llcommon.h
+    llcoros.h
     llcrc.h
     llcriticaldamp.h
     llcursortypes.h
@@ -127,6 +140,9 @@ set(llcommon_HEADER_FILES
     llerrorlegacy.h
     llerrorthread.h
     llevent.h
+    lleventcoro.h
+    lleventdispatcher.h
+    lleventfilter.h
     llevents.h
     lleventemitter.h
     llextendedstatus.h
@@ -141,6 +157,7 @@ set(llcommon_HEADER_FILES
     llhttpstatuscodes.h
     llindexedqueue.h
     llinstancetracker.h
+    llinstancetracker.h
     llkeythrottle.h
     lllazy.h
     lllinkedqueue.h
@@ -222,25 +239,63 @@ set_source_files_properties(${llcommon_HEADER_FILES}
 
 list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
 
-add_library (llcommon ${llcommon_SOURCE_FILES})
-target_link_libraries(llcommon
+if(LLCOMMON_LINK_SHARED)
+    add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
+
+    if(SHARED_LIB_STAGING_DIR)
+        # *FIX:Mani ---
+        # llcommon.dll get written to the DLL staging directory.
+        # Also this directory is shared with RunBuildTest.cmake, y'know, for the tests.
+        set_target_properties(llcommon PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SHARED_LIB_STAGING_DIR})
+        if(NOT WINDOWS)
+          get_target_property(LLCOMMON_PATH llcommon LOCATION)
+          get_filename_component(LLCOMMON_FILE ${LLCOMMON_PATH} NAME)
+          add_custom_command(
+            TARGET llcommon POST_BUILD
+            COMMAND ${CMAKE_COMMAND}
+            ARGS
+              -E
+              copy_if_different
+              ${LLCOMMON_PATH}
+              ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/${LLCOMMON_FILE}
+            COMMENT "Copying llcommon to the staging folder."
+            )
+        endif(NOT WINDOWS)
+    endif(SHARED_LIB_STAGING_DIR)
+
+    if (DARWIN)
+      set_target_properties(llcommon PROPERTIES
+        BUILD_WITH_INSTALL_RPATH 1
+        INSTALL_NAME_DIR "@executable_path/../Resources"
+        )
+    endif(DARWIN)
+
+else(LLCOMMON_LINK_SHARED)
+    add_library (llcommon ${llcommon_SOURCE_FILES})
+endif(LLCOMMON_LINK_SHARED)
+
+target_link_libraries(
+    llcommon
     ${APRUTIL_LIBRARIES}
     ${APR_LIBRARIES}
     ${EXPAT_LIBRARIES}
     ${ZLIB_LIBRARIES}
+    ${WINDOWS_LIBRARIES}
     ${BOOST_PROGRAM_OPTIONS_LIBRARY}
     ${BOOST_REGEX_LIBRARY}
+    ${PTH_LIBRARIES}
     )
 
-#add unit tests
-INCLUDE(LLAddBuildTest)
+add_dependencies(llcommon stage_third_party_libs)
+
+include(LLAddBuildTest)
 SET(llcommon_TEST_SOURCE_FILES
   # unit-testing llcommon is not possible right now as the test-harness *itself* depends upon llcommon, causing a circular dependency.  Add your 'unit' tests as integration tests for now.
   )
 LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}")
 
 #set(TEST_DEBUG on)
-set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
+set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES})
 LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}")
 LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}")
 LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}")
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index 8687a246558253248db47bed75f113930b87f137..c2eb867795d8c87d3a0036b1d113a158c8b2dee3 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -72,13 +72,7 @@
 #ifdef LL_WINDOWS
 // Reenable warnings we disabled above
 #pragma warning (3 : 4702) // unreachable code, we like level 3, not 4
-// level 4 warnings that we need to disable:
-#pragma warning (disable : 4100) // unreferenced formal parameter
-#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) )
-#pragma warning (disable : 4244) // possible loss of data on conversions
-#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
-#pragma warning (disable : 4512) // assignment operator could not be generated
-#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) )
+// moved msvc warnings to llpreprocessor.h  *TODO - delete this comment after merge conflicts are unlikely -brad
 #endif	//	LL_WINDOWS
 
 // Linden only libs in alpha-order other than stdtypes.h
diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h
index 2b70fee0b8f9d6dd94b7b42c0aac0364305703f3..0d6f18c5d47a80cc06499df7b2e50eddd0ce0ffd 100644
--- a/indra/llcommon/llallocator.h
+++ b/indra/llcommon/llallocator.h
@@ -1,63 +1,63 @@
-/** 
- * @file llallocator.h
- * @brief Declaration of the LLAllocator class.
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * 
- * Copyright (c) 2009-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLALLOCATOR_H
-#define LL_LLALLOCATOR_H
-
-#include <string>
-
-#include "llmemtype.h"
-#include "llallocator_heap_profile.h"
-
-class LLAllocator {
-    friend class LLMemoryView;
-    friend class LLMemType;
-
-private:
-	static void pushMemType(S32 type);
-	static S32 popMemType();
-
-public:
-    void setProfilingEnabled(bool should_enable);
-
-    static bool isProfiling();
-
-    LLAllocatorHeapProfile const & getProfile();
-
-private:
-    std::string getRawProfile();
-
-private:
-    LLAllocatorHeapProfile mProf;
-};
-
-#endif // LL_LLALLOCATOR_H
+/** 
+ * @file llallocator.h
+ * @brief Declaration of the LLAllocator class.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLALLOCATOR_H
+#define LL_LLALLOCATOR_H
+
+#include <string>
+
+#include "llmemtype.h"
+#include "llallocator_heap_profile.h"
+
+class LL_COMMON_API LLAllocator {
+    friend class LLMemoryView;
+    friend class LLMemType;
+
+private:
+	static void pushMemType(S32 type);
+	static S32 popMemType();
+
+public:
+    void setProfilingEnabled(bool should_enable);
+
+    static bool isProfiling();
+
+    LLAllocatorHeapProfile const & getProfile();
+
+private:
+    std::string getRawProfile();
+
+private:
+    LLAllocatorHeapProfile mProf;
+};
+
+#endif // LL_LLALLOCATOR_H
diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp
index d82ee9ed81bc25c43fea886a95abe558bd19d07e..0a807702d0a92fbafc805a622efef16bfe2834a0 100644
--- a/indra/llcommon/llallocator_heap_profile.cpp
+++ b/indra/llcommon/llallocator_heap_profile.cpp
@@ -38,6 +38,7 @@
 // disable warning about boost::lexical_cast returning uninitialized data
 // when it fails to parse the string
 #pragma warning (disable:4701)
+#pragma warning (disable:4702)
 #endif
 
 #include <boost/algorithm/string/split.hpp>
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index e32a293f1cca8754535f73f2db3e7d34c9b6d565..1a052ce62d6c316722e6fbda471f7c03aa2427de 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -62,7 +62,7 @@ class LLChildInfo
 };
 #endif
 
-class LLApp : public LLOptionInterface
+class LL_COMMON_API LLApp : public LLOptionInterface
 {
 	friend class LLErrorThread;
 public:
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 63130a89fcd1d3f5f7d557642c159aacced9a925..0898aeec470e26e02717b8dddf03352f6e8c2373 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -1,259 +1,259 @@
-/** 
- * @file llapr.h
- * @author Phoenix
- * @date 2004-11-28
- * @brief Helper functions for using the apache portable runtime library.
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- * 
- * Copyright (c) 2004-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLAPR_H
-#define LL_LLAPR_H
-
-#if LL_LINUX || LL_SOLARIS
-#include <sys/param.h>  // Need PATH_MAX in APR headers...
-#endif
-
-#include <boost/noncopyable.hpp>
-
-#include "apr_thread_proc.h"
-#include "apr_thread_mutex.h"
-#include "apr_getopt.h"
-#include "apr_signal.h"
-#include "apr_atomic.h"
-#include "llstring.h"
-
-extern apr_thread_mutex_t* gLogMutexp;
-extern apr_thread_mutex_t* gCallStacksLogMutexp;
-
-/** 
- * @brief initialize the common apr constructs -- apr itself, the
- * global pool, and a mutex.
- */
-void ll_init_apr();
-
-/** 
- * @brief Cleanup those common apr constructs.
- */
-void ll_cleanup_apr();
-
-//
-//LL apr_pool
-//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
-//
-class LLAPRPool
-{
-public:
-	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
-	~LLAPRPool() ;
-
-	apr_pool_t* getAPRPool() ;
-	apr_status_t getStatus() {return mStatus ; }
-
-protected:
-	void releaseAPRPool() ;
-	void createAPRPool() ;
-
-protected:
-	apr_pool_t*  mPool ;              //pointing to an apr_pool
-	apr_pool_t*  mParent ;			  //parent pool
-	apr_size_t   mMaxSize ;           //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
-	apr_status_t mStatus ;            //status when creating the pool
-	BOOL         mReleasePoolFlag ;   //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
-};
-
-//
-//volatile LL apr_pool
-//which clears memory automatically.
-//so it can not hold static data or data after memory is cleared
-//
-class LLVolatileAPRPool : public LLAPRPool
-{
-public:
-	LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
-	~LLVolatileAPRPool(){}
-
-	apr_pool_t* getVolatileAPRPool() ;
-	
-	void        clearVolatileAPRPool() ;
-
-	BOOL        isFull() ;
-	BOOL        isEmpty() {return !mNumActiveRef ;}
-private:
-	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
-	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.   
-} ;
-
-/** 
- * @class LLScopedLock
- * @brief Small class to help lock and unlock mutexes.
- *
- * This class is used to have a stack level lock once you already have
- * an apr mutex handy. The constructor handles the lock, and the
- * destructor handles the unlock. Instances of this class are
- * <b>not</b> thread safe.
- */
-class LLScopedLock : private boost::noncopyable
-{
-public:
-	/**
-	 * @brief Constructor which accepts a mutex, and locks it.
-	 *
-	 * @param mutex An allocated APR mutex. If you pass in NULL,
-	 * this wrapper will not lock.
-	 */
-	LLScopedLock(apr_thread_mutex_t* mutex);
-
-	/**
-	 * @brief Destructor which unlocks the mutex if still locked.
-	 */
-	~LLScopedLock();
-
-	/** 
-	 * @brief Check lock.
-	 */
-	bool isLocked() const { return mLocked; }
-
-	/** 
-	 * @brief This method unlocks the mutex.
-	 */
-	void unlock();
-
-protected:
-	bool mLocked;
-	apr_thread_mutex_t* mMutex;
-};
-
-template <typename Type> class LLAtomic32
-{
-public:
-	LLAtomic32<Type>() {};
-	LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
-	~LLAtomic32<Type>() {};
-
-	operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
-	Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
-	void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
-	void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
-	Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
-	Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
-	
-private:
-	apr_uint32_t mData;
-};
-
-typedef LLAtomic32<U32> LLAtomicU32;
-typedef LLAtomic32<S32> LLAtomicS32;
-
-// File IO convenience functions.
-// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
-// abbreviated flags
-#define LL_APR_R (APR_READ) // "r"
-#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
-#define LL_APR_RB (APR_READ|APR_BINARY) // "rb"
-#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
-#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
-#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
-
-//
-//apr_file manager
-//which: 1)only keeps one file open;
-//       2)closes the open file in the destruction function
-//       3)informs the apr_pool to clean the memory when the file is closed.
-//Note: please close an open file at the earliest convenience. 
-//      especially do not put some time-costly operations between open() and close().
-//      otherwise it might lock the APRFilePool.
-//there are two different apr_pools the APRFile can use:
-//      1, a temperary pool passed to an APRFile function, which is used within this function and only once.
-//      2, a global pool.
-//
-class LLAPRFile
-{
-private:
-	apr_file_t* mFile ;
-	LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. 
-
-public:
-	LLAPRFile() ;
-	~LLAPRFile() ;
-
-	apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
-	apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
-	apr_status_t close() ;
-
-	// Returns actual offset, -1 if seek fails
-	S32 seek(apr_seek_where_t where, S32 offset);
-	apr_status_t eof() { return apr_file_eof(mFile);}
-
-	// Returns bytes read/written, 0 if read/write fails:
-	S32 read(void* buf, S32 nbytes);
-	S32 write(const void* buf, S32 nbytes);
-	
-	apr_file_t* getFileHandle() {return mFile;}	
-
-private:
-	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
-
-//
-//*******************************************************************************************************************************
-//static components
-//
-public:
-	static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
-
-private:
-	static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
-	static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
-	static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
-public:
-	// returns false if failure:
-	static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
-	static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
-	static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
-	static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
-	static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
-	static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
-
-	// Returns bytes read/written, 0 if read/write fails:
-	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
-	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
-//*******************************************************************************************************************************
-};
-
-/**
- * @brief Function which approprately logs error or remains quiet on
- * APR_SUCCESS.
- * @return Returns <code>true</code> if status is an error condition.
- */
-bool ll_apr_warn_status(apr_status_t status);
-
-void ll_apr_assert_status(apr_status_t status);
-
-extern "C" apr_pool_t* gAPRPoolp; // Global APR memory pool
-
-#endif // LL_LLAPR_H
+/** 
+ * @file llapr.h
+ * @author Phoenix
+ * @date 2004-11-28
+ * @brief Helper functions for using the apache portable runtime library.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ * 
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAPR_H
+#define LL_LLAPR_H
+
+#if LL_LINUX || LL_SOLARIS
+#include <sys/param.h>  // Need PATH_MAX in APR headers...
+#endif
+
+#include <boost/noncopyable.hpp>
+
+#include "apr_thread_proc.h"
+#include "apr_thread_mutex.h"
+#include "apr_getopt.h"
+#include "apr_signal.h"
+#include "apr_atomic.h"
+#include "llstring.h"
+
+extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
+extern apr_thread_mutex_t* gCallStacksLogMutexp;
+
+/** 
+ * @brief initialize the common apr constructs -- apr itself, the
+ * global pool, and a mutex.
+ */
+void LL_COMMON_API ll_init_apr();
+
+/** 
+ * @brief Cleanup those common apr constructs.
+ */
+void LL_COMMON_API ll_cleanup_apr();
+
+//
+//LL apr_pool
+//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
+//
+class LL_COMMON_API LLAPRPool
+{
+public:
+	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
+	~LLAPRPool() ;
+
+	apr_pool_t* getAPRPool() ;
+	apr_status_t getStatus() {return mStatus ; }
+
+protected:
+	void releaseAPRPool() ;
+	void createAPRPool() ;
+
+protected:
+	apr_pool_t*  mPool ;              //pointing to an apr_pool
+	apr_pool_t*  mParent ;			  //parent pool
+	apr_size_t   mMaxSize ;           //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
+	apr_status_t mStatus ;            //status when creating the pool
+	BOOL         mReleasePoolFlag ;   //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
+};
+
+//
+//volatile LL apr_pool
+//which clears memory automatically.
+//so it can not hold static data or data after memory is cleared
+//
+class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
+{
+public:
+	LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
+	~LLVolatileAPRPool(){}
+
+	apr_pool_t* getVolatileAPRPool() ;
+	
+	void        clearVolatileAPRPool() ;
+
+	BOOL        isFull() ;
+	BOOL        isEmpty() {return !mNumActiveRef ;}
+private:
+	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
+	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.   
+} ;
+
+/** 
+ * @class LLScopedLock
+ * @brief Small class to help lock and unlock mutexes.
+ *
+ * This class is used to have a stack level lock once you already have
+ * an apr mutex handy. The constructor handles the lock, and the
+ * destructor handles the unlock. Instances of this class are
+ * <b>not</b> thread safe.
+ */
+class LL_COMMON_API LLScopedLock : private boost::noncopyable
+{
+public:
+	/**
+	 * @brief Constructor which accepts a mutex, and locks it.
+	 *
+	 * @param mutex An allocated APR mutex. If you pass in NULL,
+	 * this wrapper will not lock.
+	 */
+	LLScopedLock(apr_thread_mutex_t* mutex);
+
+	/**
+	 * @brief Destructor which unlocks the mutex if still locked.
+	 */
+	~LLScopedLock();
+
+	/** 
+	 * @brief Check lock.
+	 */
+	bool isLocked() const { return mLocked; }
+
+	/** 
+	 * @brief This method unlocks the mutex.
+	 */
+	void unlock();
+
+protected:
+	bool mLocked;
+	apr_thread_mutex_t* mMutex;
+};
+
+template <typename Type> class LLAtomic32
+{
+public:
+	LLAtomic32<Type>() {};
+	LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
+	~LLAtomic32<Type>() {};
+
+	operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
+	Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
+	void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
+	void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
+	Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
+	Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
+	
+private:
+	apr_uint32_t mData;
+};
+
+typedef LLAtomic32<U32> LLAtomicU32;
+typedef LLAtomic32<S32> LLAtomicS32;
+
+// File IO convenience functions.
+// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
+// abbreviated flags
+#define LL_APR_R (APR_READ) // "r"
+#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
+#define LL_APR_RB (APR_READ|APR_BINARY) // "rb"
+#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
+#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
+#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
+
+//
+//apr_file manager
+//which: 1)only keeps one file open;
+//       2)closes the open file in the destruction function
+//       3)informs the apr_pool to clean the memory when the file is closed.
+//Note: please close an open file at the earliest convenience. 
+//      especially do not put some time-costly operations between open() and close().
+//      otherwise it might lock the APRFilePool.
+//there are two different apr_pools the APRFile can use:
+//      1, a temperary pool passed to an APRFile function, which is used within this function and only once.
+//      2, a global pool.
+//
+class LL_COMMON_API LLAPRFile
+{
+private:
+	apr_file_t* mFile ;
+	LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. 
+
+public:
+	LLAPRFile() ;
+	~LLAPRFile() ;
+
+	apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
+	apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
+	apr_status_t close() ;
+
+	// Returns actual offset, -1 if seek fails
+	S32 seek(apr_seek_where_t where, S32 offset);
+	apr_status_t eof() { return apr_file_eof(mFile);}
+
+	// Returns bytes read/written, 0 if read/write fails:
+	S32 read(void* buf, S32 nbytes);
+	S32 write(const void* buf, S32 nbytes);
+	
+	apr_file_t* getFileHandle() {return mFile;}	
+
+private:
+	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
+
+//
+//*******************************************************************************************************************************
+//static components
+//
+public:
+	static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
+
+private:
+	static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
+	static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
+	static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
+public:
+	// returns false if failure:
+	static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+	static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
+	static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
+	static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+	static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+	static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+
+	// Returns bytes read/written, 0 if read/write fails:
+	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
+	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
+//*******************************************************************************************************************************
+};
+
+/**
+ * @brief Function which approprately logs error or remains quiet on
+ * APR_SUCCESS.
+ * @return Returns <code>true</code> if status is an error condition.
+ */
+bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
+
+void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
+
+extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
+
+#endif // LL_LLAPR_H
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 0b016b81fbee089a205cefb7cadc4cb86e8c09f2..b2a92861cc31a43e602fb710a9b8e694b8ff7a95 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -289,6 +289,7 @@ bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type)
 			asset_type <= AT_FOLDER_ENSEMBLE_END);
 }
 
+
 // static. Generate a good default description
 void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type,
 										 std::string& description)
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 5e5118854161f3348244f712e0a81cae2f8fb1ba..33705cd2b1bc36a5e6d4e5c8100e0725b4b472c3 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -1,204 +1,205 @@
-/** 
- * @file llassettype.h
- * @brief Declaration of LLAssetType.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- * 
- * Copyright (c) 2001-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLASSETTYPE_H
-#define LL_LLASSETTYPE_H
-
-#include <string>
-
-#include "stdenums.h" 	// for EDragAndDropType
-
-class LLAssetType
-{
-public:
-	enum EType
-	{
-		AT_TEXTURE = 0,
-			// Used for painting the faces of geometry.
-			// Stored in typical j2c stream format.
-
-		AT_SOUND = 1, 
-			// Used to fill the aural spectrum.
-
-		AT_CALLINGCARD = 2,
-		    // Links instant message access to the user on the card.
-			// : E.G. A card for yourself, for linden support, for
-			// : the guy you were talking to in the coliseum.
-
-		AT_LANDMARK = 3,
-			// Links to places in the world with location and a screen shot or image saved.
-			// : E.G. Home, linden headquarters, the coliseum, destinations where 
-			// : we want to increase traffic.
-
-		AT_SCRIPT = 4,
-			// Valid scripts that can be attached to an object.
-			// : E.G. Open a door, jump into the air.
-
-		AT_CLOTHING = 5,
-			// A collection of textures and parameters that can be worn by an avatar.
-
-		AT_OBJECT = 6,
-			// Any combination of textures, sounds, and scripts that are
-			// associated with a fixed piece of geometry.
-			// : E.G. A hot tub, a house with working door.
-
-		AT_NOTECARD = 7,
-			// Just text.
-
-		AT_CATEGORY = 8,
-			// Holds a collection of inventory items.
-			// It's treated as an item in the inventory and therefore needs a type.
-
-		AT_ROOT_CATEGORY = 9,
-			// A user's root inventory category.
-			// We decided to expose it visually, so it seems logical to fold
-			// it into the asset types.
-
-		AT_LSL_TEXT = 10,
-		AT_LSL_BYTECODE = 11,
-			// The LSL is the scripting language. 
-			// We've split it into a text and bytecode representation.
-		
-		AT_TEXTURE_TGA = 12,
-			// Uncompressed TGA texture.
-
-		AT_BODYPART = 13,
-			// A collection of textures and parameters that can be worn by an avatar.
-
-		AT_TRASH = 14,
-			// Only to be used as a marker for a category preferred type. 
-			// Using this, we can throw things in the trash before completely deleting.
-
-		AT_SNAPSHOT_CATEGORY = 15,
-			// A marker for a folder meant for snapshots. 
-			// No actual assets will be snapshots, though if there were, you
-			// could interpret them as textures.
-
-		AT_LOST_AND_FOUND = 16,
-			// Used to stuff lost&found items into.
-
-		AT_SOUND_WAV = 17,
-			// Uncompressed sound.
-
-		AT_IMAGE_TGA = 18,
-			// Uncompressed image, non-square.
-			// Not appropriate for use as a texture.
-
-		AT_IMAGE_JPEG = 19,
-			// Compressed image, non-square.
-			// Not appropriate for use as a texture.
-
-		AT_ANIMATION = 20,
-			// Animation.
-
-		AT_GESTURE = 21,
-			// Gesture, sequence of animations, sounds, chat, wait steps.
-
-		AT_SIMSTATE = 22,
-			// Simstate file.
-
-		AT_FAVORITE = 23,
-			// favorite items
-
-		AT_LINK = 24,
-			// Inventory symbolic link
-
-		AT_LINK_FOLDER = 25,
-			// Inventory folder link
-
-		AT_FOLDER_ENSEMBLE_START = 26,
-		AT_FOLDER_ENSEMBLE_END = 45,
-			// This range is reserved for special clothing folder types.
-
-		AT_CURRENT_OUTFIT = 46,
-			// Current outfit
-
-		AT_OUTFIT = 47,
-			// Predefined outfit ("look")
-
-		AT_MY_OUTFITS = 48,
-			// Folder that holds your outfits.
-
-		
-		AT_COUNT = 49,
-			// +*********************************************************+
-			// |  TO ADD AN ELEMENT TO THIS ENUM:                        |
-			// +*********************************************************+
-			// | 1. INSERT BEFORE AT_COUNT                               |
-			// | 2. INCREMENT AT_COUNT BY 1                              |
-			// | 3. ADD TO LLAssetDictionary in LLAssetType.cpp          |
-			// | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp  |
-			// +*********************************************************+
-
-		AT_NONE = -1
-	};
-
-	// machine transation between type and strings
-	static EType 				lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
-	static EType 				lookup(const std::string& type_name);
-	static const char*			lookup(EType asset_type);
-
-	// translation from a type to a human readable form.
-	static EType 				lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate
-	static EType 				lookupHumanReadable(const std::string& readable_name);
-	static const char*			lookupHumanReadable(EType asset_type);
-
-	// Generate a good default description. You may want to add a verb
-	// or agent name after this depending on your application.
-	static void 				generateDescriptionFor(LLAssetType::EType asset_type,
-													   std::string& description);
-
-	static EType 				getType(const std::string& desc_name);
-	static const std::string&	getDesc(EType asset_type);
-	static EDragAndDropType   	lookupDragAndDropType(EType asset_type);
-
-	static bool 				lookupCanLink(EType asset_type);
-	static bool 				lookupIsLinkType(EType asset_type);
-
-	static const char*  		lookupCategoryName(EType asset_type);
-	static bool 				lookupIsProtectedCategoryType(EType asset_type);
-	static bool 				lookupIsEnsembleCategoryType(EType asset_type);
-
-	/* TODO: Change return types from "const char *" to "const std::string &".
-	This is fairly straightforward, but requires changing some calls to use .c_str().
-	e.g.:
-	-	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
-	+	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str());
-	*/
-	
-private:
-	// don't instantiate or derive one of these objects
-	LLAssetType( void ) {}
-	~LLAssetType( void ) {}
-};
-
-#endif // LL_LLASSETTYPE_H
+/** 
+ * @file llassettype.h
+ * @brief Declaration of LLAssetType.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLASSETTYPE_H
+#define LL_LLASSETTYPE_H
+
+#include <string>
+
+#include "stdenums.h" 	// for EDragAndDropType
+
+class LL_COMMON_API LLAssetType
+{
+public:
+	enum EType
+	{
+		AT_TEXTURE = 0,
+			// Used for painting the faces of geometry.
+			// Stored in typical j2c stream format.
+
+		AT_SOUND = 1, 
+			// Used to fill the aural spectrum.
+
+		AT_CALLINGCARD = 2,
+		    // Links instant message access to the user on the card.
+			// : E.G. A card for yourself, for linden support, for
+			// : the guy you were talking to in the coliseum.
+
+		AT_LANDMARK = 3,
+			// Links to places in the world with location and a screen shot or image saved.
+			// : E.G. Home, linden headquarters, the coliseum, destinations where 
+			// : we want to increase traffic.
+
+		AT_SCRIPT = 4,
+			// Valid scripts that can be attached to an object.
+			// : E.G. Open a door, jump into the air.
+
+		AT_CLOTHING = 5,
+			// A collection of textures and parameters that can be worn by an avatar.
+
+		AT_OBJECT = 6,
+			// Any combination of textures, sounds, and scripts that are
+			// associated with a fixed piece of geometry.
+			// : E.G. A hot tub, a house with working door.
+
+		AT_NOTECARD = 7,
+			// Just text.
+
+		AT_CATEGORY = 8,
+			// Holds a collection of inventory items.
+			// It's treated as an item in the inventory and therefore needs a type.
+
+		AT_ROOT_CATEGORY = 9,
+			// A user's root inventory category.
+			// We decided to expose it visually, so it seems logical to fold
+			// it into the asset types.
+
+		AT_LSL_TEXT = 10,
+		AT_LSL_BYTECODE = 11,
+			// The LSL is the scripting language. 
+			// We've split it into a text and bytecode representation.
+		
+		AT_TEXTURE_TGA = 12,
+			// Uncompressed TGA texture.
+
+		AT_BODYPART = 13,
+			// A collection of textures and parameters that can be worn by an avatar.
+
+		AT_TRASH = 14,
+			// Only to be used as a marker for a category preferred type. 
+			// Using this, we can throw things in the trash before completely deleting.
+
+		AT_SNAPSHOT_CATEGORY = 15,
+			// A marker for a folder meant for snapshots. 
+			// No actual assets will be snapshots, though if there were, you
+			// could interpret them as textures.
+
+		AT_LOST_AND_FOUND = 16,
+			// Used to stuff lost&found items into.
+
+		AT_SOUND_WAV = 17,
+			// Uncompressed sound.
+
+		AT_IMAGE_TGA = 18,
+			// Uncompressed image, non-square.
+			// Not appropriate for use as a texture.
+
+		AT_IMAGE_JPEG = 19,
+			// Compressed image, non-square.
+			// Not appropriate for use as a texture.
+
+		AT_ANIMATION = 20,
+			// Animation.
+
+		AT_GESTURE = 21,
+			// Gesture, sequence of animations, sounds, chat, wait steps.
+
+		AT_SIMSTATE = 22,
+			// Simstate file.
+
+		AT_FAVORITE = 23,
+			// favorite items
+
+		AT_LINK = 24,
+			// Inventory symbolic link
+
+		AT_LINK_FOLDER = 25,
+			// Inventory folder link
+
+		AT_FOLDER_ENSEMBLE_START = 26,
+		AT_FOLDER_ENSEMBLE_END = 45,
+			// This range is reserved for special clothing folder types.
+
+		AT_CURRENT_OUTFIT = 46,
+			// Current outfit
+
+		AT_OUTFIT = 47,
+			// Predefined outfit ("look")
+
+		AT_MY_OUTFITS = 48,
+			// Folder that holds your outfits.
+
+		
+		AT_COUNT = 49,
+
+			// +*********************************************************+
+			// |  TO ADD AN ELEMENT TO THIS ENUM:                        |
+			// +*********************************************************+
+			// | 1. INSERT BEFORE AT_COUNT                               |
+			// | 2. INCREMENT AT_COUNT BY 1                              |
+			// | 3. ADD TO LLAssetDictionary in LLAssetType.cpp          |
+			// | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp  |
+			// +*********************************************************+
+
+		AT_NONE = -1
+	};
+
+	// machine transation between type and strings
+	static EType 				lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
+	static EType 				lookup(const std::string& type_name);
+	static const char*			lookup(EType asset_type);
+
+	// translation from a type to a human readable form.
+	static EType 				lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate
+	static EType 				lookupHumanReadable(const std::string& readable_name);
+	static const char*			lookupHumanReadable(EType asset_type);
+
+	// Generate a good default description. You may want to add a verb
+	// or agent name after this depending on your application.
+	static void 				generateDescriptionFor(LLAssetType::EType asset_type,
+													   std::string& description);
+
+	static EType 				getType(const std::string& desc_name);
+	static const std::string&	getDesc(EType asset_type);
+	static EDragAndDropType   	lookupDragAndDropType(EType asset_type);
+
+	static bool 				lookupCanLink(EType asset_type);
+	static bool 				lookupIsLinkType(EType asset_type);
+
+	static const char*  		lookupCategoryName(EType asset_type);
+	static bool 				lookupIsProtectedCategoryType(EType asset_type);
+	static bool 				lookupIsEnsembleCategoryType(EType asset_type);
+
+	/* TODO: Change return types from "const char *" to "const std::string &".
+	This is fairly straightforward, but requires changing some calls to use .c_str().
+	e.g.:
+	-	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+	+	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str());
+	*/
+	
+private:
+	// don't instantiate or derive one of these objects
+	LLAssetType( void ) {}
+	~LLAssetType( void ) {}
+};
+
+#endif // LL_LLASSETTYPE_H
diff --git a/indra/llcommon/llbase32.h b/indra/llcommon/llbase32.h
index 63a93e11ab503a952156fcdf2f588afa6ce31239..0697f7b8e204d36c28b891dd3fea241958f0b99c 100644
--- a/indra/llcommon/llbase32.h
+++ b/indra/llcommon/llbase32.h
@@ -32,9 +32,9 @@
  */
 
 #ifndef LLBASE32_H
-#define LLBASE32_h
+#define LLBASE32_H
 
-class LLBase32
+class LL_COMMON_API LLBase32
 {
 public:
 	static std::string encode(const U8* input, size_t input_size);
diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h
index 58414bba8bb980557679258220e837a6f9b9f9cc..c48fea24783716d397734260b27ce4e604a5124a 100644
--- a/indra/llcommon/llbase64.h
+++ b/indra/llcommon/llbase64.h
@@ -32,9 +32,9 @@
  */
 
 #ifndef LLBASE64_H
-#define LLBASE64_h
+#define LLBASE64_H
 
-class LLBase64
+class LL_COMMON_API LLBase64
 {
 public:
 	static std::string encode(const U8* input, size_t input_size);
diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h
index a1808e8a6c2dc54b535f93952a37f7de01862778..b36471f9f81cac843b35140ab7df4d1c0dd1c0f5 100644
--- a/indra/llcommon/llcommon.h
+++ b/indra/llcommon/llcommon.h
@@ -37,7 +37,7 @@
 #include "lltimer.h"
 #include "llfile.h"
 
-class LLCommon
+class LL_COMMON_API LLCommon
 {
 public:
 	static void initClass();
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..377bfaa247cd422edffc4db220c15c154ccc7103
--- /dev/null
+++ b/indra/llcommon/llcoros.cpp
@@ -0,0 +1,137 @@
+/**
+ * @file   llcoros.cpp
+ * @author Nat Goodspeed
+ * @date   2009-06-03
+ * @brief  Implementation for llcoros.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llcoros.h"
+// STL headers
+// std headers
+// external library headers
+#include <boost/bind.hpp>
+// other Linden headers
+#include "llevents.h"
+#include "llerror.h"
+#include "stringize.h"
+
+LLCoros::LLCoros()
+{
+    // Register our cleanup() method for "mainloop" ticks
+    LLEventPumps::instance().obtain("mainloop").listen(
+        "LLCoros", boost::bind(&LLCoros::cleanup, this, _1));
+}
+
+bool LLCoros::cleanup(const LLSD&)
+{
+    // Walk the mCoros map, checking and removing completed coroutines.
+    for (CoroMap::iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; )
+    {
+        // Has this coroutine exited (normal return, exception, exit() call)
+        // since last tick?
+        if (mi->second->exited())
+        {
+            LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
+            // The erase() call will invalidate its passed iterator value --
+            // so increment mi FIRST -- but pass its original value to
+            // erase(). This is what postincrement is all about.
+            mCoros.erase(mi++);
+        }
+        else
+        {
+            // Still live, just skip this entry as if incrementing at the top
+            // of the loop as usual.
+            ++mi;
+        }
+    }
+    return false;
+}
+
+std::string LLCoros::generateDistinctName(const std::string& prefix) const
+{
+    // Allowing empty name would make getName()'s not-found return ambiguous.
+    if (prefix.empty())
+    {
+        LL_ERRS("LLCoros") << "LLCoros::launch(): pass non-empty name string" << LL_ENDL;
+    }
+
+    // If the specified name isn't already in the map, just use that.
+    std::string name(prefix);
+
+    // Find the lowest numeric suffix that doesn't collide with an existing
+    // entry. Start with 2 just to make it more intuitive for any interested
+    // parties: e.g. "joe", "joe2", "joe3"...
+    for (int i = 2; ; name = STRINGIZE(prefix << i++))
+    {
+        if (mCoros.find(name) == mCoros.end())
+        {
+            LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
+            return name;
+        }
+    }
+}
+
+bool LLCoros::kill(const std::string& name)
+{
+    CoroMap::iterator found = mCoros.find(name);
+    if (found == mCoros.end())
+    {
+        return false;
+    }
+    // Because this is a boost::ptr_map, erasing the map entry also destroys
+    // the referenced heap object, in this case the boost::coroutine object,
+    // which will terminate the coroutine.
+    mCoros.erase(found);
+    return true;
+}
+
+std::string LLCoros::getNameByID(const void* self_id) const
+{
+    // Walk the existing coroutines, looking for one from which the 'self_id'
+    // passed to us comes.
+    for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi)
+    {
+        namespace coro_private = boost::coroutines::detail;
+        if (static_cast<void*>(coro_private::coroutine_accessor::get_impl(const_cast<coro&>(*mi->second)).get())
+            == self_id)
+        {
+            return mi->first;
+        }
+    }
+    return "";
+}
+
+/*****************************************************************************
+*   MUST BE LAST
+*****************************************************************************/
+// Turn off MSVC optimizations for just LLCoros::launchImpl() -- see
+// DEV-32777. But MSVC doesn't support push/pop for optimization flags as it
+// does for warning suppression, and we really don't want to force
+// optimization ON for other code even in Debug or RelWithDebInfo builds.
+
+#if LL_MSVC
+// work around broken optimizations
+#pragma warning(disable: 4748)
+#pragma optimize("", off)
+#endif // LL_MSVC
+
+std::string LLCoros::launchImpl(const std::string& prefix, coro* newCoro)
+{
+    std::string name(generateDistinctName(prefix));
+    mCoros.insert(name, newCoro);
+    /* Run the coroutine until its first wait, then return here */
+    (*newCoro)(std::nothrow);
+    return name;
+}
+
+#if LL_MSVC
+// reenable optimizations
+#pragma optimize("", on)
+#endif // LL_MSVC
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c5fa5af6d6884908d36fcbd64e0510a72de6a7d
--- /dev/null
+++ b/indra/llcommon/llcoros.h
@@ -0,0 +1,149 @@
+/**
+ * @file   llcoros.h
+ * @author Nat Goodspeed
+ * @date   2009-06-02
+ * @brief  Manage running boost::coroutine instances
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLCOROS_H)
+#define LL_LLCOROS_H
+
+#include <boost/coroutine/coroutine.hpp>
+#include "llsingleton.h"
+#include <boost/ptr_container/ptr_map.hpp>
+#include <string>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/iteration/local.hpp>
+#include <stdexcept>
+
+/**
+ * Registry of named Boost.Coroutine instances
+ *
+ * The Boost.Coroutine library supports the general case of a coroutine
+ * accepting arbitrary parameters and yielding multiple (sets of) results. For
+ * such use cases, it's natural for the invoking code to retain the coroutine
+ * instance: the consumer repeatedly calls into the coroutine, perhaps passing
+ * new parameter values, prompting it to yield its next result.
+ *
+ * Our typical coroutine usage is different, though. For us, coroutines
+ * provide an alternative to the @c Responder pattern. Our typical coroutine
+ * has @c void return, invoked in fire-and-forget mode: the handler for some
+ * user gesture launches the coroutine and promptly returns to the main loop.
+ * The coroutine initiates some action that will take multiple frames (e.g. a
+ * capability request), waits for its result, processes it and silently steals
+ * away.
+ *
+ * This usage poses two (related) problems:
+ *
+ * # Who should own the coroutine instance? If it's simply local to the
+ *   handler code that launches it, return from the handler will destroy the
+ *   coroutine object, terminating the coroutine.
+ * # Once the coroutine terminates, in whatever way, who's responsible for
+ *   cleaning up the coroutine object?
+ *
+ * LLCoros is a Singleton collection of currently-active coroutine instances.
+ * Each has a name. You ask LLCoros to launch a new coroutine with a suggested
+ * name prefix; from your prefix it generates a distinct name, registers the
+ * new coroutine and returns the actual name.
+ *
+ * The name can be used to kill off the coroutine prematurely, if needed. It
+ * can also provide diagnostic info: we can look up the name of the
+ * currently-running coroutine.
+ *
+ * Finally, the next frame ("mainloop" event) after the coroutine terminates,
+ * LLCoros will notice its demise and destroy it.
+ */
+class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
+{
+public:
+    /// Canonical boost::coroutines::coroutine signature we use
+    typedef boost::coroutines::coroutine<void()> coro;
+    /// Canonical 'self' type
+    typedef coro::self self;
+
+    /**
+     * Create and start running a new coroutine with specified name. The name
+     * string you pass is a suggestion; it will be tweaked for uniqueness. The
+     * actual name is returned to you.
+     *
+     * Usage looks like this, for (e.g.) two coroutine parameters:
+     * @code
+     * class MyClass
+     * {
+     * public:
+     *     ...
+     *     // Do NOT NOT NOT accept reference params other than 'self'!
+     *     // Pass by value only!
+     *     void myCoroutineMethod(LLCoros::self& self, std::string, LLSD);
+     *     ...
+     * };
+     * ...
+     * std::string name = LLCoros::instance().launch(
+     *    "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1,
+     *                          "somestring", LLSD(17));
+     * @endcode
+     *
+     * Your function/method must accept LLCoros::self& as its first parameter.
+     * It can accept any other parameters you want -- but ONLY BY VALUE!
+     * Other reference parameters are a BAD IDEA! You Have Been Warned. See
+     * DEV-32777 comments for an explanation.
+     *
+     * Pass a callable that accepts the single LLCoros::self& parameter. It
+     * may work to pass a free function whose only parameter is 'self'; for
+     * all other cases use boost::bind(). Of course, for a non-static class
+     * method, the first parameter must be the class instance. Use the
+     * placeholder _1 for the 'self' parameter. Any other parameters should be
+     * passed via the bind() expression.
+     *
+     * launch() tweaks the suggested name so it won't collide with any
+     * existing coroutine instance, creates the coroutine instance, registers
+     * it with the tweaked name and runs it until its first wait. At that
+     * point it returns the tweaked name.
+     */
+    template <typename CALLABLE>
+    std::string launch(const std::string& prefix, const CALLABLE& callable)
+    {
+        return launchImpl(prefix, new coro(callable));
+    }
+
+    /**
+     * Abort a running coroutine by name. Normally, when a coroutine either
+     * runs to completion or terminates with an exception, LLCoros quietly
+     * cleans it up. This is for use only when you must explicitly interrupt
+     * one prematurely. Returns @c true if the specified name was found and
+     * still running at the time.
+     */
+    bool kill(const std::string& name);
+
+    /**
+     * From within a coroutine, pass its @c self object to look up the
+     * (tweaked) name string by which this coroutine is registered. Returns
+     * the empty string if not found (e.g. if the coroutine was launched by
+     * hand rather than using LLCoros::launch()).
+     */
+    template <typename COROUTINE_SELF>
+    std::string getName(const COROUTINE_SELF& self) const
+    {
+        return getNameByID(self.get_id());
+    }
+
+    /// getName() by self.get_id()
+    std::string getNameByID(const void* self_id) const;
+
+private:
+    friend class LLSingleton<LLCoros>;
+    LLCoros();
+    std::string launchImpl(const std::string& prefix, coro* newCoro);
+    std::string generateDistinctName(const std::string& prefix) const;
+    bool cleanup(const LLSD&);
+
+    typedef boost::ptr_map<std::string, coro> CoroMap;
+    CoroMap mCoros;
+};
+
+#endif /* ! defined(LL_LLCOROS_H) */
diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h
index 27fae7d26979b280e1f4e8fd7c5b0ff13f97b146..74369062cc112d8a8e0c6f57ab4355ab3b6bc412 100644
--- a/indra/llcommon/llcrc.h
+++ b/indra/llcommon/llcrc.h
@@ -50,7 +50,7 @@
 //  llinfos << "File crc: " << crc.getCRC() << llendl;
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-class LLCRC
+class LL_COMMON_API LLCRC
 {
 protected:
 	U32 mCurrent;
diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h
index ad98284a6c59a1174d568e5b5b8c1cbe00b6642f..1ea5914b5b972978bbd6fe8e988639bb4a811923 100644
--- a/indra/llcommon/llcriticaldamp.h
+++ b/indra/llcommon/llcriticaldamp.h
@@ -38,7 +38,7 @@
 
 #include "llframetimer.h"
 
-class LLCriticalDamp 
+class LL_COMMON_API LLCriticalDamp 
 {
 public:
 	LLCriticalDamp();
diff --git a/indra/llcommon/llcursortypes.h b/indra/llcommon/llcursortypes.h
index 35dbeaf16e63ee9aa49117a273c45b38f88ecc7d..a1b8178bfe65365b4ca81e8881814be50f4b8f49 100644
--- a/indra/llcommon/llcursortypes.h
+++ b/indra/llcommon/llcursortypes.h
@@ -71,6 +71,6 @@ enum ECursorType {
 	UI_CURSOR_COUNT			// Number of elements in this enum (NOT a cursor)
 };
 
-ECursorType getCursorFromString(const std::string& cursor_string);
+LL_COMMON_API ECursorType getCursorFromString(const std::string& cursor_string);
 
 #endif // LL_LLCURSORTYPES_H
diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h
index 40b5f782d6bf7623a72bf1619f3c52967ff74f39..f8b2f2f163e825e1858bbdc52cd14c7ff8df3d67 100644
--- a/indra/llcommon/lldate.h
+++ b/indra/llcommon/lldate.h
@@ -46,7 +46,7 @@
  *
  * The date class represents a point in time after epoch - 1970-01-01.
  */
-class LLDate
+class LL_COMMON_API LLDate
 {
 public:
 	/** 
@@ -156,10 +156,10 @@ class LLDate
 };
 
 // Helper function to stream out a date
-std::ostream& operator<<(std::ostream& s, const LLDate& date);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLDate& date);
 
 // Helper function to stream in a date
-std::istream& operator>>(std::istream& s, LLDate& date);
+LL_COMMON_API std::istream& operator>>(std::istream& s, LLDate& date);
 
 
 
diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h
index 82f53c6e170f1126138df55a6e95ab70a57f3dfa..e6229db834a5f6aee83051f16641245bdd68722d 100644
--- a/indra/llcommon/lldependencies.h
+++ b/indra/llcommon/lldependencies.h
@@ -81,7 +81,7 @@ struct instance_from_range: public TYPE
  * LLDependencies components that should not be reinstantiated for each KEY,
  * NODE specialization
  */
-class LLDependenciesBase
+class LL_COMMON_API LLDependenciesBase
 {
 public:
     virtual ~LLDependenciesBase() {}
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 37e922d4b7131c2362dd2236c930de00b3c6ddc4..5a4c64485943cb139dc012b899cdbdf1127c12e9 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -131,7 +131,7 @@ namespace LLError
 	
 	class CallSite;
 	
-	class Log
+	class LL_COMMON_API Log
 	{
 	public:
 		static bool shouldLog(CallSite&);
@@ -140,7 +140,7 @@ namespace LLError
 		static void flush(std::ostringstream*, const CallSite&);
 	};
 	
-	class CallSite
+	class LL_COMMON_API CallSite
 	{
 		// Represents a specific place in the code where a message is logged
 		// This is public because it is used by the macros below.  It is not
@@ -189,7 +189,7 @@ namespace LLError
 	//LLCallStacks is designed not to be thread-safe.
    //so try not to use it in multiple parallel threads at same time.
    //Used in a single thread at a time is fine.
-   class LLCallStacks
+   class LL_COMMON_API LLCallStacks
    {
    private:
        static char**  sBuffer ;
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index fab0a1ef9f4466572425ab7476af4deffa9c1ec5..233e9d33892998a89091fed99f3c4d6c9cc9f945 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -63,12 +63,12 @@ class LLLineBuffer
 
 namespace LLError
 {
-	void initForServer(const std::string& identity);
+	LL_COMMON_API void initForServer(const std::string& identity);
 		// resets all logging settings to defaults needed by server processes
 		// logs to stderr, syslog, and windows debug log
 		// the identity string is used for in the syslog
 
-	void initForApplication(const std::string& dir);
+	LL_COMMON_API void initForApplication(const std::string& dir);
 		// resets all logging settings to defaults needed by applicaitons
 		// logs to stderr and windows debug log
 		// sets up log configuration from the file logcontrol.xml in dir
@@ -79,14 +79,14 @@ namespace LLError
 		Setting a level means log messages at that level or above.
 	*/
 	
-	void setPrintLocation(bool);
-	void setDefaultLevel(LLError::ELevel);
-	void setFunctionLevel(const std::string& function_name, LLError::ELevel);
-	void setClassLevel(const std::string& class_name, LLError::ELevel);
-	void setFileLevel(const std::string& file_name, LLError::ELevel);
-	void setTagLevel(const std::string& file_name, LLError::ELevel);
+	LL_COMMON_API void setPrintLocation(bool);
+	LL_COMMON_API void setDefaultLevel(LLError::ELevel);
+	LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel);
+	LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
+	LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
+	LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel);
 	
-	void configure(const LLSD&);
+	LL_COMMON_API void configure(const LLSD&);
 		// the LLSD can configure all of the settings
 		// usually read automatically from the live errorlog.xml file
 
@@ -96,21 +96,21 @@ namespace LLError
 	*/
 
 	typedef boost::function<void(const std::string&)> FatalFunction;
-	void crashAndLoop(const std::string& message);
+	LL_COMMON_API void crashAndLoop(const std::string& message);
 		// Default fatal function: access null pointer and loops forever
 
-	void setFatalFunction(const FatalFunction&);
+	LL_COMMON_API void setFatalFunction(const FatalFunction&);
 		// The fatal function will be called when an message of LEVEL_ERROR
 		// is logged.  Note: supressing a LEVEL_ERROR message from being logged
 		// (by, for example, setting a class level to LEVEL_NONE), will keep
 		// the that message from causing the fatal funciton to be invoked.
 
-    FatalFunction getFatalFunction();
+    LL_COMMON_API FatalFunction getFatalFunction();
         // Retrieve the previously-set FatalFunction
 
     /// temporarily override the FatalFunction for the duration of a
     /// particular scope, e.g. for unit tests
-    class OverrideFatalFunction
+    class LL_COMMON_API OverrideFatalFunction
     {
     public:
         OverrideFatalFunction(const FatalFunction& func):
@@ -128,15 +128,15 @@ namespace LLError
     };
 
 	typedef std::string (*TimeFunction)();
-	std::string utcTime();
+	LL_COMMON_API std::string utcTime();
 	
-	void setTimeFunction(TimeFunction);
+	LL_COMMON_API void setTimeFunction(TimeFunction);
 		// The function is use to return the current time, formatted for
 		// display by those error recorders that want the time included.
 
 
 
-	class Recorder
+	class LL_COMMON_API Recorder
 	{
 		// An object that handles the actual output or error messages.
 	public:
@@ -150,17 +150,17 @@ namespace LLError
 			// included in the text of the message
 	};
 	
-	void addRecorder(Recorder*);
-	void removeRecorder(Recorder*);
+	LL_COMMON_API void addRecorder(Recorder*);
+	LL_COMMON_API void removeRecorder(Recorder*);
 		// each error message is passed to each recorder via recordMessage()
 	
-	void logToFile(const std::string& filename);
-	void logToFixedBuffer(LLLineBuffer*);
+	LL_COMMON_API void logToFile(const std::string& filename);
+	LL_COMMON_API void logToFixedBuffer(LLLineBuffer*);
 		// Utilities to add recorders for logging to a file or a fixed buffer
 		// A second call to the same function will remove the logger added
 		// with the first.
 		// Passing the empty string or NULL to just removes any prior.
-	std::string logFileName();
+	LL_COMMON_API std::string logFileName();
 		// returns name of current logging file, empty string if none
 
 
@@ -169,11 +169,11 @@ namespace LLError
 	*/
 
 	class Settings;
-	Settings* saveAndResetSettings();
-	void restoreSettings(Settings *);
+	LL_COMMON_API Settings* saveAndResetSettings();
+	LL_COMMON_API void restoreSettings(Settings *);
 		
-	std::string abbreviateFile(const std::string& filePath);
-	int shouldLogCallCount();
+	LL_COMMON_API std::string abbreviateFile(const std::string& filePath);
+	LL_COMMON_API int shouldLogCallCount();
 	
 };
 
diff --git a/indra/llcommon/llerrorthread.h b/indra/llcommon/llerrorthread.h
index f1d6ffc34f5f05293861b0686939df9a613de359..3121d29675484ff079d536bda871ee1586157561 100644
--- a/indra/llcommon/llerrorthread.h
+++ b/indra/llcommon/llerrorthread.h
@@ -35,7 +35,7 @@
 
 #include "llthread.h"
 
-class LLErrorThread : public LLThread
+class LL_COMMON_API LLErrorThread : public LLThread
 {
 public:
 	LLErrorThread();
diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h
index 2cc8577219da76fe1e28ef9ef096782410d70f08..0ea7cf4ae83a1a3f07c3be770a8cbf2fda282bb3 100644
--- a/indra/llcommon/llevent.h
+++ b/indra/llcommon/llevent.h
@@ -47,7 +47,7 @@ class LLEventDispatcher;
 class LLObservable;
 
 // Abstract event. All events derive from LLEvent
-class LLEvent : public LLThreadSafeRefCount
+class LL_COMMON_API LLEvent : public LLThreadSafeRefCount
 {
 protected:
 	virtual ~LLEvent();
@@ -75,7 +75,7 @@ class LLEvent : public LLThreadSafeRefCount
 };
 
 // Abstract listener. All listeners derive from LLEventListener
-class LLEventListener : public LLThreadSafeRefCount
+class LL_COMMON_API LLEventListener : public LLThreadSafeRefCount
 {
 protected:
 	virtual ~LLEventListener();
@@ -92,7 +92,7 @@ class LLEventListener : public LLThreadSafeRefCount
 };
 
 // A listener which tracks references to it and cleans up when it's deallocated
-class LLSimpleListener : public LLEventListener
+class LL_COMMON_API LLSimpleListener : public LLEventListener
 {
 public:
 	void clearDispatchers();
@@ -117,7 +117,7 @@ struct LLListenerEntry
 // Base class for a dispatcher - an object which listens
 // to events being fired and relays them to their
 // appropriate destinations.
-class LLEventDispatcher : public LLThreadSafeRefCount
+class LL_COMMON_API LLEventDispatcher : public LLThreadSafeRefCount
 {
 protected:
 	virtual ~LLEventDispatcher();
@@ -160,7 +160,7 @@ class LLEventDispatcher : public LLThreadSafeRefCount
 // In order for this class to work properly, it needs
 // an instance of an LLEventDispatcher to route events to their
 // listeners.
-class LLObservable
+class LL_COMMON_API LLObservable
 {
 public:
 	// Initialize with the default Dispatcher
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d598f1cc4a80a2b7e95f1c17344c2a188e9abafd
--- /dev/null
+++ b/indra/llcommon/lleventcoro.cpp
@@ -0,0 +1,129 @@
+/**
+ * @file   lleventcoro.cpp
+ * @author Nat Goodspeed
+ * @date   2009-04-29
+ * @brief  Implementation for lleventcoro.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventcoro.h"
+// STL headers
+#include <map>
+// std headers
+// external library headers
+// other Linden headers
+#include "llsdserialize.h"
+#include "llerror.h"
+#include "llcoros.h"
+
+std::string LLEventDetail::listenerNameForCoroImpl(const void* self_id)
+{
+    // First, if this coroutine was launched by LLCoros::launch(), find that name.
+    std::string name(LLCoros::instance().getNameByID(self_id));
+    if (! name.empty())
+    {
+        return name;
+    }
+    // Apparently this coroutine wasn't launched by LLCoros::launch(). Check
+    // whether we have a memo for this self_id.
+    typedef std::map<const void*, std::string> MapType;
+    static MapType memo;
+    MapType::const_iterator found = memo.find(self_id);
+    if (found != memo.end())
+    {
+        // this coroutine instance has called us before, reuse same name
+        return found->second;
+    }
+    // this is the first time we've been called for this coroutine instance
+    name = LLEventPump::inventName("coro");
+    memo[self_id] = name;
+    LL_INFOS("LLEventCoro") << "listenerNameForCoroImpl(" << self_id << "): inventing coro name '"
+                            << name << "'" << LL_ENDL;
+    return name;
+}
+
+void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)
+{
+    if (rawPath.isUndefined())
+    {
+        // no-op case
+        return;
+    }
+
+    // Arrange to treat rawPath uniformly as an array. If it's not already an
+    // array, store it as the only entry in one.
+    LLSD path;
+    if (rawPath.isArray())
+    {
+        path = rawPath;
+    }
+    else
+    {
+        path.append(rawPath);
+    }
+
+    // Need to indicate a current destination -- but that current destination
+    // needs to change as we step through the path array. Where normally we'd
+    // use an LLSD& to capture a subscripted LLSD lvalue, this time we must
+    // instead use a pointer -- since it must be reassigned.
+    LLSD* pdest = &dest;
+
+    // Now loop through that array
+    for (LLSD::Integer i = 0; i < path.size(); ++i)
+    {
+        if (path[i].isString())
+        {
+            // *pdest is an LLSD map
+            pdest = &((*pdest)[path[i].asString()]);
+        }
+        else if (path[i].isInteger())
+        {
+            // *pdest is an LLSD array
+            pdest = &((*pdest)[path[i].asInteger()]);
+        }
+        else
+        {
+            // What do we do with Real or Array or Map or ...?
+            // As it's a coder error -- not a user error -- rub the coder's
+            // face in it so it gets fixed.
+            LL_ERRS("lleventcoro") << "storeToLLSDPath(" << dest << ", " << rawPath << ", " << value
+                                   << "): path[" << i << "] bad type " << path[i].type() << LL_ENDL;
+        }
+    }
+
+    // Here *pdest is where we should store value.
+    *pdest = value;
+}
+
+LLSD errorException(const LLEventWithID& result, const std::string& desc)
+{
+    // If the result arrived on the error pump (pump 1), instead of
+    // returning it, deliver it via exception.
+    if (result.second)
+    {
+        throw LLErrorEvent(desc, result.first);
+    }
+    // That way, our caller knows a simple return must be from the reply
+    // pump (pump 0).
+    return result.first;
+}
+
+LLSD errorLog(const LLEventWithID& result, const std::string& desc)
+{
+    // If the result arrived on the error pump (pump 1), log it as a fatal
+    // error.
+    if (result.second)
+    {
+        LL_ERRS("errorLog") << desc << ":" << std::endl;
+        LLSDSerialize::toPrettyXML(result.first, LL_CONT);
+        LL_CONT << LL_ENDL;
+    }
+    // A simple return must therefore be from the reply pump (pump 0).
+    return result.first;
+}
diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h
new file mode 100644
index 0000000000000000000000000000000000000000..c6d9de171d29f0f5a185bb60c1f48ab407867dd1
--- /dev/null
+++ b/indra/llcommon/lleventcoro.h
@@ -0,0 +1,549 @@
+/**
+ * @file   lleventcoro.h
+ * @author Nat Goodspeed
+ * @date   2009-04-29
+ * @brief  Utilities to interface between coroutines and events.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLEVENTCORO_H)
+#define LL_LLEVENTCORO_H
+
+#include <boost/coroutine/coroutine.hpp>
+#include <boost/coroutine/future.hpp>
+#include <boost/optional.hpp>
+#include <string>
+#include <stdexcept>
+#include "llevents.h"
+#include "llerror.h"
+
+/**
+ * Like LLListenerOrPumpName, this is a class intended for parameter lists:
+ * accept a <tt>const LLEventPumpOrPumpName&</tt> and you can accept either an
+ * <tt>LLEventPump&</tt> or its string name. For a single parameter that could
+ * be either, it's not hard to overload the function -- but as soon as you
+ * want to accept two such parameters, this is cheaper than four overloads.
+ */
+class LLEventPumpOrPumpName
+{
+public:
+    /// Pass an actual LLEventPump&
+    LLEventPumpOrPumpName(LLEventPump& pump):
+        mPump(pump)
+    {}
+    /// Pass the string name of an LLEventPump
+    LLEventPumpOrPumpName(const std::string& pumpname):
+        mPump(LLEventPumps::instance().obtain(pumpname))
+    {}
+    /// Pass string constant name of an LLEventPump. This override must be
+    /// explicit, since otherwise passing <tt>const char*</tt> to a function
+    /// accepting <tt>const LLEventPumpOrPumpName&</tt> would require two
+    /// different implicit conversions: <tt>const char*</tt> -> <tt>const
+    /// std::string&</tt> -> <tt>const LLEventPumpOrPumpName&</tt>.
+    LLEventPumpOrPumpName(const char* pumpname):
+        mPump(LLEventPumps::instance().obtain(pumpname))
+    {}
+    /// Unspecified: "I choose not to identify an LLEventPump."
+    LLEventPumpOrPumpName() {}
+    operator LLEventPump& () const { return *mPump; }
+    LLEventPump& getPump() const { return *mPump; }
+    operator bool() const { return mPump; }
+    bool operator!() const { return ! mPump; }
+
+private:
+    boost::optional<LLEventPump&> mPump;
+};
+
+/// This is an adapter for a signature like void LISTENER(const LLSD&), which
+/// isn't a valid LLEventPump listener: such listeners should return bool.
+template <typename LISTENER>
+class LLVoidListener
+{
+public:
+    LLVoidListener(const LISTENER& listener):
+        mListener(listener)
+    {}
+    bool operator()(const LLSD& event)
+    {
+        mListener(event);
+        // don't swallow the event, let other listeners see it
+        return false;
+    }
+private:
+    LISTENER mListener;
+};
+
+/// LLVoidListener helper function to infer the type of the LISTENER
+template <typename LISTENER>
+LLVoidListener<LISTENER> voidlistener(const LISTENER& listener)
+{
+    return LLVoidListener<LISTENER>(listener);
+}
+
+namespace LLEventDetail
+{
+    /**
+     * waitForEventOn() permits a coroutine to temporarily listen on an
+     * LLEventPump any number of times. We don't really want to have to ask
+     * the caller to label each such call with a distinct string; the whole
+     * point of waitForEventOn() is to present a nice sequential interface to
+     * the underlying LLEventPump-with-named-listeners machinery. So we'll use
+     * LLEventPump::inventName() to generate a distinct name for each
+     * temporary listener. On the other hand, because a given coroutine might
+     * call waitForEventOn() any number of times, we don't really want to
+     * consume an arbitrary number of generated inventName()s: that namespace,
+     * though large, is nonetheless finite. So we memoize an invented name for
+     * each distinct coroutine instance (each different 'self' object). We
+     * can't know the type of 'self', because it depends on the coroutine
+     * body's signature. So we cast its address to void*, looking for distinct
+     * pointer values. Yes, that means that an early coroutine could cache a
+     * value here, then be destroyed, only to be supplanted by a later
+     * coroutine (of the same or different type), and we'll end up
+     * "recognizing" the second one and reusing the listener name -- but
+     * that's okay, since it won't collide with any listener name used by the
+     * earlier coroutine since that earlier coroutine no longer exists.
+     */
+    template <typename COROUTINE_SELF>
+    std::string listenerNameForCoro(COROUTINE_SELF& self)
+    {
+        return listenerNameForCoroImpl(self.get_id());
+    }
+
+    /// Implementation for listenerNameForCoro()
+    LL_COMMON_API std::string listenerNameForCoroImpl(const void* self_id);
+
+    /**
+     * Implement behavior described for postAndWait()'s @a replyPumpNamePath
+     * parameter:
+     *
+     * * If <tt>path.isUndefined()</tt>, do nothing.
+     * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value
+     *   into <tt>dest[path.asString()]</tt>.
+     * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a
+     *   value into <tt>dest[path.asInteger()]</tt>.
+     * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step
+     *   down through the structure of @a dest. The last array entry in @a
+     *   path specifies the entry in the lowest-level structure in @a dest
+     *   into which to store @a value.
+     *
+     * @note
+     * In the degenerate case in which @a path is an empty array, @a dest will
+     * @em become @a value rather than @em containing it.
+     */
+    LL_COMMON_API void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value);
+} // namespace LLEventDetail
+
+/**
+ * Post specified LLSD event on the specified LLEventPump, then wait for a
+ * response on specified other LLEventPump. This is more than mere
+ * convenience: the difference between this function and the sequence
+ * @code
+ * requestPump.post(myEvent);
+ * LLSD reply = waitForEventOn(self, replyPump);
+ * @endcode
+ * is that the sequence above fails if the reply is posted immediately on
+ * @a replyPump, that is, before <tt>requestPump.post()</tt> returns. In the
+ * sequence above, the running coroutine isn't even listening on @a replyPump
+ * until <tt>requestPump.post()</tt> returns and @c waitForEventOn() is
+ * entered. Therefore, the coroutine completely misses an immediate reply
+ * event, making it wait indefinitely.
+ *
+ * By contrast, postAndWait() listens on the @a replyPump @em before posting
+ * the specified LLSD event on the specified @a requestPump.
+ *
+ * @param self The @c self object passed into a coroutine
+ * @param event LLSD data to be posted on @a requestPump
+ * @param requestPump an LLEventPump on which to post @a event. Pass either
+ * the LLEventPump& or its string name. However, if you pass a
+ * default-constructed @c LLEventPumpOrPumpName, we skip the post() call.
+ * @param replyPump an LLEventPump on which postAndWait() will listen for a
+ * reply. Pass either the LLEventPump& or its string name. The calling
+ * coroutine will wait until that reply arrives. (If you're concerned about a
+ * reply that might not arrive, please see also LLEventTimeout.)
+ * @param replyPumpNamePath specifies the location within @a event in which to
+ * store <tt>replyPump.getName()</tt>. This is a strictly optional convenience
+ * feature; obviously you can store the name in @a event "by hand" if desired.
+ * @a replyPumpNamePath can be specified in any of four forms:
+ * * @c isUndefined() (default-constructed LLSD object): do nothing. This is
+ *   the default behavior if you omit @a replyPumpNamePath.
+ * * @c isInteger(): @a event is an array. Store <tt>replyPump.getName()</tt>
+ *   in <tt>event[replyPumpNamePath.asInteger()]</tt>.
+ * * @c isString(): @a event is a map. Store <tt>replyPump.getName()</tt> in
+ *   <tt>event[replyPumpNamePath.asString()]</tt>.
+ * * @c isArray(): @a event has several levels of structure, e.g. map of
+ *   maps, array of arrays, array of maps, map of arrays, ... Store
+ *   <tt>replyPump.getName()</tt> in
+ *   <tt>event[replyPumpNamePath[0]][replyPumpNamePath[1]]...</tt> In other
+ *   words, examine each array entry in @a replyPumpNamePath in turn. If it's an
+ *   <tt>LLSD::String</tt>, the current level of @a event is a map; step down to
+ *   that map entry. If it's an <tt>LLSD::Integer</tt>, the current level of @a
+ *   event is an array; step down to that array entry. The last array entry in
+ *   @a replyPumpNamePath specifies the entry in the lowest-level structure in
+ *   @a event into which to store <tt>replyPump.getName()</tt>.
+ */
+template <typename SELF>
+LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+                 const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD())
+{
+    // declare the future
+    boost::coroutines::future<LLSD> future(self);
+    // make a callback that will assign a value to the future, and listen on
+    // the specified LLEventPump with that callback
+    std::string listenerName(LLEventDetail::listenerNameForCoro(self));
+    LLTempBoundListener connection(
+        replyPump.getPump().listen(listenerName,
+                                   voidlistener(boost::coroutines::make_callback(future))));
+    // skip the "post" part if requestPump is default-constructed
+    if (requestPump)
+    {
+        // If replyPumpNamePath is non-empty, store the replyPump name in the
+        // request event.
+        LLSD modevent(event);
+        LLEventDetail::storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName());
+        LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+                                 << " posting to " << requestPump.getPump().getName()
+                                 << ": " << modevent << LL_ENDL;
+        requestPump.getPump().post(modevent);
+    }
+    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+                             << " about to wait on LLEventPump " << replyPump.getPump().getName()
+                             << LL_ENDL;
+    // trying to dereference ("resolve") the future makes us wait for it
+    LLSD value(*future);
+    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+                             << " resuming with " << value << LL_ENDL;
+    // returning should disconnect the connection
+    return value;
+}
+
+/// Wait for the next event on the specified LLEventPump. Pass either the
+/// LLEventPump& or its string name.
+template <typename SELF>
+LLSD waitForEventOn(SELF& self, const LLEventPumpOrPumpName& pump)
+{
+    // This is now a convenience wrapper for postAndWait().
+    return postAndWait(self, LLSD(), LLEventPumpOrPumpName(), pump);
+}
+
+/// return type for two-pump variant of waitForEventOn()
+typedef std::pair<LLSD, int> LLEventWithID;
+
+namespace LLEventDetail
+{
+    /**
+     * This helper is specifically for the two-pump version of waitForEventOn().
+     * We use a single future object, but we want to listen on two pumps with it.
+     * Since we must still adapt from (the callable constructed by)
+     * boost::coroutines::make_callback() (void return) to provide an event
+     * listener (bool return), we've adapted LLVoidListener for the purpose. The
+     * basic idea is that we construct a distinct instance of WaitForEventOnHelper
+     * -- binding different instance data -- for each of the pumps. Then, when a
+     * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine
+     * that LLSD with its discriminator to feed the future object.
+     */
+    template <typename LISTENER>
+    class WaitForEventOnHelper
+    {
+    public:
+        WaitForEventOnHelper(const LISTENER& listener, int discriminator):
+            mListener(listener),
+            mDiscrim(discriminator)
+        {}
+        // this signature is required for an LLEventPump listener
+        bool operator()(const LLSD& event)
+        {
+            // our future object is defined to accept LLEventWithID
+            mListener(LLEventWithID(event, mDiscrim));
+            // don't swallow the event, let other listeners see it
+            return false;
+        }
+    private:
+        LISTENER mListener;
+        const int mDiscrim;
+    };
+
+    /// WaitForEventOnHelper type-inference helper
+    template <typename LISTENER>
+    WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator)
+    {
+        return WaitForEventOnHelper<LISTENER>(listener, discriminator);
+    }
+} // namespace LLEventDetail
+
+/**
+ * This function waits for a reply on either of two specified LLEventPumps.
+ * Otherwise, it closely resembles postAndWait(); please see the documentation
+ * for that function for detailed parameter info.
+ *
+ * While we could have implemented the single-pump variant in terms of this
+ * one, there's enough added complexity here to make it worthwhile to give the
+ * single-pump variant its own straightforward implementation. Conversely,
+ * though we could use preprocessor logic to generate n-pump overloads up to
+ * BOOST_COROUTINE_WAIT_MAX, we don't foresee a use case. This two-pump
+ * overload exists because certain event APIs are defined in terms of a reply
+ * LLEventPump and an error LLEventPump.
+ *
+ * The LLEventWithID return value provides not only the received event, but
+ * the index of the pump on which it arrived (0 or 1).
+ *
+ * @note
+ * I'd have preferred to overload the name postAndWait() for both signatures.
+ * But consider the following ambiguous call:
+ * @code
+ * postAndWait(self, LLSD(), requestPump, replyPump, "someString");
+ * @endcode
+ * "someString" could be converted to either LLSD (@a replyPumpNamePath for
+ * the single-pump function) or LLEventOrPumpName (@a replyPump1 for two-pump
+ * function).
+ *
+ * It seems less burdensome to write postAndWait2() than to write either
+ * LLSD("someString") or LLEventOrPumpName("someString").
+ */
+template <typename SELF>
+LLEventWithID postAndWait2(SELF& self, const LLSD& event,
+                           const LLEventPumpOrPumpName& requestPump,
+                           const LLEventPumpOrPumpName& replyPump0,
+                           const LLEventPumpOrPumpName& replyPump1,
+                           const LLSD& replyPump0NamePath=LLSD(),
+                           const LLSD& replyPump1NamePath=LLSD())
+{
+    // declare the future
+    boost::coroutines::future<LLEventWithID> future(self);
+    // either callback will assign a value to this future; listen on
+    // each specified LLEventPump with a callback
+    std::string name(LLEventDetail::listenerNameForCoro(self));
+    LLTempBoundListener connection0(
+        replyPump0.getPump().listen(name + "a",
+                               LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 0)));
+    LLTempBoundListener connection1(
+        replyPump1.getPump().listen(name + "b",
+                               LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 1)));
+    // skip the "post" part if requestPump is default-constructed
+    if (requestPump)
+    {
+        // If either replyPumpNamePath is non-empty, store the corresponding
+        // replyPump name in the request event.
+        LLSD modevent(event);
+        LLEventDetail::storeToLLSDPath(modevent, replyPump0NamePath,
+                                       replyPump0.getPump().getName());
+        LLEventDetail::storeToLLSDPath(modevent, replyPump1NamePath,
+                                       replyPump1.getPump().getName());
+        LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
+                                 << " posting to " << requestPump.getPump().getName()
+                                 << ": " << modevent << LL_ENDL;
+        requestPump.getPump().post(modevent);
+    }
+    LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
+                             << " about to wait on LLEventPumps " << replyPump0.getPump().getName()
+                             << ", " << replyPump1.getPump().getName() << LL_ENDL;
+    // trying to dereference ("resolve") the future makes us wait for it
+    LLEventWithID value(*future);
+    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name
+                             << " resuming with (" << value.first << ", " << value.second << ")"
+                             << LL_ENDL;
+    // returning should disconnect both connections
+    return value;
+}
+
+/**
+ * Wait for the next event on either of two specified LLEventPumps.
+ */
+template <typename SELF>
+LLEventWithID
+waitForEventOn(SELF& self,
+               const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)
+{
+    // This is now a convenience wrapper for postAndWait2().
+    return postAndWait2(self, LLSD(), LLEventPumpOrPumpName(), pump0, pump1);
+}
+
+/**
+ * Helper for the two-pump variant of waitForEventOn(), e.g.:
+ *
+ * @code
+ * LLSD reply = errorException(waitForEventOn(self, replyPump, errorPump),
+ *                             "error response from login.cgi");
+ * @endcode
+ *
+ * Examines an LLEventWithID, assuming that the second pump (pump 1) is
+ * listening for an error indication. If the incoming data arrived on pump 1,
+ * throw an LLErrorEvent exception. If the incoming data arrived on pump 0,
+ * just return it. Since a normal return can only be from pump 0, we no longer
+ * need the LLEventWithID's discriminator int; we can just return the LLSD.
+ *
+ * @note I'm not worried about introducing the (fairly generic) name
+ * errorException() into global namespace, because how many other overloads of
+ * the same name are going to accept an LLEventWithID parameter?
+ */
+LLSD errorException(const LLEventWithID& result, const std::string& desc);
+
+/**
+ * Exception thrown by errorException(). We don't call this LLEventError
+ * because it's not an error in event processing: rather, this exception
+ * announces an event that bears error information (for some other API).
+ */
+class LL_COMMON_API LLErrorEvent: public std::runtime_error
+{
+public:
+    LLErrorEvent(const std::string& what, const LLSD& data):
+        std::runtime_error(what),
+        mData(data)
+    {}
+    virtual ~LLErrorEvent() throw() {}
+
+    LLSD getData() const { return mData; }
+
+private:
+    LLSD mData;
+};
+
+/**
+ * Like errorException(), save that this trips a fatal error using LL_ERRS
+ * rather than throwing an exception.
+ */
+LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc);
+
+/**
+ * Certain event APIs require the name of an LLEventPump on which they should
+ * post results. While it works to invent a distinct name and let
+ * LLEventPumps::obtain() instantiate the LLEventPump as a "named singleton,"
+ * in a certain sense it's more robust to instantiate a local LLEventPump and
+ * provide its name instead. This class packages the following idiom:
+ *
+ * 1. Instantiate a local LLCoroEventPump, with an optional name prefix.
+ * 2. Provide its actual name to the event API in question as the name of the
+ *    reply LLEventPump.
+ * 3. Initiate the request to the event API.
+ * 4. Call your LLEventTempStream's wait() method to wait for the reply.
+ * 5. Let the LLCoroEventPump go out of scope.
+ */
+class LL_COMMON_API LLCoroEventPump
+{
+public:
+    LLCoroEventPump(const std::string& name="coro"):
+        mPump(name, true)           // allow tweaking the pump instance name
+    {}
+    /// It's typical to request the LLEventPump name to direct an event API to
+    /// send its response to this pump.
+    std::string getName() const { return mPump.getName(); }
+    /// Less typically, we'd request the pump itself for some reason.
+    LLEventPump& getPump() { return mPump; }
+
+    /**
+     * Wait for an event on this LLEventPump.
+     *
+     * @note
+     * The other major usage pattern we considered was to bind @c self at
+     * LLCoroEventPump construction time, which would avoid passing the
+     * parameter to each wait() call. But if we were going to bind @c self as
+     * a class member, we'd need to specify a class template parameter
+     * indicating its type. The big advantage of passing it to the wait() call
+     * is that the type can be implicit.
+     */
+    template <typename SELF>
+    LLSD wait(SELF& self)
+    {
+        return waitForEventOn(self, mPump);
+    }
+
+    template <typename SELF>
+    LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+                     const LLSD& replyPumpNamePath=LLSD())
+    {
+        return ::postAndWait(self, event, requestPump, mPump, replyPumpNamePath);
+    }
+
+private:
+    LLEventStream mPump;
+};
+
+/**
+ * Other event APIs require the names of two different LLEventPumps: one for
+ * success response, the other for error response. Extend LLCoroEventPump
+ * for the two-pump use case.
+ */
+class LL_COMMON_API LLCoroEventPumps
+{
+public:
+    LLCoroEventPumps(const std::string& name="coro",
+                     const std::string& suff0="Reply",
+                     const std::string& suff1="Error"):
+        mPump0(name + suff0, true),   // allow tweaking the pump instance name
+        mPump1(name + suff1, true)
+    {}
+    /// request pump 0's name
+    std::string getName0() const { return mPump0.getName(); }
+    /// request pump 1's name
+    std::string getName1() const { return mPump1.getName(); }
+    /// request both names
+    std::pair<std::string, std::string> getNames() const
+    {
+        return std::pair<std::string, std::string>(mPump0.getName(), mPump1.getName());
+    }
+
+    /// request pump 0
+    LLEventPump& getPump0() { return mPump0; }
+    /// request pump 1
+    LLEventPump& getPump1() { return mPump1; }
+
+    /// waitForEventOn(self, either of our two LLEventPumps)
+    template <typename SELF>
+    LLEventWithID wait(SELF& self)
+    {
+        return waitForEventOn(self, mPump0, mPump1);
+    }
+
+    /// errorException(wait(self))
+    template <typename SELF>
+    LLSD waitWithException(SELF& self)
+    {
+        return errorException(wait(self), std::string("Error event on ") + getName1());
+    }
+
+    /// errorLog(wait(self))
+    template <typename SELF>
+    LLSD waitWithLog(SELF& self)
+    {
+        return errorLog(wait(self), std::string("Error event on ") + getName1());
+    }
+
+    template <typename SELF>
+    LLEventWithID postAndWait(SELF& self, const LLSD& event,
+                              const LLEventPumpOrPumpName& requestPump,
+                              const LLSD& replyPump0NamePath=LLSD(),
+                              const LLSD& replyPump1NamePath=LLSD())
+    {
+        return postAndWait2(self, event, requestPump, mPump0, mPump1,
+                            replyPump0NamePath, replyPump1NamePath);
+    }
+
+    template <typename SELF>
+    LLSD postAndWaitWithException(SELF& self, const LLSD& event,
+                                  const LLEventPumpOrPumpName& requestPump,
+                                  const LLSD& replyPump0NamePath=LLSD(),
+                                  const LLSD& replyPump1NamePath=LLSD())
+    {
+        return errorException(postAndWait(self, event, requestPump,
+                                          replyPump0NamePath, replyPump1NamePath),
+                              std::string("Error event on ") + getName1());
+    }
+
+    template <typename SELF>
+    LLSD postAndWaitWithLog(SELF& self, const LLSD& event,
+                            const LLEventPumpOrPumpName& requestPump,
+                            const LLSD& replyPump0NamePath=LLSD(),
+                            const LLSD& replyPump1NamePath=LLSD())
+    {
+        return errorLog(postAndWait(self, event, requestPump,
+                                    replyPump0NamePath, replyPump1NamePath),
+                        std::string("Error event on ") + getName1());
+    }
+
+private:
+    LLEventStream mPump0, mPump1;
+};
+
+#endif /* ! defined(LL_LLEVENTCORO_H) */
diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6b1413d05494851ca76373a91ed5f3569e93df1b
--- /dev/null
+++ b/indra/llcommon/lleventdispatcher.cpp
@@ -0,0 +1,133 @@
+/**
+ * @file   lleventdispatcher.cpp
+ * @author Nat Goodspeed
+ * @date   2009-06-18
+ * @brief  Implementation for lleventdispatcher.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventdispatcher.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llevents.h"
+#include "llerror.h"
+#include "llsdutil.h"
+
+LLEventDispatcher::LLEventDispatcher(const std::string& desc, const std::string& key):
+    mDesc(desc),
+    mKey(key)
+{
+}
+
+LLEventDispatcher::~LLEventDispatcher()
+{
+}
+
+/// Register a callable by name
+void LLEventDispatcher::add(const std::string& name, const Callable& callable, const LLSD& required)
+{
+    mDispatch[name] = DispatchMap::mapped_type(callable, required);
+}
+
+void LLEventDispatcher::addFail(const std::string& name, const std::string& classname) const
+{
+    LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ")::add(" << name
+                                 << "): " << classname << " is not a subclass "
+                                 << "of LLEventDispatcher" << LL_ENDL;
+}
+
+/// Unregister a callable
+bool LLEventDispatcher::remove(const std::string& name)
+{
+    DispatchMap::iterator found = mDispatch.find(name);
+    if (found == mDispatch.end())
+    {
+        return false;
+    }
+    mDispatch.erase(found);
+    return true;
+}
+
+/// Call a registered callable with an explicitly-specified name. If no
+/// such callable exists, die with LL_ERRS.
+void LLEventDispatcher::operator()(const std::string& name, const LLSD& event) const
+{
+    if (! attemptCall(name, event))
+    {
+        LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): '" << name
+                                     << "' not found" << LL_ENDL;
+    }
+}
+
+/// Extract the @a key value from the incoming @a event, and call the
+/// callable whose name is specified by that map @a key. If no such
+/// callable exists, die with LL_ERRS.
+void LLEventDispatcher::operator()(const LLSD& event) const
+{
+    // This could/should be implemented in terms of the two-arg overload.
+    // However -- we can produce a more informative error message.
+    std::string name(event[mKey]);
+    if (! attemptCall(name, event))
+    {
+        LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): bad " << mKey
+                                     << " value '" << name << "'" << LL_ENDL;
+    }
+}
+
+bool LLEventDispatcher::attemptCall(const std::string& name, const LLSD& event) const
+{
+    DispatchMap::const_iterator found = mDispatch.find(name);
+    if (found == mDispatch.end())
+    {
+        // The reason we only return false, leaving it up to our caller to die
+        // with LL_ERRS, is that different callers have different amounts of
+        // available information.
+        return false;
+    }
+    // Found the name, so it's plausible to even attempt the call. But first,
+    // validate the syntax of the event itself.
+    std::string mismatch(llsd_matches(found->second.second, event));
+    if (! mismatch.empty())
+    {
+        LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ") calling '" << name
+                                     << "': bad request: " << mismatch << LL_ENDL;
+    }
+    // Event syntax looks good, go for it!
+    (found->second.first)(event);
+    return true;                    // tell caller we were able to call
+}
+
+LLEventDispatcher::Callable LLEventDispatcher::get(const std::string& name) const
+{
+    DispatchMap::const_iterator found = mDispatch.find(name);
+    if (found == mDispatch.end())
+    {
+        return Callable();
+    }
+    return found->second.first;
+}
+
+LLDispatchListener::LLDispatchListener(const std::string& pumpname, const std::string& key):
+    LLEventDispatcher(pumpname, key),
+    mPump(pumpname, true),          // allow tweaking for uniqueness
+    mBoundListener(mPump.listen("self", boost::bind(&LLDispatchListener::process, this, _1)))
+{
+}
+
+bool LLDispatchListener::process(const LLSD& event)
+{
+    (*this)(event);
+    return false;
+}
diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h
new file mode 100644
index 0000000000000000000000000000000000000000..671f2a4d1cf19944a659d9d3e21704db4485db63
--- /dev/null
+++ b/indra/llcommon/lleventdispatcher.h
@@ -0,0 +1,130 @@
+/**
+ * @file   lleventdispatcher.h
+ * @author Nat Goodspeed
+ * @date   2009-06-18
+ * @brief  Central mechanism for dispatching events by string name. This is
+ *         useful when you have a single LLEventPump listener on which you can
+ *         request different operations, vs. instantiating a different
+ *         LLEventPump for each such operation.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLEVENTDISPATCHER_H)
+#define LL_LLEVENTDISPATCHER_H
+
+#include <string>
+#include <map>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <typeinfo>
+#include "llevents.h"
+
+class LLSD;
+
+/**
+ * Given an LLSD map, examine a string-valued key and call a corresponding
+ * callable. This class is designed to be contained by an LLEventPump
+ * listener class that will register some of its own methods, though any
+ * callable can be used.
+ */
+class LL_COMMON_API LLEventDispatcher
+{
+public:
+    LLEventDispatcher(const std::string& desc, const std::string& key);
+    virtual ~LLEventDispatcher();
+
+    /// Accept any C++ callable, typically a boost::bind() expression
+    typedef boost::function<void(const LLSD&)> Callable;
+
+    /**
+     * Register a @a callable by @a name. The optional @a required parameter
+     * is used to validate the structure of each incoming event (see
+     * llsd_matches()).
+     */
+    void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD());
+
+    /**
+     * Special case: a subclass of this class can pass an unbound member
+     * function pointer without explicitly specifying the
+     * <tt>boost::bind()</tt> expression.
+     */
+    template <class CLASS>
+    void add(const std::string& name, void (CLASS::*method)(const LLSD&),
+             const LLSD& required=LLSD())
+    {
+        addMethod<CLASS>(name, method, required);
+    }
+
+    /// Overload for both const and non-const methods
+    template <class CLASS>
+    void add(const std::string& name, void (CLASS::*method)(const LLSD&) const,
+             const LLSD& required=LLSD())
+    {
+        addMethod<CLASS>(name, method, required);
+    }
+
+    /// Unregister a callable
+    bool remove(const std::string& name);
+
+    /// Call a registered callable with an explicitly-specified name. If no
+    /// such callable exists, die with LL_ERRS. If the @a event fails to match
+    /// the @a required prototype specified at add() time, die with LL_ERRS.
+    void operator()(const std::string& name, const LLSD& event) const;
+
+    /// Extract the @a key value from the incoming @a event, and call the
+    /// callable whose name is specified by that map @a key. If no such
+    /// callable exists, die with LL_ERRS. If the @a event fails to match the
+    /// @a required prototype specified at add() time, die with LL_ERRS.
+    void operator()(const LLSD& event) const;
+
+    /// Fetch the Callable for the specified name. If no such name was
+    /// registered, return an empty() Callable.
+    Callable get(const std::string& name) const;
+
+private:
+    template <class CLASS, typename METHOD>
+    void addMethod(const std::string& name, const METHOD& method, const LLSD& required)
+    {
+        CLASS* downcast = dynamic_cast<CLASS*>(this);
+        if (! downcast)
+        {
+            addFail(name, typeid(CLASS).name());
+        }
+        else
+        {
+            add(name, boost::bind(method, downcast, _1), required);
+        }
+    }
+    void addFail(const std::string& name, const std::string& classname) const;
+    /// try to dispatch, return @c true if success
+    bool attemptCall(const std::string& name, const LLSD& event) const;
+
+    std::string mDesc, mKey;
+    typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap;
+    DispatchMap mDispatch;
+};
+
+/**
+ * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
+ * that contains (or derives from) LLDispatchListener need only specify the
+ * LLEventPump name and dispatch key, and add() its methods. Incoming events
+ * will automatically be dispatched.
+ */
+class LL_COMMON_API LLDispatchListener: public LLEventDispatcher
+{
+public:
+    LLDispatchListener(const std::string& pumpname, const std::string& key);
+
+    std::string getPumpName() const { return mPump.getName(); }
+
+private:
+    bool process(const LLSD& event);
+
+    LLEventStream mPump;
+    LLTempBoundListener mBoundListener;
+};
+
+#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */
diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..74133781bef2503d05ba30f2a7e2509417d0c27f
--- /dev/null
+++ b/indra/llcommon/lleventfilter.cpp
@@ -0,0 +1,149 @@
+/**
+ * @file   lleventfilter.cpp
+ * @author Nat Goodspeed
+ * @date   2009-03-05
+ * @brief  Implementation for lleventfilter.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventfilter.h"
+// STL headers
+// std headers
+// external library headers
+#include <boost/bind.hpp>
+// other Linden headers
+#include "llerror.h"                // LL_ERRS
+#include "llsdutil.h"               // llsd_matches()
+
+LLEventFilter::LLEventFilter(LLEventPump& source, const std::string& name, bool tweak):
+    LLEventStream(name, tweak)
+{
+    source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1));
+}
+
+LLEventMatching::LLEventMatching(const LLSD& pattern):
+    LLEventFilter("matching"),
+    mPattern(pattern)
+{
+}
+
+LLEventMatching::LLEventMatching(LLEventPump& source, const LLSD& pattern):
+    LLEventFilter(source, "matching"),
+    mPattern(pattern)
+{
+}
+
+bool LLEventMatching::post(const LLSD& event)
+{
+    if (! llsd_matches(mPattern, event).empty())
+        return false;
+
+    return LLEventStream::post(event);
+}
+
+LLEventTimeoutBase::LLEventTimeoutBase():
+    LLEventFilter("timeout")
+{
+}
+
+LLEventTimeoutBase::LLEventTimeoutBase(LLEventPump& source):
+    LLEventFilter(source, "timeout")
+{
+}
+
+void LLEventTimeoutBase::actionAfter(F32 seconds, const Action& action)
+{
+    setCountdown(seconds);
+    mAction = action;
+    if (! mMainloop.connected())
+    {
+        LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
+        mMainloop = mainloop.listen(getName(), boost::bind(&LLEventTimeoutBase::tick, this, _1));
+    }
+}
+
+class ErrorAfter
+{
+public:
+    ErrorAfter(const std::string& message): mMessage(message) {}
+
+    void operator()()
+    {
+        LL_ERRS("LLEventTimeout") << mMessage << LL_ENDL;
+    }
+
+private:
+    std::string mMessage;
+};
+
+void LLEventTimeoutBase::errorAfter(F32 seconds, const std::string& message)
+{
+    actionAfter(seconds, ErrorAfter(message));
+}
+
+class EventAfter
+{
+public:
+    EventAfter(LLEventPump& pump, const LLSD& event):
+        mPump(pump),
+        mEvent(event)
+    {}
+
+    void operator()()
+    {
+        mPump.post(mEvent);
+    }
+
+private:
+    LLEventPump& mPump;
+    LLSD mEvent;
+};
+
+void LLEventTimeoutBase::eventAfter(F32 seconds, const LLSD& event)
+{
+    actionAfter(seconds, EventAfter(*this, event));
+}
+
+bool LLEventTimeoutBase::post(const LLSD& event)
+{
+    cancel();
+    return LLEventStream::post(event);
+}
+
+void LLEventTimeoutBase::cancel()
+{
+    mMainloop.disconnect();
+}
+
+bool LLEventTimeoutBase::tick(const LLSD&)
+{
+    if (countdownElapsed())
+    {
+        cancel();
+        mAction();
+    }
+    return false;                   // show event to other listeners
+}
+
+LLEventTimeout::LLEventTimeout() {}
+
+LLEventTimeout::LLEventTimeout(LLEventPump& source):
+    LLEventTimeoutBase(source)
+{
+}
+
+void LLEventTimeout::setCountdown(F32 seconds)
+{
+    mTimer.setTimerExpirySec(seconds);
+}
+
+bool LLEventTimeout::countdownElapsed() const
+{
+    return mTimer.hasExpired();
+}
diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..89f0c7ea43c9702663e53dfa4fa78f5e3a7ca3cf
--- /dev/null
+++ b/indra/llcommon/lleventfilter.h
@@ -0,0 +1,186 @@
+/**
+ * @file   lleventfilter.h
+ * @author Nat Goodspeed
+ * @date   2009-03-05
+ * @brief  Define LLEventFilter: LLEventStream subclass with conditions
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLEVENTFILTER_H)
+#define LL_LLEVENTFILTER_H
+
+#include "llevents.h"
+#include "stdtypes.h"
+#include "lltimer.h"
+#include <boost/function.hpp>
+
+/**
+ * Generic base class
+ */
+class LL_COMMON_API LLEventFilter: public LLEventStream
+{
+public:
+    /// construct a standalone LLEventFilter
+    LLEventFilter(const std::string& name="filter", bool tweak=true):
+        LLEventStream(name, tweak)
+    {}
+    /// construct LLEventFilter and connect it to the specified LLEventPump
+    LLEventFilter(LLEventPump& source, const std::string& name="filter", bool tweak=true);
+
+    /// Post an event to all listeners
+    virtual bool post(const LLSD& event) = 0;
+};
+
+/**
+ * Pass through only events matching a specified pattern
+ */
+class LLEventMatching: public LLEventFilter
+{
+public:
+    /// Pass an LLSD map with keys and values the incoming event must match
+    LLEventMatching(const LLSD& pattern);
+    /// instantiate and connect
+    LLEventMatching(LLEventPump& source, const LLSD& pattern);
+
+    /// Only pass through events matching the pattern
+    virtual bool post(const LLSD& event);
+
+private:
+    LLSD mPattern;
+};
+
+/**
+ * Wait for an event to be posted. If no such event arrives within a specified
+ * time, take a specified action. See LLEventTimeout for production
+ * implementation.
+ *
+ * @NOTE This is an abstract base class so that, for testing, we can use an
+ * alternate "timer" that doesn't actually consume real time.
+ */
+class LL_COMMON_API LLEventTimeoutBase: public LLEventFilter
+{
+public:
+    /// construct standalone
+    LLEventTimeoutBase();
+    /// construct and connect
+    LLEventTimeoutBase(LLEventPump& source);
+
+    /// Callable, can be constructed with boost::bind()
+    typedef boost::function<void()> Action;
+
+    /**
+     * Start countdown timer for the specified number of @a seconds. Forward
+     * all events. If any event arrives before timer expires, cancel timer. If
+     * no event arrives before timer expires, take specified @a action.
+     *
+     * This is a one-shot timer. Once it has either expired or been canceled,
+     * it is inert until another call to actionAfter().
+     *
+     * Calling actionAfter() while an existing timer is running cheaply
+     * replaces that original timer. Thus, a valid use case is to detect
+     * idleness of some event source by calling actionAfter() on each new
+     * event. A rapid sequence of events will keep the timer from expiring;
+     * the first gap in events longer than the specified timer will fire the
+     * specified Action.
+     *
+     * Any post() call cancels the timer. To be satisfied with only a
+     * particular event, chain on an LLEventMatching that only passes such
+     * events:
+     *
+     * @code
+     * event                                                 ultimate
+     * source ---> LLEventMatching ---> LLEventTimeout  ---> listener
+     * @endcode
+     *
+     * @NOTE
+     * The implementation relies on frequent events on the LLEventPump named
+     * "mainloop".
+     */
+    void actionAfter(F32 seconds, const Action& action);
+
+    /**
+     * Like actionAfter(), but where the desired Action is LL_ERRS
+     * termination. Pass the timeout time and the desired LL_ERRS @a message.
+     *
+     * This method is useful when, for instance, some async API guarantees an
+     * event, whether success or failure, within a stated time window.
+     * Instantiate an LLEventTimeout listening to that API and call
+     * errorAfter() on each async request with a timeout comfortably longer
+     * than the API's time guarantee (much longer than the anticipated
+     * "mainloop" granularity).
+     *
+     * Then if the async API breaks its promise, the program terminates with
+     * the specified LL_ERRS @a message. The client of the async API can
+     * therefore assume the guarantee is upheld.
+     *
+     * @NOTE
+     * errorAfter() is implemented in terms of actionAfter(), so all remarks
+     * about calling actionAfter() also apply to errorAfter().
+     */
+    void errorAfter(F32 seconds, const std::string& message);
+
+    /**
+     * Like actionAfter(), but where the desired Action is a particular event
+     * for all listeners. Pass the timeout time and the desired @a event data.
+     * 
+     * Suppose the timeout should only be satisfied by a particular event, but
+     * the ultimate listener must see all other incoming events as well, plus
+     * the timeout @a event if any:
+     * 
+     * @code
+     * some        LLEventMatching                           LLEventMatching
+     * event  ---> for particular  ---> LLEventTimeout  ---> for timeout
+     * source      event                                     event \
+     *       \                                                      \ ultimate
+     *        `-----------------------------------------------------> listener
+     * @endcode
+     * 
+     * Since a given listener can listen on more than one LLEventPump, we can
+     * set things up so it sees the set union of events from LLEventTimeout
+     * and the original event source. However, as LLEventTimeout passes
+     * through all incoming events, the "particular event" that satisfies the
+     * left LLEventMatching would reach the ultimate listener twice. So we add
+     * an LLEventMatching that only passes timeout events.
+     *
+     * @NOTE
+     * eventAfter() is implemented in terms of actionAfter(), so all remarks
+     * about calling actionAfter() also apply to eventAfter().
+     */
+    void eventAfter(F32 seconds, const LLSD& event);
+
+    /// Pass event through, canceling the countdown timer
+    virtual bool post(const LLSD& event);
+
+    /// Cancel timer without event
+    void cancel();
+
+protected:
+    virtual void setCountdown(F32 seconds) = 0;
+    virtual bool countdownElapsed() const = 0;
+
+private:
+    bool tick(const LLSD&);
+
+    LLBoundListener mMainloop;
+    Action mAction;
+};
+
+/// Production implementation of LLEventTimoutBase
+class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase
+{
+public:
+    LLEventTimeout();
+    LLEventTimeout(LLEventPump& source);
+
+protected:
+    virtual void setCountdown(F32 seconds);
+    virtual bool countdownElapsed() const;
+
+private:
+    LLTimer mTimer;
+};
+
+#endif /* ! defined(LL_LLEVENTFILTER_H) */
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index eb380ba7c8b04f02879fbb8bb3c95e01ed5801ea..4bdfe5a867be25aa69aab95d0b32d858491894e5 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -38,6 +38,12 @@
 #pragma warning (pop)
 #endif
 // other Linden headers
+#include "stringize.h"
+#include "llerror.h"
+#include "llsdutil.h"
+#if LL_MSVC
+#pragma warning (disable : 4702)
+#endif
 
 /*****************************************************************************
 *   queue_names: specify LLEventPump names that should be instantiated as
@@ -56,14 +62,12 @@ const char* queue_names[] =
 /*****************************************************************************
 *   If there's a "mainloop" pump, listen on that to flush all LLEventQueues
 *****************************************************************************/
-struct RegisterFlush
+struct RegisterFlush : public LLEventTrackable
 {
     RegisterFlush():
-        pumps(LLEventPumps::instance()),
-        mainloop(pumps.obtain("mainloop")),
-        name("flushLLEventQueues")
+        pumps(LLEventPumps::instance())
     {
-        mainloop.listen(name, boost::bind(&RegisterFlush::flush, this, _1));
+        pumps.obtain("mainloop").listen("flushLLEventQueues", boost::bind(&RegisterFlush::flush, this, _1));
     }
     bool flush(const LLSD&)
     {
@@ -72,11 +76,9 @@ struct RegisterFlush
     }
     ~RegisterFlush()
     {
-        mainloop.stopListening(name);
+        // LLEventTrackable handles stopListening for us.
     }
     LLEventPumps& pumps;
-    LLEventPump& mainloop;
-    const std::string name;
 };
 static RegisterFlush registerFlush;
 
@@ -124,6 +126,16 @@ void LLEventPumps::flush()
     }
 }
 
+void LLEventPumps::reset()
+{
+    // Reset every known LLEventPump instance. Leave it up to each instance to
+    // decide what to do with the reset() call.
+    for (PumpMap::iterator pmi = mPumpMap.begin(), pmend = mPumpMap.end(); pmi != pmend; ++pmi)
+    {
+        pmi->second->reset();
+    }
+}
+
 std::string LLEventPumps::registerNew(const LLEventPump& pump, const std::string& name, bool tweak)
 {
     std::pair<PumpMap::iterator, bool> inserted =
@@ -240,6 +252,7 @@ LLEventPumps::~LLEventPumps()
 LLEventPump::LLEventPump(const std::string& name, bool tweak):
     // Register every new instance with LLEventPumps
     mName(LLEventPumps::instance().registerNew(*this, name, tweak)),
+    mSignal(new LLStandardSignal()),
     mEnabled(true)
 {}
 
@@ -256,6 +269,19 @@ LLEventPump::~LLEventPump()
 // static data member
 const LLEventPump::NameList LLEventPump::empty;
 
+std::string LLEventPump::inventName(const std::string& pfx)
+{
+    static long suffix = 0;
+    return STRINGIZE(pfx << suffix++);
+}
+
+void LLEventPump::reset()
+{
+    mSignal.reset();
+    mConnections.clear();
+    //mDeps.clear();
+}
+
 LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventListener& listener,
                                          const NameList& after,
                                          const NameList& before)
@@ -397,7 +423,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
     }
     // Now that newNode has a value that places it appropriately in mSignal,
     // connect it.
-    LLBoundListener bound = mSignal.connect(newNode, listener);
+    LLBoundListener bound = mSignal->connect(newNode, listener);
     mConnections[name] = bound;
     return bound;
 }
@@ -437,7 +463,7 @@ bool LLEventStream::post(const LLSD& event)
     // Let caller know if any one listener handled the event. This is mostly
     // useful when using LLEventStream as a listener for an upstream
     // LLEventPump.
-    return mSignal(event);
+    return (*mSignal)(event);
 }
 
 /*****************************************************************************
@@ -468,7 +494,7 @@ void LLEventQueue::flush()
     mEventQueue.clear();
     for ( ; ! queue.empty(); queue.pop_front())
     {
-        mSignal(queue.front());
+        (*mSignal)(queue.front());
     }
 }
 
@@ -499,3 +525,26 @@ bool LLListenerOrPumpName::operator()(const LLSD& event) const
     }
     return (*mListener)(event);
 }
+
+void LLReqID::stamp(LLSD& response) const
+{
+    if (! (response.isUndefined() || response.isMap()))
+    {
+        // If 'response' was previously completely empty, it's okay to
+        // turn it into a map. If it was already a map, then it should be
+        // okay to add a key. But if it was anything else (e.g. a scalar),
+        // assigning a ["reqid"] key will DISCARD the previous value,
+        // replacing it with a map. That would be Bad.
+        LL_INFOS("LLReqID") << "stamp(" << mReqid << ") leaving non-map response unmodified: "
+                            << response << LL_ENDL;
+        return;
+    }
+    LLSD oldReqid(response["reqid"]);
+    if (! (oldReqid.isUndefined() || llsd_equals(oldReqid, mReqid)))
+    {
+        LL_INFOS("LLReqID") << "stamp(" << mReqid << ") preserving existing [\"reqid\"] value "
+                            << oldReqid << " in response: " << response << LL_ENDL;
+        return;
+    }
+    response["reqid"] = mReqid;
+}
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index 240adcdd411211db0f54c968b441bfe10b872a0b..64e5cb5da7f290134b89f988e806f71dcd16f0b0 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -1,831 +1,943 @@
-/**
- * @file   llevents.h
- * @author Kent Quirk, Nat Goodspeed
- * @date   2008-09-11
- * @brief  This is an implementation of the event system described at
- *         https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System,
- *         originally introduced in llnotifications.h. It has nothing
- *         whatsoever to do with the older system in llevent.h.
- * 
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- * Copyright (c) 2008, Linden Research, Inc.
- * $/LicenseInfo$
- */
-
-#if ! defined(LL_LLEVENTS_H)
-#define LL_LLEVENTS_H
-
-#include <string>
-#include <map>
-#include <set>
-#include <vector>
-#include <list>
-#include <deque>
-#include <stdexcept>
-#if LL_WINDOWS
-	#pragma warning (push)
-	#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
-	#pragma warning (disable : 4264) 
-#endif
-#include <boost/signals2.hpp>
-#if LL_WINDOWS
-	#pragma warning (pop)
-#endif
-
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/utility.hpp>        // noncopyable
-#include <boost/optional/optional.hpp>
-#include <boost/ptr_container/ptr_vector.hpp>
-#include <boost/visit_each.hpp>
-#include <boost/ref.hpp>            // reference_wrapper
-#include <boost/type_traits/is_pointer.hpp>
-#include <boost/utility/addressof.hpp>
-#include <boost/preprocessor/repetition/enum_params.hpp>
-#include <boost/preprocessor/iteration/local.hpp>
-#include <boost/function.hpp>
-#include <boost/static_assert.hpp>
-#include "llsd.h"
-#include "llsingleton.h"
-#include "lldependencies.h"
-
-// override this to allow binding free functions with more parameters
-#ifndef LLEVENTS_LISTENER_ARITY
-#define LLEVENTS_LISTENER_ARITY 10
-#endif
-
-// hack for testing
-#ifndef testable
-#define testable private
-#endif
-
-/*****************************************************************************
-*   Signal and handler declarations
-*   Using a single handler signature means that we can have a common handler
-*   type, rather than needing a distinct one for each different handler.
-*****************************************************************************/
-
-/**
- * A boost::signals Combiner that stops the first time a handler returns true
- * We need this because we want to have our handlers return bool, so that
- * we have the option to cause a handler to stop further processing. The
- * default handler fails when the signal returns a value but has no slots.
- */
-struct LLStopWhenHandled
-{
-    typedef bool result_type;
-
-    template<typename InputIterator>
-    result_type operator()(InputIterator first, InputIterator last) const
-    {
-        for (InputIterator si = first; si != last; ++si)
-		{
-            if (*si)
-			{
-                return true;
-			}
-		}
-        return false;
-    }
-};
-
-/**
- * We want to have a standard signature for all signals; this way,
- * we can easily document a protocol for communicating across
- * dlls and into scripting languages someday.
- *
- * We want to return a bool to indicate whether the signal has been
- * handled and should NOT be passed on to other listeners.
- * Return true to stop further handling of the signal, and false
- * to continue.
- *
- * We take an LLSD because this way the contents of the signal
- * are independent of the API used to communicate it.
- * It is const ref because then there's low cost to pass it;
- * if you only need to inspect it, it's very cheap.
- *
- * @internal
- * The @c float template parameter indicates that we will internally use @c
- * float to indicate relative listener order on a given LLStandardSignal.
- * Don't worry, the @c float values are strictly internal! They are not part
- * of the interface, for the excellent reason that requiring the caller to
- * specify a numeric key to establish order means that the caller must know
- * the universe of possible values. We use LLDependencies for that instead.
- */
-typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float>  LLStandardSignal;
-/// Methods that forward listeners (e.g. constructed with
-/// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
-typedef LLStandardSignal::slot_type LLEventListener;
-/// Result of registering a listener, supports <tt>connected()</tt>,
-/// <tt>disconnect()</tt> and <tt>blocked()</tt>
-typedef boost::signals2::connection LLBoundListener;
-
-/**
- * A common idiom for event-based code is to accept either a callable --
- * directly called on completion -- or the string name of an LLEventPump on
- * which to post the completion event. Specifying a parameter as <tt>const
- * LLListenerOrPumpName&</tt> allows either.
- *
- * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD
- * 'event' object, either calls the callable or posts the event to the named
- * LLEventPump.
- *
- * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
- * the default value of an optional method parameter.) Calling it throws
- * LLListenerOrPumpName::Empty. Test for this condition beforehand using
- * either <tt>if (param)</tt> or <tt>if (! param)</tt>.
- */
-class LLListenerOrPumpName
-{
-public:
-    /// passing string name of LLEventPump
-    LLListenerOrPumpName(const std::string& pumpname);
-    /// passing string literal (overload so compiler isn't forced to infer
-    /// double conversion)
-    LLListenerOrPumpName(const char* pumpname);
-    /// passing listener -- the "anything else" catch-all case. The type of an
-    /// object constructed by boost::bind() isn't intended to be written out.
-    /// Normally we'd just accept 'const LLEventListener&', but that would
-    /// require double implicit conversion: boost::bind() object to
-    /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
-    /// template to forward anything.
-    template<typename T>
-    LLListenerOrPumpName(const T& listener): mListener(listener) {}
-
-    /// for omitted method parameter: uninitialized mListener
-    LLListenerOrPumpName() {}
-
-    /// test for validity
-    operator bool() const { return bool(mListener); }
-    bool operator! () const { return ! mListener; }
-
-    /// explicit accessor
-    const LLEventListener& getListener() const { return *mListener; }
-
-    /// implicit conversion to LLEventListener
-    operator LLEventListener() const { return *mListener; }
-
-    /// allow calling directly
-    bool operator()(const LLSD& event) const;
-
-    /// exception if you try to call when empty
-    struct Empty: public std::runtime_error
-    {
-        Empty(const std::string& what):
-            std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
-    };
-
-private:
-    boost::optional<LLEventListener> mListener;
-};
-
-/*****************************************************************************
-*   LLEventPumps
-*****************************************************************************/
-class LLEventPump;
-
-/**
- * LLEventPumps is a Singleton manager through which one typically accesses
- * this subsystem.
- */
-class LLEventPumps: public LLSingleton<LLEventPumps>
-{
-    friend class LLSingleton<LLEventPumps>;
-public:
-    /**
-     * Find or create an LLEventPump instance with a specific name. We return
-     * a reference so there's no question about ownership. obtain() @em finds
-     * an instance without conferring @em ownership.
-     */
-    LLEventPump& obtain(const std::string& name);
-    /**
-     * Flush all known LLEventPump instances
-     */
-    void flush();
-
-private:
-    friend class LLEventPump;
-    /**
-     * Register a new LLEventPump instance (internal)
-     */
-    std::string registerNew(const LLEventPump&, const std::string& name, bool tweak);
-    /**
-     * Unregister a doomed LLEventPump instance (internal)
-     */
-    void unregister(const LLEventPump&);
-
-private:
-    LLEventPumps();
-    ~LLEventPumps();
-
-testable:
-    // Map of all known LLEventPump instances, whether or not we instantiated
-    // them. We store a plain old LLEventPump* because this map doesn't claim
-    // ownership of the instances. Though the common usage pattern is to
-    // request an instance using obtain(), it's fair to instantiate an
-    // LLEventPump subclass statically, as a class member, on the stack or on
-    // the heap. In such cases, the instantiating party is responsible for its
-    // lifespan.
-    typedef std::map<std::string, LLEventPump*> PumpMap;
-    PumpMap mPumpMap;
-    // Set of all LLEventPumps we instantiated. Membership in this set means
-    // we claim ownership, and will delete them when this LLEventPumps is
-    // destroyed.
-    typedef std::set<LLEventPump*> PumpSet;
-    PumpSet mOurPumps;
-    // LLEventPump names that should be instantiated as LLEventQueue rather
-    // than as LLEventStream
-    typedef std::set<std::string> PumpNames;
-    PumpNames mQueueNames;
-};
-
-/*****************************************************************************
-*   details
-*****************************************************************************/
-namespace LLEventDetail
-{
-    /// Any callable capable of connecting an LLEventListener to an
-    /// LLStandardSignal to produce an LLBoundListener can be mapped to this
-    /// signature.
-    typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc;
-
-    /**
-     * Utility template function to use Visitor appropriately
-     *
-     * @param listener Callable to connect, typically a boost::bind()
-     * expression. This will be visited by Visitor using boost::visit_each().
-     * @param connect_func Callable that will connect() @a listener to an
-     * LLStandardSignal, returning LLBoundListener.
-     */
-    template <typename LISTENER>
-    LLBoundListener visit_and_connect(const LISTENER& listener,
-                                      const ConnectFunc& connect_func);
-} // namespace LLEventDetail
-
-/*****************************************************************************
-*   LLEventPump
-*****************************************************************************/
-/**
- * LLEventPump is the base class interface through which we access the
- * concrete subclasses LLEventStream and LLEventQueue.
- */
-class LLEventPump: boost::noncopyable
-{
-public:
-    /**
-     * Exception thrown by LLEventPump(). You are trying to instantiate an
-     * LLEventPump (subclass) using the same name as some other instance, and
-     * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
-     * variant.
-     */
-    struct DupPumpName: public std::runtime_error
-    {
-        DupPumpName(const std::string& what):
-            std::runtime_error(std::string("DupPumpName: ") + what) {}
-    };
-
-    /**
-     * Instantiate an LLEventPump (subclass) with the string name by which it
-     * can be found using LLEventPumps::obtain().
-     *
-     * If you pass (or default) @a tweak to @c false, then a duplicate name
-     * will throw DupPumpName. This won't happen if LLEventPumps::obtain()
-     * instantiates the LLEventPump, because obtain() uses find-or-create
-     * logic. It can only happen if you instantiate an LLEventPump in your own
-     * code -- and a collision with the name of some other LLEventPump is
-     * likely to cause much more subtle problems!
-     *
-     * When you hand-instantiate an LLEventPump, consider passing @a tweak as
-     * @c true. This directs LLEventPump() to append a suffix to the passed @a
-     * name to make it unique. You can retrieve the adjusted name by calling
-     * getName() on your new instance.
-     */
-    LLEventPump(const std::string& name, bool tweak=false);
-    virtual ~LLEventPump();
-
-    /// group exceptions thrown by listen(). We use exceptions because these
-    /// particular errors are likely to be coding errors, found and fixed by
-    /// the developer even before preliminary checkin.
-    struct ListenError: public std::runtime_error
-    {
-        ListenError(const std::string& what): std::runtime_error(what) {}
-    };
-    /**
-     * exception thrown by listen(). You are attempting to register a
-     * listener on this LLEventPump using the same listener name as an
-     * already-registered listener.
-     */
-    struct DupListenerName: public ListenError
-    {
-        DupListenerName(const std::string& what):
-            ListenError(std::string("DupListenerName: ") + what)
-        {}
-    };
-    /**
-     * exception thrown by listen(). The order dependencies specified for your
-     * listener are incompatible with existing listeners.
-     *
-     * Consider listener "a" which specifies before "b" and "b" which
-     * specifies before "c". You are now attempting to register "c" before
-     * "a". There is no order that can satisfy all constraints.
-     */
-    struct Cycle: public ListenError
-    {
-        Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {}
-    };
-    /**
-     * exception thrown by listen(). This one means that your new listener
-     * would force a change to the order of previously-registered listeners,
-     * and we don't have a good way to implement that.
-     *
-     * Consider listeners "some", "other" and "third". "some" and "other" are
-     * registered earlier without specifying relative order, so "other"
-     * happens to be first. Now you attempt to register "third" after "some"
-     * and before "other". Whoops, that would require swapping "some" and
-     * "other", which we can't do. Instead we throw this exception.
-     *
-     * It may not be possible to change the registration order so we already
-     * know "third"s order requirement by the time we register the second of
-     * "some" and "other". A solution would be to specify that "some" must
-     * come before "other", or equivalently that "other" must come after
-     * "some".
-     */
-    struct OrderChange: public ListenError
-    {
-        OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {}
-    };
-
-    /// used by listen()
-    typedef std::vector<std::string> NameList;
-    /// convenience placeholder for when you explicitly want to pass an empty
-    /// NameList
-    const static NameList empty;
-
-    /// Get this LLEventPump's name
-    std::string getName() const { return mName; }
-
-    /**
-     * Register a new listener with a unique name. Specify an optional list
-     * of other listener names after which this one must be called, likewise
-     * an optional list of other listener names before which this one must be
-     * called. The other listeners mentioned need not yet be registered
-     * themselves. listen() can throw any ListenError; see ListenError
-     * subclasses.
-     *
-     * If (as is typical) you pass a <tt>boost::bind()</tt> expression,
-     * listen() will inspect the components of that expression. If a bound
-     * object matches any of several cases, the connection will automatically
-     * be disconnected when that object is destroyed.
-     *
-     * * You bind a <tt>boost::weak_ptr</tt>.
-     * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
-     *   referenced object would @em never be destroyed, since the @c
-     *   shared_ptr stored in the LLEventPump would remain an outstanding
-     *   reference. Use the weaken() function to convert your @c shared_ptr to
-     *   @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr
-     *   will produce a compile error (@c BOOST_STATIC_ASSERT failure).
-     * * You bind a simple pointer or reference to an object derived from
-     *   <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION)
-     * * You bind a simple pointer or reference to an object derived from
-     *   LLEventTrackable. Unlike the cases described above, though, this is
-     *   vulnerable to a couple of cross-thread race conditions, as described
-     *   in the LLEventTrackable documentation.
-     */
-    template <typename LISTENER>
-    LLBoundListener listen(const std::string& name, const LISTENER& listener,
-                           const NameList& after=NameList(),
-                           const NameList& before=NameList())
-    {
-        // Examine listener, using our listen_impl() method to make the
-        // actual connection.
-        // This is why listen() is a template. Conversion from boost::bind()
-        // to LLEventListener performs type erasure, so it's important to look
-        // at the boost::bind object itself before that happens.
-        return LLEventDetail::visit_and_connect(listener,
-                                                boost::bind(&LLEventPump::listen_impl,
-                                                            this,
-                                                            name,
-                                                            _1,
-                                                            after,
-                                                            before));
-    }
-
-    /// Get the LLBoundListener associated with the passed name (dummy
-    /// LLBoundListener if not found)
-    virtual LLBoundListener getListener(const std::string& name) const;
-    /**
-     * Instantiate one of these to block an existing connection:
-     * @code
-     * { // in some local scope
-     *     LLEventPump::Blocker block(someLLBoundListener);
-     *     // code that needs the connection blocked
-     * } // unblock the connection again
-     * @endcode
-     */
-    typedef boost::signals2::shared_connection_block Blocker;
-    /// Unregister a listener by name. Prefer this to
-    /// <tt>getListener(name).disconnect()</tt> because stopListening() also
-    /// forgets this name.
-    virtual void stopListening(const std::string& name);
-    /// Post an event to all listeners. The @c bool return is only meaningful
-    /// if the underlying leaf class is LLEventStream -- beware of relying on
-    /// it too much! Truthfully, we return @c bool mostly to permit chaining
-    /// one LLEventPump as a listener on another.
-    virtual bool post(const LLSD&) = 0;
-    /// Enable/disable: while disabled, silently ignore all post() calls
-    virtual void enable(bool enabled=true) { mEnabled = enabled; }
-    /// query
-    virtual bool enabled() const { return mEnabled; }
-
-private:
-    friend class LLEventPumps;
-    /// flush queued events
-    virtual void flush() {}
-
-private:
-    virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
-                                        const NameList& after,
-                                        const NameList& before);
-    std::string mName;
-
-protected:
-    /// implement the dispatching
-    LLStandardSignal mSignal;
-    /// valve open?
-    bool mEnabled;
-    /// Map of named listeners. This tracks the listeners that actually exist
-    /// at this moment. When we stopListening(), we discard the entry from
-    /// this map.
-    typedef std::map<std::string, boost::signals2::connection> ConnectionMap;
-    ConnectionMap mConnections;
-    typedef LLDependencies<std::string, float> DependencyMap;
-    /// Dependencies between listeners. For each listener, track the float
-    /// used to establish its place in mSignal's order. This caches all the
-    /// listeners that have ever registered; stopListening() does not discard
-    /// the entry from this map. This is to avoid a new dependency sort if the
-    /// same listener with the same dependencies keeps hopping on and off this
-    /// LLEventPump.
-    DependencyMap mDeps;
-};
-
-/*****************************************************************************
-*   LLEventStream
-*****************************************************************************/
-/**
- * LLEventStream is a thin wrapper around LLStandardSignal. Posting an
- * event immediately calls all registered listeners.
- */
-class LLEventStream: public LLEventPump
-{
-public:
-    LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
-    virtual ~LLEventStream() {}
-
-    /// Post an event to all listeners
-    virtual bool post(const LLSD& event);
-};
-
-/*****************************************************************************
-*   LLEventQueue
-*****************************************************************************/
-/**
- * LLEventQueue isa LLEventPump whose post() method defers calling registered
- * listeners until flush() is called.
- */
-class LLEventQueue: public LLEventPump
-{
-public:
-    LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
-    virtual ~LLEventQueue() {}
-
-    /// Post an event to all listeners
-    virtual bool post(const LLSD& event);
-
-private:
-    /// flush queued events
-    virtual void flush();
-
-private:
-    typedef std::deque<LLSD> EventQueue;
-    EventQueue mEventQueue;
-};
-
-/*****************************************************************************
-*   LLEventTrackable and underpinnings
-*****************************************************************************/
-/**
- * LLEventTrackable wraps boost::signals2::trackable, which resembles
- * boost::trackable. Derive your listener class from LLEventTrackable instead,
- * and use something like
- * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
- * instance, _1))</tt>. This will implicitly disconnect when the object
- * referenced by @c instance is destroyed.
- *
- * @note
- * LLEventTrackable doesn't address a couple of cases:
- * * Object destroyed during call
- *   - You enter a slot call in thread A.
- *   - Thread B destroys the object, which of course disconnects it from any
- *     future slot calls.
- *   - Thread A's call uses 'this', which now refers to a defunct object.
- *     Undefined behavior results.
- * * Call during destruction
- *   - @c MySubclass is derived from LLEventTrackable.
- *   - @c MySubclass registers one of its own methods using
- *     <tt>LLEventPump::listen()</tt>.
- *   - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
- *     runs, destroying state specific to the subclass. (For instance, a
- *     <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
- *   - The listening method will not be disconnected until
- *     <tt>~LLEventTrackable()</tt> runs.
- *   - Before we get there, another thread posts data to the @c LLEventPump
- *     instance, calling the @c MySubclass method.
- *   - The method in question relies on valid @c MySubclass state. (For
- *     instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
- *     <tt>delete</tt>d but not zeroed.)
- *   - Undefined behavior results.
- * If you suspect you may encounter any such scenario, you're better off
- * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
- * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
- * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
- * thread-safe Boost.Signals2 machinery.
- */
-typedef boost::signals2::trackable LLEventTrackable;
-
-/**
- * We originally provided a suite of overloaded
- * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call
- * LLEventPump::listen(...) and then pass the returned LLBoundListener to
- * LLEventTrackable::track(). This was workable but error-prone: the coder
- * must remember to call listenTo() rather than the more straightforward
- * listen() method.
- *
- * Now we publish only the single canonical listen() method, so there's a
- * uniform mechanism. Having a single way to do this is good, in that there's
- * no question in the coder's mind which of several alternatives to choose.
- *
- * To support automatic connection management, we use boost::visit_each
- * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to
- * inspect each argument of a boost::bind expression. (Although the visit_each
- * mechanism was first introduced with the original Boost.Signals library, it
- * was only later documented.)
- *
- * Cases:
- * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass
- *   the corresponding shared_ptr to slot_type::track(). Ideally that would be
- *   the object whose method we want to call, but in fact we do the same for
- *   any weak_ptr we might find among the bound arguments. If we're passing
- *   our bound method a weak_ptr to some object, wouldn't the destruction of
- *   that object invalidate the call? So we disconnect automatically when any
- *   such object is destroyed. This is the mechanism preferred by boost::
- *   signals2.
- * * One of the functions's arguments is a boost::shared_ptr<T>. This produces
- *   a compile error: the bound copy of the shared_ptr stored in the
- *   boost_bind object stored in the signal object would make the referenced
- *   T object immortal. We provide a weaken() function. Pass
- *   weaken(your_shared_ptr) instead. (We can inspect, but not modify, the
- *   boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr
- *   implicitly and just proceed.)
- * * One of the function's arguments is a plain pointer/reference to an object
- *   derived from boost::enable_shared_from_this. We assume that this object
- *   is managed using boost::shared_ptr, so we implicitly extract a shared_ptr
- *   and track that. (UNDER CONSTRUCTION)
- * * One of the function's arguments is derived from LLEventTrackable. Pass
- *   the LLBoundListener to its LLEventTrackable::track(). This is vulnerable
- *   to a couple different race conditions, as described in LLEventTrackable
- *   documentation. (NOTE: Now that LLEventTrackable is a typedef for
- *   boost::signals2::trackable, the Signals2 library handles this itself, so
- *   our visitor needs no special logic for this case.)
- * * Any other argument type is irrelevant to automatic connection management.
- */
-
-namespace LLEventDetail
-{
-    template <typename F>
-    const F& unwrap(const F& f) { return f; }
-
-    template <typename F>
-    const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); }
-
-    // Most of the following is lifted from the Boost.Signals use of
-    // visit_each.
-    template<bool Cond> struct truth {};
-
-    /**
-     * boost::visit_each() Visitor, used on a template argument <tt>const F&
-     * f</tt> as follows (see visit_and_connect()):
-     * @code
-     * LLEventListener listener(f);
-     * Visitor visitor(listener); // bind listener so it can track() shared_ptrs
-     * using boost::visit_each;   // allow unqualified visit_each() call for ADL
-     * visit_each(visitor, unwrap(f));
-     * @endcode
-     */
-    class Visitor
-    {
-    public:
-        /**
-         * Visitor binds a reference to LLEventListener so we can track() any
-         * shared_ptrs we find in the argument list.
-         */
-        Visitor(LLEventListener& listener):
-            mListener(listener)
-        {
-        }
-
-        /**
-         * boost::visit_each() calls this method for each component of a
-         * boost::bind() expression.
-         */
-        template <typename T>
-        void operator()(const T& t) const
-        {
-            decode(t, 0);
-        }
-
-    private:
-        // decode() decides between a reference wrapper and anything else
-        // boost::ref() variant
-        template<typename T>
-        void decode(const boost::reference_wrapper<T>& t, int) const
-        {
-//          add_if_trackable(t.get_pointer());
-        }
-
-        // decode() anything else
-        template<typename T>
-        void decode(const T& t, long) const
-        {
-            typedef truth<(boost::is_pointer<T>::value)> is_a_pointer;
-            maybe_get_pointer(t, is_a_pointer());
-        }
-
-        // maybe_get_pointer() decides between a pointer and a non-pointer
-        // plain pointer variant
-        template<typename T>
-        void maybe_get_pointer(const T& t, truth<true>) const
-        {
-//          add_if_trackable(t);
-        }
-
-        // shared_ptr variant
-        template<typename T>
-        void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const
-        {
-            // If we have a shared_ptr to this object, it doesn't matter
-            // whether the object is derived from LLEventTrackable, so no
-            // further analysis of T is needed.
-//          mListener.track(t);
-
-            // Make this case illegal. Passing a bound shared_ptr to
-            // slot_type::track() is useless, since the bound shared_ptr will
-            // keep the object alive anyway! Force the coder to cast to weak_ptr.
-
-            // Trivial as it is, make the BOOST_STATIC_ASSERT() condition
-            // dependent on template param so the macro is only evaluated if
-            // this method is in fact instantiated, as described here:
-            // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html
-
-            // ATTENTION: Don't bind a shared_ptr<anything> using
-            // LLEventPump::listen(boost::bind()). Doing so captures a copy of
-            // the shared_ptr, making the referenced object effectively
-            // immortal. Use the weaken() function, e.g.:
-            // somepump.listen(boost::bind(...weaken(my_shared_ptr)...));
-            // This lets us automatically disconnect when the referenced
-            // object is destroyed.
-            BOOST_STATIC_ASSERT(sizeof(T) == 0);
-        }
-
-        // weak_ptr variant
-        template<typename T>
-        void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const
-        {
-            // If we have a weak_ptr to this object, it doesn't matter
-            // whether the object is derived from LLEventTrackable, so no
-            // further analysis of T is needed.
-            mListener.track(t);
-//          std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n";
-        }
-
-#if 0
-        // reference to anything derived from boost::enable_shared_from_this
-        template <typename T>
-        inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct,
-                                      truth<false>) const
-        {
-            // Use the slot_type::track(shared_ptr) mechanism. Cast away
-            // const-ness because (in our code base anyway) it's unusual
-            // to find shared_ptr<const T>.
-            boost::enable_shared_from_this<T>&
-                t(const_cast<boost::enable_shared_from_this<T>&>(ct));
-            std::cout << "Capturing shared_from_this()" << std::endl;
-            boost::shared_ptr<T> sp(t.shared_from_this());
-/*==========================================================================*|
-            std::cout << "Capturing weak_ptr" << std::endl;
-            boost::weak_ptr<T> wp(sp);
-|*==========================================================================*/
-            std::cout << "Tracking shared__ptr" << std::endl;
-            mListener.track(sp);
-        }
-#endif
-
-        // non-pointer variant
-        template<typename T>
-        void maybe_get_pointer(const T& t, truth<false>) const
-        {
-            // Take the address of this object, because the object itself may be
-            // trackable
-//          add_if_trackable(boost::addressof(t));
-        }
-
-/*==========================================================================*|
-        // add_if_trackable() adds LLEventTrackable objects to mTrackables
-        inline void add_if_trackable(const LLEventTrackable* t) const
-        {
-            if (t)
-            {
-            }
-        }
-
-        // pointer to anything not an LLEventTrackable subclass
-        inline void add_if_trackable(const void*) const
-        {
-        }
-
-        // pointer to free function
-        // The following construct uses the preprocessor to generate
-        // add_if_trackable() overloads accepting pointer-to-function taking
-        // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type.
-#define BOOST_PP_LOCAL_MACRO(n)                                     \
-        template <typename R                                        \
-                  BOOST_PP_COMMA_IF(n)                              \
-                  BOOST_PP_ENUM_PARAMS(n, typename T)>              \
-        inline void                                                 \
-        add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const   \
-        {                                                           \
-        }
-#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY)
-#include BOOST_PP_LOCAL_ITERATE()
-#undef  BOOST_PP_LOCAL_MACRO
-#undef  BOOST_PP_LOCAL_LIMITS
-|*==========================================================================*/
-
-        /// Bind a reference to the LLEventListener to call its track() method.
-        LLEventListener& mListener;
-    };
-
-    /**
-     * Utility template function to use Visitor appropriately
-     *
-     * @param raw_listener Callable to connect, typically a boost::bind()
-     * expression. This will be visited by Visitor using boost::visit_each().
-     * @param connect_funct Callable that will connect() @a raw_listener to an
-     * LLStandardSignal, returning LLBoundListener.
-     */
-    template <typename LISTENER>
-    LLBoundListener visit_and_connect(const LISTENER& raw_listener,
-                                      const ConnectFunc& connect_func)
-    {
-        // Capture the listener
-        LLEventListener listener(raw_listener);
-        // Define our Visitor, binding the listener so we can call
-        // listener.track() if we discover any shared_ptr<Foo>.
-        LLEventDetail::Visitor visitor(listener);
-        // Allow unqualified visit_each() call for ADL
-        using boost::visit_each;
-        // Visit each component of a boost::bind() expression. Pass
-        // 'raw_listener', our template argument, rather than 'listener' from
-        // which type details have been erased. unwrap() comes from
-        // Boost.Signals, in case we were passed a boost::ref().
-        visit_each(visitor, LLEventDetail::unwrap(raw_listener));
-        // Make the connection using passed function. At present, wrapping
-        // this functionality into this function is a bit silly: we don't
-        // really need a visit_and_connect() function any more, just a visit()
-        // function. The definition of this function dates from when, after
-        // visit_each(), after establishing the connection, we had to
-        // postprocess the new connection with the visitor object. That's no
-        // longer necessary.
-        return connect_func(listener);
-    }
-} // namespace LLEventDetail
-
-// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
-// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
-// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
-// specialized for boost::weak_ptr. This remedies that omission.
-namespace boost
-{
-    template <typename T>
-    T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
-}
-
-/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an
-/// easy way to cast to the corresponding weak_ptr.
-template <typename T>
-boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr)
-{
-    return boost::weak_ptr<T>(ptr);
-}
-
-#endif /* ! defined(LL_LLEVENTS_H) */
+/**
+ * @file   llevents.h
+ * @author Kent Quirk, Nat Goodspeed
+ * @date   2008-09-11
+ * @brief  This is an implementation of the event system described at
+ *         https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System,
+ *         originally introduced in llnotifications.h. It has nothing
+ *         whatsoever to do with the older system in llevent.h.
+ * 
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * Copyright (c) 2008, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLEVENTS_H)
+#define LL_LLEVENTS_H
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <deque>
+#include <stdexcept>
+#if LL_WINDOWS
+	#pragma warning (push)
+	#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
+	#pragma warning (disable : 4264) 
+#endif
+#include <boost/signals2.hpp>
+#if LL_WINDOWS
+	#pragma warning (pop)
+#endif
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/utility.hpp>        // noncopyable
+#include <boost/optional/optional.hpp>
+#include <boost/visit_each.hpp>
+#include <boost/ref.hpp>            // reference_wrapper
+#include <boost/type_traits/is_pointer.hpp>
+#include <boost/function.hpp>
+#include <boost/static_assert.hpp>
+#include "llsd.h"
+#include "llsingleton.h"
+#include "lldependencies.h"
+
+// override this to allow binding free functions with more parameters
+#ifndef LLEVENTS_LISTENER_ARITY
+#define LLEVENTS_LISTENER_ARITY 10
+#endif
+
+// hack for testing
+#ifndef testable
+#define testable private
+#endif
+
+/*****************************************************************************
+*   Signal and handler declarations
+*   Using a single handler signature means that we can have a common handler
+*   type, rather than needing a distinct one for each different handler.
+*****************************************************************************/
+
+/**
+ * A boost::signals Combiner that stops the first time a handler returns true
+ * We need this because we want to have our handlers return bool, so that
+ * we have the option to cause a handler to stop further processing. The
+ * default handler fails when the signal returns a value but has no slots.
+ */
+struct LLStopWhenHandled
+{
+    typedef bool result_type;
+
+    template<typename InputIterator>
+    result_type operator()(InputIterator first, InputIterator last) const
+    {
+        for (InputIterator si = first; si != last; ++si)
+		{
+            if (*si)
+			{
+                return true;
+			}
+		}
+        return false;
+    }
+};
+
+/**
+ * We want to have a standard signature for all signals; this way,
+ * we can easily document a protocol for communicating across
+ * dlls and into scripting languages someday.
+ *
+ * We want to return a bool to indicate whether the signal has been
+ * handled and should NOT be passed on to other listeners.
+ * Return true to stop further handling of the signal, and false
+ * to continue.
+ *
+ * We take an LLSD because this way the contents of the signal
+ * are independent of the API used to communicate it.
+ * It is const ref because then there's low cost to pass it;
+ * if you only need to inspect it, it's very cheap.
+ *
+ * @internal
+ * The @c float template parameter indicates that we will internally use @c
+ * float to indicate relative listener order on a given LLStandardSignal.
+ * Don't worry, the @c float values are strictly internal! They are not part
+ * of the interface, for the excellent reason that requiring the caller to
+ * specify a numeric key to establish order means that the caller must know
+ * the universe of possible values. We use LLDependencies for that instead.
+ */
+typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float>  LLStandardSignal;
+/// Methods that forward listeners (e.g. constructed with
+/// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
+typedef LLStandardSignal::slot_type LLEventListener;
+/// Result of registering a listener, supports <tt>connected()</tt>,
+/// <tt>disconnect()</tt> and <tt>blocked()</tt>
+typedef boost::signals2::connection LLBoundListener;
+/// Storing an LLBoundListener in LLTempBoundListener will disconnect the
+/// referenced listener when the LLTempBoundListener instance is destroyed.
+typedef boost::signals2::scoped_connection LLTempBoundListener;
+
+/**
+ * A common idiom for event-based code is to accept either a callable --
+ * directly called on completion -- or the string name of an LLEventPump on
+ * which to post the completion event. Specifying a parameter as <tt>const
+ * LLListenerOrPumpName&</tt> allows either.
+ *
+ * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD
+ * 'event' object, either calls the callable or posts the event to the named
+ * LLEventPump.
+ *
+ * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
+ * the default value of an optional method parameter.) Calling it throws
+ * LLListenerOrPumpName::Empty. Test for this condition beforehand using
+ * either <tt>if (param)</tt> or <tt>if (! param)</tt>.
+ */
+class LL_COMMON_API LLListenerOrPumpName
+{
+public:
+    /// passing string name of LLEventPump
+    LLListenerOrPumpName(const std::string& pumpname);
+    /// passing string literal (overload so compiler isn't forced to infer
+    /// double conversion)
+    LLListenerOrPumpName(const char* pumpname);
+    /// passing listener -- the "anything else" catch-all case. The type of an
+    /// object constructed by boost::bind() isn't intended to be written out.
+    /// Normally we'd just accept 'const LLEventListener&', but that would
+    /// require double implicit conversion: boost::bind() object to
+    /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
+    /// template to forward anything.
+    template<typename T>
+    LLListenerOrPumpName(const T& listener): mListener(listener) {}
+
+    /// for omitted method parameter: uninitialized mListener
+    LLListenerOrPumpName() {}
+
+    /// test for validity
+    operator bool() const { return bool(mListener); }
+    bool operator! () const { return ! mListener; }
+
+    /// explicit accessor
+    const LLEventListener& getListener() const { return *mListener; }
+
+    /// implicit conversion to LLEventListener
+    operator LLEventListener() const { return *mListener; }
+
+    /// allow calling directly
+    bool operator()(const LLSD& event) const;
+
+    /// exception if you try to call when empty
+    struct Empty: public std::runtime_error
+    {
+        Empty(const std::string& what):
+            std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
+    };
+
+private:
+    boost::optional<LLEventListener> mListener;
+};
+
+/*****************************************************************************
+*   LLEventPumps
+*****************************************************************************/
+class LLEventPump;
+
+/**
+ * LLEventPumps is a Singleton manager through which one typically accesses
+ * this subsystem.
+ */
+class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
+{
+    friend class LLSingleton<LLEventPumps>;
+public:
+    /**
+     * Find or create an LLEventPump instance with a specific name. We return
+     * a reference so there's no question about ownership. obtain() @em finds
+     * an instance without conferring @em ownership.
+     */
+    LLEventPump& obtain(const std::string& name);
+    /**
+     * Flush all known LLEventPump instances
+     */
+    void flush();
+
+    /**
+     * Reset all known LLEventPump instances
+     * workaround for DEV-35406 crash on shutdown
+     */
+    void reset();
+
+private:
+    friend class LLEventPump;
+    /**
+     * Register a new LLEventPump instance (internal)
+     */
+    std::string registerNew(const LLEventPump&, const std::string& name, bool tweak);
+    /**
+     * Unregister a doomed LLEventPump instance (internal)
+     */
+    void unregister(const LLEventPump&);
+
+private:
+    LLEventPumps();
+    ~LLEventPumps();
+
+testable:
+    // Map of all known LLEventPump instances, whether or not we instantiated
+    // them. We store a plain old LLEventPump* because this map doesn't claim
+    // ownership of the instances. Though the common usage pattern is to
+    // request an instance using obtain(), it's fair to instantiate an
+    // LLEventPump subclass statically, as a class member, on the stack or on
+    // the heap. In such cases, the instantiating party is responsible for its
+    // lifespan.
+    typedef std::map<std::string, LLEventPump*> PumpMap;
+    PumpMap mPumpMap;
+    // Set of all LLEventPumps we instantiated. Membership in this set means
+    // we claim ownership, and will delete them when this LLEventPumps is
+    // destroyed.
+    typedef std::set<LLEventPump*> PumpSet;
+    PumpSet mOurPumps;
+    // LLEventPump names that should be instantiated as LLEventQueue rather
+    // than as LLEventStream
+    typedef std::set<std::string> PumpNames;
+    PumpNames mQueueNames;
+};
+
+/*****************************************************************************
+*   details
+*****************************************************************************/
+namespace LLEventDetail
+{
+    /// Any callable capable of connecting an LLEventListener to an
+    /// LLStandardSignal to produce an LLBoundListener can be mapped to this
+    /// signature.
+    typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc;
+
+    /**
+     * Utility template function to use Visitor appropriately
+     *
+     * @param listener Callable to connect, typically a boost::bind()
+     * expression. This will be visited by Visitor using boost::visit_each().
+     * @param connect_func Callable that will connect() @a listener to an
+     * LLStandardSignal, returning LLBoundListener.
+     */
+    template <typename LISTENER>
+    LLBoundListener visit_and_connect(const LISTENER& listener,
+                                      const ConnectFunc& connect_func);
+} // namespace LLEventDetail
+
+/*****************************************************************************
+*   LLEventTrackable
+*****************************************************************************/
+/**
+ * LLEventTrackable wraps boost::signals2::trackable, which resembles
+ * boost::trackable. Derive your listener class from LLEventTrackable instead,
+ * and use something like
+ * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
+ * instance, _1))</tt>. This will implicitly disconnect when the object
+ * referenced by @c instance is destroyed.
+ *
+ * @note
+ * LLEventTrackable doesn't address a couple of cases:
+ * * Object destroyed during call
+ *   - You enter a slot call in thread A.
+ *   - Thread B destroys the object, which of course disconnects it from any
+ *     future slot calls.
+ *   - Thread A's call uses 'this', which now refers to a defunct object.
+ *     Undefined behavior results.
+ * * Call during destruction
+ *   - @c MySubclass is derived from LLEventTrackable.
+ *   - @c MySubclass registers one of its own methods using
+ *     <tt>LLEventPump::listen()</tt>.
+ *   - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
+ *     runs, destroying state specific to the subclass. (For instance, a
+ *     <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
+ *   - The listening method will not be disconnected until
+ *     <tt>~LLEventTrackable()</tt> runs.
+ *   - Before we get there, another thread posts data to the @c LLEventPump
+ *     instance, calling the @c MySubclass method.
+ *   - The method in question relies on valid @c MySubclass state. (For
+ *     instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
+ *     <tt>delete</tt>d but not zeroed.)
+ *   - Undefined behavior results.
+ * If you suspect you may encounter any such scenario, you're better off
+ * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
+ * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
+ * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
+ * thread-safe Boost.Signals2 machinery.
+ */
+typedef boost::signals2::trackable LLEventTrackable;
+
+/*****************************************************************************
+*   LLEventPump
+*****************************************************************************/
+/**
+ * LLEventPump is the base class interface through which we access the
+ * concrete subclasses LLEventStream and LLEventQueue.
+ *
+ * @NOTE
+ * LLEventPump derives from LLEventTrackable so that when you "chain"
+ * LLEventPump instances together, they will automatically disconnect on
+ * destruction. Please see LLEventTrackable documentation for situations in
+ * which this may be perilous across threads.
+ */
+class LL_COMMON_API LLEventPump: public LLEventTrackable
+{
+public:
+    /**
+     * Exception thrown by LLEventPump(). You are trying to instantiate an
+     * LLEventPump (subclass) using the same name as some other instance, and
+     * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
+     * variant.
+     */
+    struct DupPumpName: public std::runtime_error
+    {
+        DupPumpName(const std::string& what):
+            std::runtime_error(std::string("DupPumpName: ") + what) {}
+    };
+
+    /**
+     * Instantiate an LLEventPump (subclass) with the string name by which it
+     * can be found using LLEventPumps::obtain().
+     *
+     * If you pass (or default) @a tweak to @c false, then a duplicate name
+     * will throw DupPumpName. This won't happen if LLEventPumps::obtain()
+     * instantiates the LLEventPump, because obtain() uses find-or-create
+     * logic. It can only happen if you instantiate an LLEventPump in your own
+     * code -- and a collision with the name of some other LLEventPump is
+     * likely to cause much more subtle problems!
+     *
+     * When you hand-instantiate an LLEventPump, consider passing @a tweak as
+     * @c true. This directs LLEventPump() to append a suffix to the passed @a
+     * name to make it unique. You can retrieve the adjusted name by calling
+     * getName() on your new instance.
+     */
+    LLEventPump(const std::string& name, bool tweak=false);
+    virtual ~LLEventPump();
+
+    /// group exceptions thrown by listen(). We use exceptions because these
+    /// particular errors are likely to be coding errors, found and fixed by
+    /// the developer even before preliminary checkin.
+    struct ListenError: public std::runtime_error
+    {
+        ListenError(const std::string& what): std::runtime_error(what) {}
+    };
+    /**
+     * exception thrown by listen(). You are attempting to register a
+     * listener on this LLEventPump using the same listener name as an
+     * already-registered listener.
+     */
+    struct DupListenerName: public ListenError
+    {
+        DupListenerName(const std::string& what):
+            ListenError(std::string("DupListenerName: ") + what)
+        {}
+    };
+    /**
+     * exception thrown by listen(). The order dependencies specified for your
+     * listener are incompatible with existing listeners.
+     *
+     * Consider listener "a" which specifies before "b" and "b" which
+     * specifies before "c". You are now attempting to register "c" before
+     * "a". There is no order that can satisfy all constraints.
+     */
+    struct Cycle: public ListenError
+    {
+        Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {}
+    };
+    /**
+     * exception thrown by listen(). This one means that your new listener
+     * would force a change to the order of previously-registered listeners,
+     * and we don't have a good way to implement that.
+     *
+     * Consider listeners "some", "other" and "third". "some" and "other" are
+     * registered earlier without specifying relative order, so "other"
+     * happens to be first. Now you attempt to register "third" after "some"
+     * and before "other". Whoops, that would require swapping "some" and
+     * "other", which we can't do. Instead we throw this exception.
+     *
+     * It may not be possible to change the registration order so we already
+     * know "third"s order requirement by the time we register the second of
+     * "some" and "other". A solution would be to specify that "some" must
+     * come before "other", or equivalently that "other" must come after
+     * "some".
+     */
+    struct OrderChange: public ListenError
+    {
+        OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {}
+    };
+
+    /// used by listen()
+    typedef std::vector<std::string> NameList;
+    /// convenience placeholder for when you explicitly want to pass an empty
+    /// NameList
+    const static NameList empty;
+
+    /// Get this LLEventPump's name
+    std::string getName() const { return mName; }
+
+    /**
+     * Register a new listener with a unique name. Specify an optional list
+     * of other listener names after which this one must be called, likewise
+     * an optional list of other listener names before which this one must be
+     * called. The other listeners mentioned need not yet be registered
+     * themselves. listen() can throw any ListenError; see ListenError
+     * subclasses.
+     *
+     * The listener name must be unique among active listeners for this
+     * LLEventPump, else you get DupListenerName. If you don't care to invent
+     * a name yourself, use inventName(). (I was tempted to recognize e.g. ""
+     * and internally generate a distinct name for that case. But that would
+     * handle badly the scenario in which you want to add, remove, re-add,
+     * etc. the same listener: each new listen() call would necessarily
+     * perform a new dependency sort. Assuming you specify the same
+     * after/before lists each time, using inventName() when you first
+     * instantiate your listener, then passing the same name on each listen()
+     * call, allows us to optimize away the second and subsequent dependency
+     * sorts.
+     *
+     * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a
+     * listener, listen() will inspect the components of that expression. If a
+     * bound object matches any of several cases, the connection will
+     * automatically be disconnected when that object is destroyed.
+     *
+     * * You bind a <tt>boost::weak_ptr</tt>.
+     * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
+     *   referenced object would @em never be destroyed, since the @c
+     *   shared_ptr stored in the LLEventPump would remain an outstanding
+     *   reference. Use the weaken() function to convert your @c shared_ptr to
+     *   @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr
+     *   will produce a compile error (@c BOOST_STATIC_ASSERT failure).
+     * * You bind a simple pointer or reference to an object derived from
+     *   <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION)
+     * * You bind a simple pointer or reference to an object derived from
+     *   LLEventTrackable. Unlike the cases described above, though, this is
+     *   vulnerable to a couple of cross-thread race conditions, as described
+     *   in the LLEventTrackable documentation.
+     */
+    template <typename LISTENER>
+    LLBoundListener listen(const std::string& name, const LISTENER& listener,
+                           const NameList& after=NameList(),
+                           const NameList& before=NameList())
+    {
+        // Examine listener, using our listen_impl() method to make the
+        // actual connection.
+        // This is why listen() is a template. Conversion from boost::bind()
+        // to LLEventListener performs type erasure, so it's important to look
+        // at the boost::bind object itself before that happens.
+        return LLEventDetail::visit_and_connect(listener,
+                                                boost::bind(&LLEventPump::listen_impl,
+                                                            this,
+                                                            name,
+                                                            _1,
+                                                            after,
+                                                            before));
+    }
+
+    /// Get the LLBoundListener associated with the passed name (dummy
+    /// LLBoundListener if not found)
+    virtual LLBoundListener getListener(const std::string& name) const;
+    /**
+     * Instantiate one of these to block an existing connection:
+     * @code
+     * { // in some local scope
+     *     LLEventPump::Blocker block(someLLBoundListener);
+     *     // code that needs the connection blocked
+     * } // unblock the connection again
+     * @endcode
+     */
+    typedef boost::signals2::shared_connection_block Blocker;
+    /// Unregister a listener by name. Prefer this to
+    /// <tt>getListener(name).disconnect()</tt> because stopListening() also
+    /// forgets this name.
+    virtual void stopListening(const std::string& name);
+    /// Post an event to all listeners. The @c bool return is only meaningful
+    /// if the underlying leaf class is LLEventStream -- beware of relying on
+    /// it too much! Truthfully, we return @c bool mostly to permit chaining
+    /// one LLEventPump as a listener on another.
+    virtual bool post(const LLSD&) = 0;
+    /// Enable/disable: while disabled, silently ignore all post() calls
+    virtual void enable(bool enabled=true) { mEnabled = enabled; }
+    /// query
+    virtual bool enabled() const { return mEnabled; }
+
+    /// Generate a distinct name for a listener -- see listen()
+    static std::string inventName(const std::string& pfx="listener");
+
+private:
+    friend class LLEventPumps;
+    /// flush queued events
+    virtual void flush() {}
+
+    virtual void reset();
+
+private:
+    virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
+                                        const NameList& after,
+                                        const NameList& before);
+    std::string mName;
+
+protected:
+    /// implement the dispatching
+    boost::scoped_ptr<LLStandardSignal> mSignal;
+
+    /// valve open?
+    bool mEnabled;
+    /// Map of named listeners. This tracks the listeners that actually exist
+    /// at this moment. When we stopListening(), we discard the entry from
+    /// this map.
+    typedef std::map<std::string, boost::signals2::connection> ConnectionMap;
+    ConnectionMap mConnections;
+    typedef LLDependencies<std::string, float> DependencyMap;
+    /// Dependencies between listeners. For each listener, track the float
+    /// used to establish its place in mSignal's order. This caches all the
+    /// listeners that have ever registered; stopListening() does not discard
+    /// the entry from this map. This is to avoid a new dependency sort if the
+    /// same listener with the same dependencies keeps hopping on and off this
+    /// LLEventPump.
+    DependencyMap mDeps;
+};
+
+/*****************************************************************************
+*   LLEventStream
+*****************************************************************************/
+/**
+ * LLEventStream is a thin wrapper around LLStandardSignal. Posting an
+ * event immediately calls all registered listeners.
+ */
+class LL_COMMON_API LLEventStream: public LLEventPump
+{
+public:
+    LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
+    virtual ~LLEventStream() {}
+
+    /// Post an event to all listeners
+    virtual bool post(const LLSD& event);
+};
+
+/*****************************************************************************
+*   LLEventQueue
+*****************************************************************************/
+/**
+ * LLEventQueue isa LLEventPump whose post() method defers calling registered
+ * listeners until flush() is called.
+ */
+class LL_COMMON_API LLEventQueue: public LLEventPump
+{
+public:
+    LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
+    virtual ~LLEventQueue() {}
+
+    /// Post an event to all listeners
+    virtual bool post(const LLSD& event);
+
+private:
+    /// flush queued events
+    virtual void flush();
+
+private:
+    typedef std::deque<LLSD> EventQueue;
+    EventQueue mEventQueue;
+};
+
+/*****************************************************************************
+*   LLReqID
+*****************************************************************************/
+/**
+ * This class helps the implementer of a given event API to honor the
+ * ["reqid"] convention. By this convention, each event API stamps into its
+ * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if
+ * any, from the corresponding request.
+ *
+ * This supports an (atypical, but occasionally necessary) use case in which
+ * two or more asynchronous requests are multiplexed onto the same ["reply"]
+ * LLEventPump. Since the response events could arrive in arbitrary order, the
+ * caller must be able to demux them. It does so by matching the ["reqid"]
+ * value in each response with the ["reqid"] value in the corresponding
+ * request.
+ *
+ * It is the caller's responsibility to ensure distinct ["reqid"] values for
+ * that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
+ * the "namespace" of unique ["reqid"] values is simply the set of requests
+ * specifying the same ["reply"] LLEventPump name.
+ *
+ * Making a given event API echo the request's ["reqid"] into the response is
+ * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
+ * place to put these comments. We hope that each time a coder implements a
+ * new event API based on some existing one, s/he will say, "Huh, what's an
+ * LLReqID?" and look up this material.
+ *
+ * The hardest part about the convention is deciding where to store the
+ * ["reqid"] value. Ironically, LLReqID can't help with that: you must store
+ * an LLReqID instance in whatever storage will persist until the reply is
+ * sent. For example, if the request ultimately ends up using a Responder
+ * subclass, storing an LLReqID instance in the Responder works.
+ *
+ * @note
+ * The @em implementer of an event API must honor the ["reqid"] convention.
+ * However, the @em caller of an event API need only use it if s/he is sharing
+ * the same ["reply"] LLEventPump for two or more asynchronous event API
+ * requests.
+ *
+ * In most cases, it's far easier for the caller to instantiate a local
+ * LLEventStream and pass its name to the event API in question. Then it's
+ * perfectly reasonable not to set a ["reqid"] key in the request, ignoring
+ * the @c isUndefined() ["reqid"] value in the response.
+ */
+class LL_COMMON_API LLReqID
+{
+public:
+    /**
+     * If you have the request in hand at the time you instantiate the
+     * LLReqID, pass that request to extract its ["reqid"].
+ */
+    LLReqID(const LLSD& request):
+        mReqid(request["reqid"])
+    {}
+    /// If you don't yet have the request, use setFrom() later.
+    LLReqID() {}
+
+    /// Extract and store the ["reqid"] value from an incoming request.
+    void setFrom(const LLSD& request)
+    {
+        mReqid = request["reqid"];
+    }
+
+    /// Set ["reqid"] key into a pending response LLSD object.
+    void stamp(LLSD& response) const;
+
+    /// Make a whole new response LLSD object with our ["reqid"].
+    LLSD makeResponse() const
+    {
+        LLSD response;
+        stamp(response);
+        return response;
+    }
+
+    /// Not really sure of a use case for this accessor...
+    LLSD getReqID() const { return mReqid; }
+
+private:
+    LLSD mReqid;
+};
+
+/*****************************************************************************
+*   Underpinnings
+*****************************************************************************/
+/**
+ * We originally provided a suite of overloaded
+ * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call
+ * LLEventPump::listen(...) and then pass the returned LLBoundListener to
+ * LLEventTrackable::track(). This was workable but error-prone: the coder
+ * must remember to call listenTo() rather than the more straightforward
+ * listen() method.
+ *
+ * Now we publish only the single canonical listen() method, so there's a
+ * uniform mechanism. Having a single way to do this is good, in that there's
+ * no question in the coder's mind which of several alternatives to choose.
+ *
+ * To support automatic connection management, we use boost::visit_each
+ * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to
+ * inspect each argument of a boost::bind expression. (Although the visit_each
+ * mechanism was first introduced with the original Boost.Signals library, it
+ * was only later documented.)
+ *
+ * Cases:
+ * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass
+ *   the corresponding shared_ptr to slot_type::track(). Ideally that would be
+ *   the object whose method we want to call, but in fact we do the same for
+ *   any weak_ptr we might find among the bound arguments. If we're passing
+ *   our bound method a weak_ptr to some object, wouldn't the destruction of
+ *   that object invalidate the call? So we disconnect automatically when any
+ *   such object is destroyed. This is the mechanism preferred by boost::
+ *   signals2.
+ * * One of the functions's arguments is a boost::shared_ptr<T>. This produces
+ *   a compile error: the bound copy of the shared_ptr stored in the
+ *   boost_bind object stored in the signal object would make the referenced
+ *   T object immortal. We provide a weaken() function. Pass
+ *   weaken(your_shared_ptr) instead. (We can inspect, but not modify, the
+ *   boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr
+ *   implicitly and just proceed.)
+ * * One of the function's arguments is a plain pointer/reference to an object
+ *   derived from boost::enable_shared_from_this. We assume that this object
+ *   is managed using boost::shared_ptr, so we implicitly extract a shared_ptr
+ *   and track that. (UNDER CONSTRUCTION)
+ * * One of the function's arguments is derived from LLEventTrackable. Pass
+ *   the LLBoundListener to its LLEventTrackable::track(). This is vulnerable
+ *   to a couple different race conditions, as described in LLEventTrackable
+ *   documentation. (NOTE: Now that LLEventTrackable is a typedef for
+ *   boost::signals2::trackable, the Signals2 library handles this itself, so
+ *   our visitor needs no special logic for this case.)
+ * * Any other argument type is irrelevant to automatic connection management.
+ */
+
+namespace LLEventDetail
+{
+    template <typename F>
+    const F& unwrap(const F& f) { return f; }
+
+    template <typename F>
+    const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); }
+
+    // Most of the following is lifted from the Boost.Signals use of
+    // visit_each.
+    template<bool Cond> struct truth {};
+
+    /**
+     * boost::visit_each() Visitor, used on a template argument <tt>const F&
+     * f</tt> as follows (see visit_and_connect()):
+     * @code
+     * LLEventListener listener(f);
+     * Visitor visitor(listener); // bind listener so it can track() shared_ptrs
+     * using boost::visit_each;   // allow unqualified visit_each() call for ADL
+     * visit_each(visitor, unwrap(f));
+     * @endcode
+     */
+    class Visitor
+    {
+    public:
+        /**
+         * Visitor binds a reference to LLEventListener so we can track() any
+         * shared_ptrs we find in the argument list.
+         */
+        Visitor(LLEventListener& listener):
+            mListener(listener)
+        {
+        }
+
+        /**
+         * boost::visit_each() calls this method for each component of a
+         * boost::bind() expression.
+         */
+        template <typename T>
+        void operator()(const T& t) const
+        {
+            decode(t, 0);
+        }
+
+    private:
+        // decode() decides between a reference wrapper and anything else
+        // boost::ref() variant
+        template<typename T>
+        void decode(const boost::reference_wrapper<T>& t, int) const
+        {
+//          add_if_trackable(t.get_pointer());
+        }
+
+        // decode() anything else
+        template<typename T>
+        void decode(const T& t, long) const
+        {
+            typedef truth<(boost::is_pointer<T>::value)> is_a_pointer;
+            maybe_get_pointer(t, is_a_pointer());
+        }
+
+        // maybe_get_pointer() decides between a pointer and a non-pointer
+        // plain pointer variant
+        template<typename T>
+        void maybe_get_pointer(const T& t, truth<true>) const
+        {
+//          add_if_trackable(t);
+        }
+
+        // shared_ptr variant
+        template<typename T>
+        void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const
+        {
+            // If we have a shared_ptr to this object, it doesn't matter
+            // whether the object is derived from LLEventTrackable, so no
+            // further analysis of T is needed.
+//          mListener.track(t);
+
+            // Make this case illegal. Passing a bound shared_ptr to
+            // slot_type::track() is useless, since the bound shared_ptr will
+            // keep the object alive anyway! Force the coder to cast to weak_ptr.
+
+            // Trivial as it is, make the BOOST_STATIC_ASSERT() condition
+            // dependent on template param so the macro is only evaluated if
+            // this method is in fact instantiated, as described here:
+            // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html
+
+            // ATTENTION: Don't bind a shared_ptr<anything> using
+            // LLEventPump::listen(boost::bind()). Doing so captures a copy of
+            // the shared_ptr, making the referenced object effectively
+            // immortal. Use the weaken() function, e.g.:
+            // somepump.listen(boost::bind(...weaken(my_shared_ptr)...));
+            // This lets us automatically disconnect when the referenced
+            // object is destroyed.
+            BOOST_STATIC_ASSERT(sizeof(T) == 0);
+        }
+
+        // weak_ptr variant
+        template<typename T>
+        void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const
+        {
+            // If we have a weak_ptr to this object, it doesn't matter
+            // whether the object is derived from LLEventTrackable, so no
+            // further analysis of T is needed.
+            mListener.track(t);
+//          std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n";
+        }
+
+#if 0
+        // reference to anything derived from boost::enable_shared_from_this
+        template <typename T>
+        inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct,
+                                      truth<false>) const
+        {
+            // Use the slot_type::track(shared_ptr) mechanism. Cast away
+            // const-ness because (in our code base anyway) it's unusual
+            // to find shared_ptr<const T>.
+            boost::enable_shared_from_this<T>&
+                t(const_cast<boost::enable_shared_from_this<T>&>(ct));
+            std::cout << "Capturing shared_from_this()" << std::endl;
+            boost::shared_ptr<T> sp(t.shared_from_this());
+/*==========================================================================*|
+            std::cout << "Capturing weak_ptr" << std::endl;
+            boost::weak_ptr<T> wp(sp);
+|*==========================================================================*/
+            std::cout << "Tracking shared__ptr" << std::endl;
+            mListener.track(sp);
+        }
+#endif
+
+        // non-pointer variant
+        template<typename T>
+        void maybe_get_pointer(const T& t, truth<false>) const
+        {
+            // Take the address of this object, because the object itself may be
+            // trackable
+//          add_if_trackable(boost::addressof(t));
+        }
+
+/*==========================================================================*|
+        // add_if_trackable() adds LLEventTrackable objects to mTrackables
+        inline void add_if_trackable(const LLEventTrackable* t) const
+        {
+            if (t)
+            {
+            }
+        }
+
+        // pointer to anything not an LLEventTrackable subclass
+        inline void add_if_trackable(const void*) const
+        {
+        }
+
+        // pointer to free function
+        // The following construct uses the preprocessor to generate
+        // add_if_trackable() overloads accepting pointer-to-function taking
+        // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type.
+#define BOOST_PP_LOCAL_MACRO(n)                                     \
+        template <typename R                                        \
+                  BOOST_PP_COMMA_IF(n)                              \
+                  BOOST_PP_ENUM_PARAMS(n, typename T)>              \
+        inline void                                                 \
+        add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const   \
+        {                                                           \
+        }
+#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY)
+#include BOOST_PP_LOCAL_ITERATE()
+#undef  BOOST_PP_LOCAL_MACRO
+#undef  BOOST_PP_LOCAL_LIMITS
+|*==========================================================================*/
+
+        /// Bind a reference to the LLEventListener to call its track() method.
+        LLEventListener& mListener;
+    };
+
+    /**
+     * Utility template function to use Visitor appropriately
+     *
+     * @param raw_listener Callable to connect, typically a boost::bind()
+     * expression. This will be visited by Visitor using boost::visit_each().
+     * @param connect_funct Callable that will connect() @a raw_listener to an
+     * LLStandardSignal, returning LLBoundListener.
+     */
+    template <typename LISTENER>
+    LLBoundListener visit_and_connect(const LISTENER& raw_listener,
+                                      const ConnectFunc& connect_func)
+    {
+        // Capture the listener
+        LLEventListener listener(raw_listener);
+        // Define our Visitor, binding the listener so we can call
+        // listener.track() if we discover any shared_ptr<Foo>.
+        LLEventDetail::Visitor visitor(listener);
+        // Allow unqualified visit_each() call for ADL
+        using boost::visit_each;
+        // Visit each component of a boost::bind() expression. Pass
+        // 'raw_listener', our template argument, rather than 'listener' from
+        // which type details have been erased. unwrap() comes from
+        // Boost.Signals, in case we were passed a boost::ref().
+        visit_each(visitor, LLEventDetail::unwrap(raw_listener));
+        // Make the connection using passed function. At present, wrapping
+        // this functionality into this function is a bit silly: we don't
+        // really need a visit_and_connect() function any more, just a visit()
+        // function. The definition of this function dates from when, after
+        // visit_each(), after establishing the connection, we had to
+        // postprocess the new connection with the visitor object. That's no
+        // longer necessary.
+        return connect_func(listener);
+    }
+} // namespace LLEventDetail
+
+// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
+// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
+// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
+// specialized for boost::weak_ptr. This remedies that omission.
+namespace boost
+{
+    template <typename T>
+    T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
+}
+
+/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an
+/// easy way to cast to the corresponding weak_ptr.
+template <typename T>
+boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr)
+{
+    return boost::weak_ptr<T>(ptr);
+}
+
+#endif /* ! defined(LL_LLEVENTS_H) */
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 576e45d2aee7f14bd0a983f4735804b6aa8ff5b1..905d736d6213a1a38f1db81e2bced96c40d1ddab 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -1,317 +1,317 @@
-/** 
- * @file llfasttimer.h
- * @brief Declaration of a fast timer.
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- * 
- * Copyright (c) 2004-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_FASTTIMER_H
-#define LL_FASTTIMER_H
-
-#include "llinstancetracker.h"
-
-#define FAST_TIMER_ON 1
-
-#if LL_WINDOWS
-
-// shift off lower 8 bits for lower resolution but longer term timing
-// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
-inline U32 get_cpu_clock_count_32()
-{
-	U32 ret_val;
-	__asm 
-	{
-        _emit   0x0f
-        _emit   0x31
-		shr eax,8
-		shl edx,24
-		or eax, edx
-		mov dword ptr [ret_val], eax
-	}
-    return ret_val;
-}
-
-// return full timer value, still shifted by 8 bits
-inline U64 get_cpu_clock_count_64()
-{
-	U64 ret_val;
-	__asm 
-	{
-        _emit   0x0f
-        _emit   0x31
-		mov eax,eax
-		mov edx,edx
-		mov dword ptr [ret_val+4], edx
-		mov dword ptr [ret_val], eax
-	}
-    return ret_val >> 8;
-}
-
-#endif // LL_WINDOWS
-
-#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
-inline U32 get_cpu_clock_count_32()
-{																	
-	U64 x;															
-	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));					
-	return (U32)x >> 8;													
-}
-
-inline U32 get_cpu_clock_count_64()
-{																	
-	U64 x;
-	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
-	return x >> 8;
-}
-#endif
-
-#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__))
-//
-// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock
-//
-// Just use gettimeofday implementation for now
-
-inline U32 get_cpu_clock_count_32()
-{
-	return (U32)get_clock_count();
-}
-
-inline U32 get_cpu_clock_count_64()
-{																	
-	return get_clock_count();
-}
-#endif
-
-class LLMutex;
-
-#include <queue>
-#include "llsd.h"
-
-
-class LLFastTimer
-{
-public:
-	// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
-	class NamedTimer 
-	:	public LLInstanceTracker<NamedTimer>
-	{
-		friend class DeclareTimer;
-	public:
-		~NamedTimer();
-
-		enum { HISTORY_NUM = 60 };
-
-		const std::string& getName() const { return mName; }
-		NamedTimer* getParent() const { return mParent; }
-		void setParent(NamedTimer* parent);
-		S32 getDepth();
-		std::string getToolTip(S32 history_index = -1);
-
-		typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
-		child_const_iter beginChildren();
-		child_const_iter endChildren();
-		std::vector<NamedTimer*>& getChildren();
-
-		void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
-		bool getCollapsed() const { return mCollapsed; }
-
-		U32 getCountAverage() const { return mCountAverage; }
-		U32 getCallAverage() const { return mCallAverage; }
-
-		U32 getHistoricalCount(S32 history_index = 0) const;
-		U32 getHistoricalCalls(S32 history_index = 0) const;
-
-		static NamedTimer& getRootNamedTimer();
-
-		struct FrameState
-		{
-			FrameState(NamedTimer* timerp);
-
-			U32 		mSelfTimeCounter;
-			U32 		mCalls;
-			FrameState*	mParent;		// info for caller timer
-			FrameState*	mLastCaller;	// used to bootstrap tree construction
-			NamedTimer*	mTimer;
-			U16			mActiveCount;	// number of timers with this ID active on stack
-			bool		mMoveUpTree;	// needs to be moved up the tree of timers at the end of frame
-		};
-
-		S32 getFrameStateIndex() const { return mFrameStateIndex; }
-
-		FrameState& getFrameState() const;
-
-
-	private: 
-		friend class LLFastTimer;
-		friend class NamedTimerFactory;
-
-		//
-		// methods
-		//
-		NamedTimer(const std::string& name);
-		// recursive call to gather total time from children
-		static void accumulateTimings();
-
-		// updates cumulative times and hierarchy, 
-		// can be called multiple times in a frame, at any point
-		static void processTimes();
-
-		static void buildHierarchy();
-		static void resetFrame();
-		static void reset();
-
-	
-		//
-		// members
-		//
-		S32			mFrameStateIndex;
-
-		std::string	mName;
-
-		U32 		mTotalTimeCounter;
-
-		U32 		mCountAverage;
-		U32			mCallAverage;
-
-		U32*		mCountHistory;
-		U32*		mCallHistory;
-
-		// tree structure
-		NamedTimer*					mParent;				// NamedTimer of caller(parent)
-		std::vector<NamedTimer*>	mChildren;
-		bool						mCollapsed;				// don't show children
-		bool						mNeedsSorting;			// sort children whenever child added
-
-	};
-
-	// used to statically declare a new named timer
-	class DeclareTimer 
-	:	public LLInstanceTracker<DeclareTimer>
-	{
-	public:
-		DeclareTimer(const std::string& name, bool open);
-		DeclareTimer(const std::string& name);
-
-		static void updateCachedPointers();
-
-		// convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
-		operator NamedTimer::FrameState&() { return *mFrameState; }
-	private:
-		NamedTimer&				mTimer;
-		NamedTimer::FrameState* mFrameState; 
-	};
-
-
-public:
-	static LLMutex* sLogLock;
-	static std::queue<LLSD> sLogQueue;
-	static BOOL sLog;
-	static BOOL sMetricLog;
-
-	typedef std::vector<NamedTimer::FrameState> info_list_t;
-	static info_list_t& getFrameStateList();
-
-	enum RootTimerMarker { ROOT };
-	LLFastTimer(RootTimerMarker);
-
-	LLFastTimer(NamedTimer::FrameState& timer)
-	:	mFrameState(&timer)
-	{
-#if FAST_TIMER_ON
-		NamedTimer::FrameState* frame_state = &timer;
-		U32 cur_time = get_cpu_clock_count_32();
-		mStartSelfTime = cur_time;
-		mStartTotalTime = cur_time;
-
-		frame_state->mActiveCount++;
-		frame_state->mCalls++;
-		// keep current parent as long as it is active when we are
-		frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
-	
-		mLastTimer = sCurTimer;
-		sCurTimer = this;
-#endif
-	}
-
-	~LLFastTimer()
-	{
-#if FAST_TIMER_ON
-		NamedTimer::FrameState* frame_state = mFrameState;
-		U32 cur_time = get_cpu_clock_count_32();
-		frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
-
-		frame_state->mActiveCount--;
-		LLFastTimer* last_timer = mLastTimer;
-		sCurTimer = last_timer;
-
-		// store last caller to bootstrap tree creation
-		frame_state->mLastCaller = last_timer->mFrameState;
-
-		// we are only tracking self time, so subtract our total time delta from parents
-		U32 total_time = cur_time - mStartTotalTime;
-		last_timer->mStartSelfTime += total_time;
-#endif
-	}
-
-
-	// call this once a frame to reset timers
-	static void nextFrame();
-
-	// dumps current cumulative frame stats to log
-	// call nextFrame() to reset timers
-	static void dumpCurTimes(); 
-
-	// call this to reset timer hierarchy, averages, etc.
-	static void reset();
-
-	static U64 countsPerSecond();
-	static S32 getLastFrameIndex() { return sLastFrameIndex; }
-	static S32 getCurFrameIndex() { return sCurFrameIndex; }
-
-	static void writeLog(std::ostream& os);
-	static const NamedTimer* getTimerByName(const std::string& name);
-
-public:
-	static bool 		sPauseHistory;
-	static bool 		sResetHistory;
-	
-private:
-	typedef std::vector<LLFastTimer*> timer_stack_t;
-	static LLFastTimer*		sCurTimer;
-	static S32				sCurFrameIndex;
-	static S32				sLastFrameIndex;
-	static U64				sLastFrameTime;
-	static info_list_t*		sTimerInfos;
-
-	U32						mStartSelfTime;	// start time + time of all child timers
-	U32						mStartTotalTime;	// start time + time of all child timers
-	NamedTimer::FrameState*	mFrameState;
-	LLFastTimer*			mLastTimer;
-};
-
-#endif // LL_LLFASTTIMER_H
+/** 
+ * @file llfasttimer.h
+ * @brief Declaration of a fast timer.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ * 
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_FASTTIMER_H
+#define LL_FASTTIMER_H
+
+#include "llinstancetracker.h"
+
+#define FAST_TIMER_ON 1
+
+#if LL_WINDOWS
+
+// shift off lower 8 bits for lower resolution but longer term timing
+// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
+inline U32 get_cpu_clock_count_32()
+{
+	U32 ret_val;
+	__asm 
+	{
+        _emit   0x0f
+        _emit   0x31
+		shr eax,8
+		shl edx,24
+		or eax, edx
+		mov dword ptr [ret_val], eax
+	}
+    return ret_val;
+}
+
+// return full timer value, still shifted by 8 bits
+inline U64 get_cpu_clock_count_64()
+{
+	U64 ret_val;
+	__asm 
+	{
+        _emit   0x0f
+        _emit   0x31
+		mov eax,eax
+		mov edx,edx
+		mov dword ptr [ret_val+4], edx
+		mov dword ptr [ret_val], eax
+	}
+    return ret_val >> 8;
+}
+
+#endif // LL_WINDOWS
+
+#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+inline U32 get_cpu_clock_count_32()
+{																	
+	U64 x;															
+	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));					
+	return (U32)x >> 8;													
+}
+
+inline U32 get_cpu_clock_count_64()
+{																	
+	U64 x;
+	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+	return x >> 8;
+}
+#endif
+
+#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__))
+//
+// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock
+//
+// Just use gettimeofday implementation for now
+
+inline U32 get_cpu_clock_count_32()
+{
+	return (U32)get_clock_count();
+}
+
+inline U32 get_cpu_clock_count_64()
+{																	
+	return get_clock_count();
+}
+#endif
+
+class LLMutex;
+
+#include <queue>
+#include "llsd.h"
+
+
+class LL_COMMON_API LLFastTimer
+{
+public:
+	// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
+	class LL_COMMON_API NamedTimer 
+	:	public LLInstanceTracker<NamedTimer>
+	{
+		friend class DeclareTimer;
+	public:
+		~NamedTimer();
+
+		enum { HISTORY_NUM = 60 };
+
+		const std::string& getName() const { return mName; }
+		NamedTimer* getParent() const { return mParent; }
+		void setParent(NamedTimer* parent);
+		S32 getDepth();
+		std::string getToolTip(S32 history_index = -1);
+
+		typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
+		child_const_iter beginChildren();
+		child_const_iter endChildren();
+		std::vector<NamedTimer*>& getChildren();
+
+		void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
+		bool getCollapsed() const { return mCollapsed; }
+
+		U32 getCountAverage() const { return mCountAverage; }
+		U32 getCallAverage() const { return mCallAverage; }
+
+		U32 getHistoricalCount(S32 history_index = 0) const;
+		U32 getHistoricalCalls(S32 history_index = 0) const;
+
+		static NamedTimer& getRootNamedTimer();
+
+		struct FrameState
+		{
+			FrameState(NamedTimer* timerp);
+
+			U32 		mSelfTimeCounter;
+			U32 		mCalls;
+			FrameState*	mParent;		// info for caller timer
+			FrameState*	mLastCaller;	// used to bootstrap tree construction
+			NamedTimer*	mTimer;
+			U16			mActiveCount;	// number of timers with this ID active on stack
+			bool		mMoveUpTree;	// needs to be moved up the tree of timers at the end of frame
+		};
+
+		S32 getFrameStateIndex() const { return mFrameStateIndex; }
+
+		FrameState& getFrameState() const;
+
+
+	private: 
+		friend class LLFastTimer;
+		friend class NamedTimerFactory;
+
+		//
+		// methods
+		//
+		NamedTimer(const std::string& name);
+		// recursive call to gather total time from children
+		static void accumulateTimings();
+
+		// updates cumulative times and hierarchy, 
+		// can be called multiple times in a frame, at any point
+		static void processTimes();
+
+		static void buildHierarchy();
+		static void resetFrame();
+		static void reset();
+
+	
+		//
+		// members
+		//
+		S32			mFrameStateIndex;
+
+		std::string	mName;
+
+		U32 		mTotalTimeCounter;
+
+		U32 		mCountAverage;
+		U32			mCallAverage;
+
+		U32*		mCountHistory;
+		U32*		mCallHistory;
+
+		// tree structure
+		NamedTimer*					mParent;				// NamedTimer of caller(parent)
+		std::vector<NamedTimer*>	mChildren;
+		bool						mCollapsed;				// don't show children
+		bool						mNeedsSorting;			// sort children whenever child added
+
+	};
+
+	// used to statically declare a new named timer
+	class LL_COMMON_API DeclareTimer
+	:	public LLInstanceTracker<DeclareTimer>
+	{
+	public:
+		DeclareTimer(const std::string& name, bool open);
+		DeclareTimer(const std::string& name);
+
+		static void updateCachedPointers();
+
+		// convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
+		operator NamedTimer::FrameState&() { return *mFrameState; }
+	private:
+		NamedTimer&				mTimer;
+		NamedTimer::FrameState* mFrameState; 
+	};
+
+
+public:
+	static LLMutex* sLogLock;
+	static std::queue<LLSD> sLogQueue;
+	static BOOL sLog;
+	static BOOL sMetricLog;
+
+	typedef std::vector<NamedTimer::FrameState> info_list_t;
+	static info_list_t& getFrameStateList();
+
+	enum RootTimerMarker { ROOT };
+	LLFastTimer(RootTimerMarker);
+
+	LLFastTimer(NamedTimer::FrameState& timer)
+	:	mFrameState(&timer)
+	{
+#if FAST_TIMER_ON
+		NamedTimer::FrameState* frame_state = &timer;
+		U32 cur_time = get_cpu_clock_count_32();
+		mStartSelfTime = cur_time;
+		mStartTotalTime = cur_time;
+
+		frame_state->mActiveCount++;
+		frame_state->mCalls++;
+		// keep current parent as long as it is active when we are
+		frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
+	
+		mLastTimer = sCurTimer;
+		sCurTimer = this;
+#endif
+	}
+
+	~LLFastTimer()
+	{
+#if FAST_TIMER_ON
+		NamedTimer::FrameState* frame_state = mFrameState;
+		U32 cur_time = get_cpu_clock_count_32();
+		frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
+
+		frame_state->mActiveCount--;
+		LLFastTimer* last_timer = mLastTimer;
+		sCurTimer = last_timer;
+
+		// store last caller to bootstrap tree creation
+		frame_state->mLastCaller = last_timer->mFrameState;
+
+		// we are only tracking self time, so subtract our total time delta from parents
+		U32 total_time = cur_time - mStartTotalTime;
+		last_timer->mStartSelfTime += total_time;
+#endif
+	}
+
+
+	// call this once a frame to reset timers
+	static void nextFrame();
+
+	// dumps current cumulative frame stats to log
+	// call nextFrame() to reset timers
+	static void dumpCurTimes(); 
+
+	// call this to reset timer hierarchy, averages, etc.
+	static void reset();
+
+	static U64 countsPerSecond();
+	static S32 getLastFrameIndex() { return sLastFrameIndex; }
+	static S32 getCurFrameIndex() { return sCurFrameIndex; }
+
+	static void writeLog(std::ostream& os);
+	static const NamedTimer* getTimerByName(const std::string& name);
+
+public:
+	static bool 		sPauseHistory;
+	static bool 		sResetHistory;
+	
+private:
+	typedef std::vector<LLFastTimer*> timer_stack_t;
+	static LLFastTimer*		sCurTimer;
+	static S32				sCurFrameIndex;
+	static S32				sLastFrameIndex;
+	static U64				sLastFrameTime;
+	static info_list_t*		sTimerInfos;
+
+	U32						mStartSelfTime;	// start time + time of all child timers
+	U32						mStartTotalTime;	// start time + time of all child timers
+	NamedTimer::FrameState*	mFrameState;
+	LLFastTimer*			mLastTimer;
+};
+
+#endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index c6092f7b9c4de29676f1cf1d9e2d5b5b969ff293..fea5d3ed2b8ee3495b73bf2e1c6156ae31cbd36a 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -70,7 +70,7 @@ typedef struct stat		llstat;
 
 #include "llstring.h" // safe char* -> std::string conversion
 
-class	LLFile
+class LL_COMMON_API LLFile
 {
 public:
 	// All these functions take UTF8 path/filenames.
@@ -95,7 +95,7 @@ class	LLFile
 
 #if USE_LLFILESTREAMS
 
-class	llifstream	:	public	std::basic_istream < char , std::char_traits < char > >
+class LL_COMMON_API llifstream	:	public	std::basic_istream < char , std::char_traits < char > >
 {
 	// input stream associated with a C stream
 public:
@@ -136,7 +136,7 @@ class	llifstream	:	public	std::basic_istream < char , std::char_traits < char >
 };
 
 
-class	llofstream	:	public	std::basic_ostream< char , std::char_traits < char > >
+class LL_COMMON_API llofstream	:	public	std::basic_ostream< char , std::char_traits < char > >
 {
 public:
 	typedef std::basic_ostream< char , std::char_traits < char > > _Myt;
@@ -185,7 +185,7 @@ class	llofstream	:	public	std::basic_ostream< char , std::char_traits < char > >
 //#define	llifstream	std::ifstream
 //#define	llofstream	std::ofstream
 
-class	llifstream	:	public	std::ifstream
+class LL_COMMON_API llifstream	:	public	std::ifstream
 {
 public:
 	llifstream() : std::ifstream()
@@ -203,7 +203,7 @@ class	llifstream	:	public	std::ifstream
 };
 
 
-class	llofstream	:	public	std::ofstream
+class LL_COMMON_API llofstream	:	public	std::ofstream
 {
 public:
 	llofstream() : std::ofstream()
@@ -231,7 +231,7 @@ class	llofstream	:	public	std::ofstream
  * and should only be used for config files and the like -- not in a
  * loop.
  */
-std::streamsize llifstream_size(llifstream& fstr);
-std::streamsize llofstream_size(llofstream& fstr);
+std::streamsize LL_COMMON_API llifstream_size(llifstream& fstr);
+std::streamsize LL_COMMON_API llofstream_size(llofstream& fstr);
 
 #endif // not LL_LLFILE_H
diff --git a/indra/llcommon/llfindlocale.h b/indra/llcommon/llfindlocale.h
index f17c7740f38fbba162ad3b17bf4a23eadd6d7831..b812a065db71b291907f488bab75da6e199a5cea 100644
--- a/indra/llcommon/llfindlocale.h
+++ b/indra/llcommon/llfindlocale.h
@@ -59,8 +59,8 @@ typedef enum {
 /* This allocates/fills in a FL_Locale structure with pointers to
    strings (which should be treated as static), or NULL for inappropriate /
    undetected fields. */
-FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain);
+LL_COMMON_API FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain);
 /* This should be used to free the struct written by FL_FindLocale */
-void FL_FreeLocale(FL_Locale **locale);
+LL_COMMON_API void FL_FreeLocale(FL_Locale **locale);
 
 #endif /*__findlocale_h_*/
diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h
index 01b46d327ab08b956665fdef4953639af6ae319b..17fdef27d7d79dda2a0511292d4f38ed4e3fc4eb 100644
--- a/indra/llcommon/llfixedbuffer.h
+++ b/indra/llcommon/llfixedbuffer.h
@@ -41,7 +41,7 @@
 #include "llerrorcontrol.h"
 
 //  fixed buffer implementation
-class LLFixedBuffer : public LLLineBuffer
+class LL_COMMON_API LLFixedBuffer : public LLLineBuffer
 {
 public:
 	LLFixedBuffer(const U32 max_lines = 20);
diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h
index 44c62d971015255cf75c4aea70ba964915157665..dc64edb26da3fdb31b9781cbdf291d4355a0b3e9 100644
--- a/indra/llcommon/llformat.h
+++ b/indra/llcommon/llformat.h
@@ -40,6 +40,6 @@
 // *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
 // should perhaps be replaced with boost::format.
 
-std::string llformat(const char *fmt, ...);
+std::string LL_COMMON_API llformat(const char *fmt, ...);
 
 #endif // LL_LLFORMAT_H
diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h
index 8f51272af24f8fb5b854d78e1067b606329ccb3d..be2d9b070340c30a1b8f8e6ccc30d60ced40fec8 100644
--- a/indra/llcommon/llframetimer.h
+++ b/indra/llcommon/llframetimer.h
@@ -43,7 +43,7 @@
 #include "lltimer.h"
 #include "timing.h"
 
-class LLFrameTimer 
+class LL_COMMON_API LLFrameTimer 
 {
 public:
 	LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {}
diff --git a/indra/llcommon/llheartbeat.h b/indra/llcommon/llheartbeat.h
index fecb5b1e5460d5e11d434a6d8006415519be9017..6f7026970fe4d66c680dbbe14ab1d472a67c21b7 100644
--- a/indra/llcommon/llheartbeat.h
+++ b/indra/llcommon/llheartbeat.h
@@ -40,7 +40,7 @@
 // Note: Win32 does not support the heartbeat/smackdown system;
 //   heartbeat-delivery turns into a no-op there.
 
-class LLHeartbeat
+class LL_COMMON_API LLHeartbeat
 {
 public:
 	// secs_between_heartbeat: after a heartbeat is successfully delivered,
diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h
index 873f50a65ef8abbeb1d2fcdbd2f50025f66cf90f..7544ab1d11ffb2a3f853d1709457186689fbf828 100644
--- a/indra/llcommon/llkeythrottle.h
+++ b/indra/llcommon/llkeythrottle.h
@@ -118,6 +118,63 @@ class LLKeyThrottle
 		THROTTLE_BLOCKED,		// rate exceed, block key
 	};
 
+	F64 getActionCount(const T& id)
+	{
+		U64 now = 0;
+		if ( mIsRealtime )
+		{
+			now = LLKeyThrottleImpl<T>::getTime();
+		}
+		else
+		{
+			now = LLKeyThrottleImpl<T>::getFrame();
+		}
+
+		if (now >= (m.startTime + m.intervalLength))
+		{
+			if (now < (m.startTime + 2 * m.intervalLength))
+			{
+				// prune old data
+				delete m.prevMap;
+				m.prevMap = m.currMap;
+				m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+
+				m.startTime += m.intervalLength;
+			}
+			else
+			{
+				// lots of time has passed, all data is stale
+				delete m.prevMap;
+				delete m.currMap;
+				m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+				m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+
+				m.startTime = now;
+			}
+		}
+
+		U32 prevCount = 0;
+
+		typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
+		if (prev != m.prevMap->end())
+		{
+			prevCount = prev->second.count;
+		}
+
+		typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
+
+		// curr.count is the number of keys in
+		// this current 'time slice' from the beginning of it until now
+		// prevCount is the number of keys in the previous
+		// time slice scaled to be one full time slice back from the current 
+		// (now) time.
+
+		// compute current, windowed rate
+		F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
+		F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
+		return averageCount;
+	}
+
 	// call each time the key wants use
 	State noteAction(const T& id, S32 weight = 1)
 	{
diff --git a/indra/llcommon/llliveappconfig.h b/indra/llcommon/llliveappconfig.h
index a6ece6e8b39caac0236f13ae2ccf2178c134025f..73b3a2335272cd695d2ff9f0d4b108e6faff7d56 100644
--- a/indra/llcommon/llliveappconfig.h
+++ b/indra/llcommon/llliveappconfig.h
@@ -45,7 +45,7 @@
  * loop.  The traditional name for it is live_config.  Be sure to call
  * <code>live_config.checkAndReload()</code> periodically.
  */
-class LLLiveAppConfig : public LLLiveFile
+class LL_COMMON_API LLLiveAppConfig : public LLLiveFile
 {
 public:
 
diff --git a/indra/llcommon/lllivefile.h b/indra/llcommon/lllivefile.h
index 89b5d95e449c0cc211124fa919c213202820f6d8..2453d7a125a6fd44f949df7ae5190329049cda89 100644
--- a/indra/llcommon/lllivefile.h
+++ b/indra/llcommon/lllivefile.h
@@ -36,7 +36,7 @@
 extern const F32 DEFAULT_CONFIG_FILE_REFRESH;
 
 
-class LLLiveFile
+class LL_COMMON_API LLLiveFile
 {
 public:
 	LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f);
diff --git a/indra/llcommon/lllog.h b/indra/llcommon/lllog.h
index 7ac6c8aa42a20cbb50ad1146902cfffec1841b63..4b6777bb9c7fa2fea2a175a64b0b5e3dbac49af6 100644
--- a/indra/llcommon/lllog.h
+++ b/indra/llcommon/lllog.h
@@ -41,7 +41,7 @@ class LLLogImpl;
 class LLApp;
 class LLSD;
 
-class LLLog
+class LL_COMMON_API LLLog
 {
 public:
 	LLLog(LLApp* app);
diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h
index d8bca03e4ecad6b3a23e7176c64aba6cef619173..df9d7324ab67f6a6115c193040f4979133470a54 100644
--- a/indra/llcommon/llmd5.h
+++ b/indra/llcommon/llmd5.h
@@ -80,7 +80,7 @@ const int MD5RAW_BYTES = 16;
 const int MD5HEX_STR_SIZE = 33;  // char hex[MD5HEX_STR_SIZE]; with null
 const int MD5HEX_STR_BYTES = 32; // message system fixed size
 
-class LLMD5 {
+class LL_COMMON_API LLMD5 {
 // first, some types:
   typedef unsigned       int uint4; // assumes integer is 4 words long
   typedef unsigned short int uint2; // assumes short integer is 2 words long
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index f41da37ba649e34b72f9e167457ef19d0c7ddf4f..09f19532b7c56439e2b580cdffd326ba9b14cf1d 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -1,65 +1,65 @@
-/** 
- * @file llmemory.h
- * @brief Memory allocation/deallocation header-stuff goes here.
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- * 
- * Copyright (c) 2002-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-#ifndef LLMEMORY_H
-#define LLMEMORY_H
-
-
-
-extern S32 gTotalDAlloc;
-extern S32 gTotalDAUse;
-extern S32 gDACount;
-
-extern void* ll_allocate (size_t size);
-extern void ll_release (void *p);
-
-class LLMemory
-{
-public:
-	static void initClass();
-	static void cleanupClass();
-	static void freeReserve();
-	// Return the resident set size of the current process, in bytes.
-	// Return value is zero if not known.
-	static U64 getCurrentRSS();
-private:
-	static char* reserveMem;
-};
-
-// LLRefCount moved to llrefcount.h
-
-// LLPointer moved to llpointer.h
-
-// LLSafeHandle moved to llsafehandle.h
-
-// LLSingleton moved to llsingleton.h
-
-#endif
+/** 
+ * @file llmemory.h
+ * @brief Memory allocation/deallocation header-stuff goes here.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#ifndef LLMEMORY_H
+#define LLMEMORY_H
+
+
+
+extern S32 gTotalDAlloc;
+extern S32 gTotalDAUse;
+extern S32 gDACount;
+
+extern void* ll_allocate (size_t size);
+extern void ll_release (void *p);
+
+class LL_COMMON_API LLMemory
+{
+public:
+	static void initClass();
+	static void cleanupClass();
+	static void freeReserve();
+	// Return the resident set size of the current process, in bytes.
+	// Return value is zero if not known.
+	static U64 getCurrentRSS();
+private:
+	static char* reserveMem;
+};
+
+// LLRefCount moved to llrefcount.h
+
+// LLPointer moved to llpointer.h
+
+// LLSafeHandle moved to llsafehandle.h
+
+// LLSingleton moved to llsingleton.h
+
+#endif
diff --git a/indra/llcommon/llmemorystream.h b/indra/llcommon/llmemorystream.h
index f3486324c57b6a0cdf79d0eac00edca48260d250..fa0f5d22f2aa330c468786d81a955b3d12d6a15b 100644
--- a/indra/llcommon/llmemorystream.h
+++ b/indra/llcommon/llmemorystream.h
@@ -52,7 +52,7 @@
  * be careful to always pass in a valid memory location that exists
  * for at least as long as this streambuf.
  */
-class LLMemoryStreamBuf : public std::streambuf
+class LL_COMMON_API LLMemoryStreamBuf : public std::streambuf
 {
 public:
 	LLMemoryStreamBuf(const U8* start, S32 length);
@@ -74,7 +74,7 @@ class LLMemoryStreamBuf : public std::streambuf
  * be careful to always pass in a valid memory location that exists
  * for at least as long as this streambuf.
  */
-class LLMemoryStream : public std::istream
+class LL_COMMON_API LLMemoryStream : public std::istream
 {
 public:
 	LLMemoryStream(const U8* start, S32 length);
diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h
index 12310fcdb4fed67f4a58fddf3a68eea0deba0dec..5952a3a7c5a5b69ea782a1b174aaf145db0aa774 100644
--- a/indra/llcommon/llmemtype.h
+++ b/indra/llcommon/llmemtype.h
@@ -1,248 +1,248 @@
-/** 
- * @file llmemtype.h
- * @brief Runtime memory usage debugging utilities.
- *
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- * 
- * Copyright (c) 2005-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_MEMTYPE_H
-#define LL_MEMTYPE_H
-
-//----------------------------------------------------------------------------
-//----------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------
-
-#include "linden_common.h"
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// WARNING: Never commit with MEM_TRACK_MEM == 1
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-#define MEM_TRACK_MEM (0 && LL_WINDOWS)
-
-#include <vector>
-
-#define MEM_TYPE_NEW(T)
-
-class LLMemType
-{
-public:
-
-	// class we'll initialize all instances of as
-	// static members of MemType.  Then use
-	// to construct any new mem type.
-	class DeclareMemType
-	{
-	public:
-		DeclareMemType(char const * st);
-		~DeclareMemType();
-	
-		S32 mID;
-		char const * mName;
-		
-		// array so we can map an index ID to Name
-		static std::vector<char const *> mNameList;
-	};
-
-	LLMemType(DeclareMemType& dt);
-	~LLMemType();
-
-	static char const * getNameFromID(S32 id);
-
-	static DeclareMemType MTYPE_INIT;
-	static DeclareMemType MTYPE_STARTUP;
-	static DeclareMemType MTYPE_MAIN;
-	static DeclareMemType MTYPE_FRAME;
-
-	static DeclareMemType MTYPE_GATHER_INPUT;
-	static DeclareMemType MTYPE_JOY_KEY;
-
-	static DeclareMemType MTYPE_IDLE;
-	static DeclareMemType MTYPE_IDLE_PUMP;
-	static DeclareMemType MTYPE_IDLE_NETWORK;
-	static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
-	static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
-	static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
-	static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
-	static DeclareMemType MTYPE_IDLE_AUDIO;
-
-	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
-	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
-	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
-
-	static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
-	static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
-
-	static DeclareMemType MTYPE_RENDER;
-	static DeclareMemType MTYPE_SLEEP;
-
-	static DeclareMemType MTYPE_NETWORK;
-	static DeclareMemType MTYPE_PHYSICS;
-	static DeclareMemType MTYPE_INTERESTLIST;
-
-	static DeclareMemType MTYPE_IMAGEBASE;
-	static DeclareMemType MTYPE_IMAGERAW;
-	static DeclareMemType MTYPE_IMAGEFORMATTED;
-	
-	static DeclareMemType MTYPE_APPFMTIMAGE;
-	static DeclareMemType MTYPE_APPRAWIMAGE;
-	static DeclareMemType MTYPE_APPAUXRAWIMAGE;
-	
-	static DeclareMemType MTYPE_DRAWABLE;
-	
-	static DeclareMemType MTYPE_OBJECT;
-	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
-	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
-
-	static DeclareMemType MTYPE_DISPLAY;
-	static DeclareMemType MTYPE_DISPLAY_UPDATE;
-	static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
-	static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
-	static DeclareMemType MTYPE_DISPLAY_SWAP;
-	static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
-	static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
-	static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
-	static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
-	static DeclareMemType MTYPE_DISPLAY_SKY;
-	static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
-	static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
-	static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
-	static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
-
-	static DeclareMemType MTYPE_VERTEX_DATA;
-	static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
-	static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
-	static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
-	static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
-	static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;	
-	static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
-	static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
-	static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
-	static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
-	static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
-	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
-	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
-	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
-	static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
-	static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
-	static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
-	static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
-	static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
-
-	static DeclareMemType MTYPE_SPACE_PARTITION;
-
-	static DeclareMemType MTYPE_PIPELINE;
-	static DeclareMemType MTYPE_PIPELINE_INIT;
-	static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
-	static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
-	static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
-	static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
-	static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
-	static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
-	static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
-	static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
-	static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
-	static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
-	static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
-	static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
-	static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
-	static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
-	static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
-	static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
-	static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
-	static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
-	static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
-	static DeclareMemType MTYPE_PIPELINE_POST_SORT;
-	
-	static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
-	static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
-	static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
-	static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
-	static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
-
-	static DeclareMemType MTYPE_UPKEEP_POOLS;
-
-	static DeclareMemType MTYPE_AVATAR;
-	static DeclareMemType MTYPE_AVATAR_MESH;
-	static DeclareMemType MTYPE_PARTICLES;
-	static DeclareMemType MTYPE_REGIONS;
-
-	static DeclareMemType MTYPE_INVENTORY;
-	static DeclareMemType MTYPE_INVENTORY_DRAW;
-	static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
-	static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
-	static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
-	static DeclareMemType MTYPE_INVENTORY_FROM_XML;
-	static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
-	static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
-	static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
-	static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
-
-	static DeclareMemType MTYPE_ANIMATION;
-	static DeclareMemType MTYPE_VOLUME;
-	static DeclareMemType MTYPE_PRIMITIVE;
-	
-	static DeclareMemType MTYPE_SCRIPT;
-	static DeclareMemType MTYPE_SCRIPT_RUN;
-	static DeclareMemType MTYPE_SCRIPT_BYTECODE;
-	
-	static DeclareMemType MTYPE_IO_PUMP;
-	static DeclareMemType MTYPE_IO_TCP;
-	static DeclareMemType MTYPE_IO_BUFFER;
-	static DeclareMemType MTYPE_IO_HTTP_SERVER;
-	static DeclareMemType MTYPE_IO_SD_SERVER;
-	static DeclareMemType MTYPE_IO_SD_CLIENT;
-	static DeclareMemType MTYPE_IO_URL_REQUEST;
-
-	static DeclareMemType MTYPE_DIRECTX_INIT;
-
-	static DeclareMemType MTYPE_TEMP1;
-	static DeclareMemType MTYPE_TEMP2;
-	static DeclareMemType MTYPE_TEMP3;
-	static DeclareMemType MTYPE_TEMP4;
-	static DeclareMemType MTYPE_TEMP5;
-	static DeclareMemType MTYPE_TEMP6;
-	static DeclareMemType MTYPE_TEMP7;
-	static DeclareMemType MTYPE_TEMP8;
-	static DeclareMemType MTYPE_TEMP9;
-
-	static DeclareMemType MTYPE_OTHER; // Special; used by display code
-
-	S32 mTypeIndex;
-};
-
-//----------------------------------------------------------------------------
-
-#endif
-
+/** 
+ * @file llmemtype.h
+ * @brief Runtime memory usage debugging utilities.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_MEMTYPE_H
+#define LL_MEMTYPE_H
+
+//----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+
+#include "linden_common.h"
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// WARNING: Never commit with MEM_TRACK_MEM == 1
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#define MEM_TRACK_MEM (0 && LL_WINDOWS)
+
+#include <vector>
+
+#define MEM_TYPE_NEW(T)
+
+class LL_COMMON_API LLMemType
+{
+public:
+
+	// class we'll initialize all instances of as
+	// static members of MemType.  Then use
+	// to construct any new mem type.
+	class LL_COMMON_API DeclareMemType
+	{
+	public:
+		DeclareMemType(char const * st);
+		~DeclareMemType();
+	
+		S32 mID;
+		char const * mName;
+		
+		// array so we can map an index ID to Name
+		static std::vector<char const *> mNameList;
+	};
+
+	LLMemType(DeclareMemType& dt);
+	~LLMemType();
+
+	static char const * getNameFromID(S32 id);
+
+	static DeclareMemType MTYPE_INIT;
+	static DeclareMemType MTYPE_STARTUP;
+	static DeclareMemType MTYPE_MAIN;
+	static DeclareMemType MTYPE_FRAME;
+
+	static DeclareMemType MTYPE_GATHER_INPUT;
+	static DeclareMemType MTYPE_JOY_KEY;
+
+	static DeclareMemType MTYPE_IDLE;
+	static DeclareMemType MTYPE_IDLE_PUMP;
+	static DeclareMemType MTYPE_IDLE_NETWORK;
+	static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
+	static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
+	static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
+	static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
+	static DeclareMemType MTYPE_IDLE_AUDIO;
+
+	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
+	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
+	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
+
+	static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
+	static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
+
+	static DeclareMemType MTYPE_RENDER;
+	static DeclareMemType MTYPE_SLEEP;
+
+	static DeclareMemType MTYPE_NETWORK;
+	static DeclareMemType MTYPE_PHYSICS;
+	static DeclareMemType MTYPE_INTERESTLIST;
+
+	static DeclareMemType MTYPE_IMAGEBASE;
+	static DeclareMemType MTYPE_IMAGERAW;
+	static DeclareMemType MTYPE_IMAGEFORMATTED;
+	
+	static DeclareMemType MTYPE_APPFMTIMAGE;
+	static DeclareMemType MTYPE_APPRAWIMAGE;
+	static DeclareMemType MTYPE_APPAUXRAWIMAGE;
+	
+	static DeclareMemType MTYPE_DRAWABLE;
+	
+	static DeclareMemType MTYPE_OBJECT;
+	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
+	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
+
+	static DeclareMemType MTYPE_DISPLAY;
+	static DeclareMemType MTYPE_DISPLAY_UPDATE;
+	static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
+	static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
+	static DeclareMemType MTYPE_DISPLAY_SWAP;
+	static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
+	static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
+	static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
+	static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
+	static DeclareMemType MTYPE_DISPLAY_SKY;
+	static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
+	static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
+	static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
+	static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
+
+	static DeclareMemType MTYPE_VERTEX_DATA;
+	static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
+	static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
+	static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
+	static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
+	static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;	
+	static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
+	static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
+	static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
+	static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
+	static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
+	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
+	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
+	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
+	static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
+	static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
+	static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
+	static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
+	static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
+
+	static DeclareMemType MTYPE_SPACE_PARTITION;
+
+	static DeclareMemType MTYPE_PIPELINE;
+	static DeclareMemType MTYPE_PIPELINE_INIT;
+	static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
+	static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
+	static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
+	static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
+	static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
+	static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
+	static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
+	static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
+	static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
+	static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
+	static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
+	static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
+	static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
+	static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
+	static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
+	static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
+	static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
+	static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
+	static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
+	static DeclareMemType MTYPE_PIPELINE_POST_SORT;
+	
+	static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
+	static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
+	static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
+	static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
+	static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
+
+	static DeclareMemType MTYPE_UPKEEP_POOLS;
+
+	static DeclareMemType MTYPE_AVATAR;
+	static DeclareMemType MTYPE_AVATAR_MESH;
+	static DeclareMemType MTYPE_PARTICLES;
+	static DeclareMemType MTYPE_REGIONS;
+
+	static DeclareMemType MTYPE_INVENTORY;
+	static DeclareMemType MTYPE_INVENTORY_DRAW;
+	static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
+	static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
+	static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
+	static DeclareMemType MTYPE_INVENTORY_FROM_XML;
+	static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
+	static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
+	static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
+	static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
+
+	static DeclareMemType MTYPE_ANIMATION;
+	static DeclareMemType MTYPE_VOLUME;
+	static DeclareMemType MTYPE_PRIMITIVE;
+	
+	static DeclareMemType MTYPE_SCRIPT;
+	static DeclareMemType MTYPE_SCRIPT_RUN;
+	static DeclareMemType MTYPE_SCRIPT_BYTECODE;
+	
+	static DeclareMemType MTYPE_IO_PUMP;
+	static DeclareMemType MTYPE_IO_TCP;
+	static DeclareMemType MTYPE_IO_BUFFER;
+	static DeclareMemType MTYPE_IO_HTTP_SERVER;
+	static DeclareMemType MTYPE_IO_SD_SERVER;
+	static DeclareMemType MTYPE_IO_SD_CLIENT;
+	static DeclareMemType MTYPE_IO_URL_REQUEST;
+
+	static DeclareMemType MTYPE_DIRECTX_INIT;
+
+	static DeclareMemType MTYPE_TEMP1;
+	static DeclareMemType MTYPE_TEMP2;
+	static DeclareMemType MTYPE_TEMP3;
+	static DeclareMemType MTYPE_TEMP4;
+	static DeclareMemType MTYPE_TEMP5;
+	static DeclareMemType MTYPE_TEMP6;
+	static DeclareMemType MTYPE_TEMP7;
+	static DeclareMemType MTYPE_TEMP8;
+	static DeclareMemType MTYPE_TEMP9;
+
+	static DeclareMemType MTYPE_OTHER; // Special; used by display code
+
+	S32 mTypeIndex;
+};
+
+//----------------------------------------------------------------------------
+
+#endif
+
diff --git a/indra/llcommon/llmetrics.h b/indra/llcommon/llmetrics.h
index 1d91e8c8a287c618c8bec4e42b5191d22976616d..f6f49eb4562b2f70ced98d14ffd0f9703f86aa34 100644
--- a/indra/llcommon/llmetrics.h
+++ b/indra/llcommon/llmetrics.h
@@ -38,7 +38,7 @@
 class LLMetricsImpl;
 class LLSD;
 
-class LLMetrics
+class LL_COMMON_API LLMetrics
 {
 public:
 	LLMetrics();
diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h
index fcda3df58e3eae9e5865d790ec6a4b010a6d9b8f..27bd8cd9b5c2ef2962e659ab26cd1d4d5a84ba1c 100644
--- a/indra/llcommon/llmortician.h
+++ b/indra/llcommon/llmortician.h
@@ -35,7 +35,7 @@
 
 #include "stdtypes.h"
 
-class LLMortician 
+class LL_COMMON_API LLMortician 
 {
 public:
 	LLMortician() { mIsDead = FALSE; }
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index bb598a2be1b494b5a314a147bae81912af2a722e..48baa50edbe809cd5a8c4f850966f281ea5f7955 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -1,142 +1,168 @@
-/** 
- * @file llpreprocessor.h
- * @brief This file should be included in all Linden Lab files and
- * should only contain special preprocessor directives
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- * 
- * Copyright (c) 2001-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LLPREPROCESSOR_H
-#define LLPREPROCESSOR_H
-
-// Figure out endianness of platform
-#ifdef LL_LINUX
-#define __ENABLE_WSTRING
-#include <endian.h>
-#endif	//	LL_LINUX
-
-#if LL_SOLARIS
-#   ifdef  __sparc     // Since we're talking Solaris 10 and up, only 64 bit is supported.
-#      define LL_BIG_ENDIAN 1
-#      define LL_SOLARIS_ALIGNED_CPU 1     //  used to designate issues where SPARC alignment is addressed
-#      define LL_SOLARIS_NON_MESA_GL 1      //  The SPARC GL does not provide a MESA-based GL API
-#   endif
-#   include <sys/isa_defs.h> // ensure we know which end is up
-#endif // LL_SOLARIS
-
-#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386)))
-#define LL_LITTLE_ENDIAN 1
-#else
-#define LL_BIG_ENDIAN 1
-#endif
-
-// Per-compiler switches
-#ifdef __GNUC__
-#define LL_FORCE_INLINE inline __attribute__((always_inline))
-#else
-#define LL_FORCE_INLINE __forceinline
-#endif
-
-// Figure out differences between compilers
-#if defined(__GNUC__)
-	#define GCC_VERSION (__GNUC__ * 10000 \
-						+ __GNUC_MINOR__ * 100 \
-						+ __GNUC_PATCHLEVEL__)
-	#ifndef LL_GNUC
-		#define LL_GNUC 1
-	#endif
-#elif defined(__MSVC_VER__) || defined(_MSC_VER)
-	#ifndef LL_MSVC
-		#define LL_MSVC 1
-	#endif
-	#if _MSC_VER < 1400
-		#define LL_MSVC7 //Visual C++ 2003 or earlier
-	#endif
-#endif
-
-// Deal with minor differences on Unixy OSes.
-#if LL_DARWIN || LL_LINUX
-	// Different name, same functionality.
-	#define stricmp strcasecmp
-	#define strnicmp strncasecmp
-
-	// Not sure why this is different, but...
-	#ifndef MAX_PATH
-		#define MAX_PATH PATH_MAX
-	#endif	//	not MAX_PATH
-
-#endif
-
-
-// Deal with the differeneces on Windows
-#if LL_MSVC
-namespace snprintf_hack
-{
-	int snprintf(char *str, size_t size, const char *format, ...);
-}
-
-// #define snprintf safe_snprintf		/* Flawfinder: ignore */
-using snprintf_hack::snprintf;
-#endif	// LL_MSVC
-
-// Static linking with apr on windows needs to be declared.
-#ifdef LL_WINDOWS
-#ifndef APR_DECLARE_STATIC
-#define APR_DECLARE_STATIC // For APR on Windows
-#endif
-#ifndef APU_DECLARE_STATIC
-#define APU_DECLARE_STATIC // For APR util on Windows
-#endif
-#endif
-
-#if defined(LL_WINDOWS)
-#define BOOST_REGEX_NO_LIB 1
-#define CURL_STATICLIB 1
-#ifndef XML_STATIC
-#define XML_STATIC
-#endif
-#endif	//	LL_WINDOWS
-
-
-// Deal with VC6 problems
-#if LL_MSVC
-#pragma warning( 3	     : 4701 )	// "local variable used without being initialized"  Treat this as level 3, not level 4.
-#pragma warning( 3	     : 4702 )	// "unreachable code"  Treat this as level 3, not level 4.
-#pragma warning( 3	     : 4189 )	// "local variable initialized but not referenced"  Treat this as level 3, not level 4.
-//#pragma warning( 3	: 4018 )	// "signed/unsigned mismatch"  Treat this as level 3, not level 4.
-#pragma warning( 3      :  4263 )	// 'function' : member function does not override any base class virtual member function
-#pragma warning( 3      :  4264 )	// "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden"
-#pragma warning( 3       : 4265 )	// "class has virtual functions, but destructor is not virtual"
-#pragma warning( 3      :  4266 )	// 'function' : no override available for virtual member function from base 'type'; function is hidden
-#pragma warning( disable : 4284 )	// silly MS warning deep inside their <map> include file
-#pragma warning( disable : 4503 )	// 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
-#pragma warning( disable : 4800 )	// 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
-#pragma warning( disable : 4996 )	// warning: deprecated
-#endif	//	LL_MSVC
-
-#endif	//	not LL_LINDEN_PREPROCESSOR_H
+/** 
+ * @file llpreprocessor.h
+ * @brief This file should be included in all Linden Lab files and
+ * should only contain special preprocessor directives
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLPREPROCESSOR_H
+#define LLPREPROCESSOR_H
+
+// Figure out endianness of platform
+#ifdef LL_LINUX
+#define __ENABLE_WSTRING
+#include <endian.h>
+#endif	//	LL_LINUX
+
+#if LL_SOLARIS
+#   ifdef  __sparc     // Since we're talking Solaris 10 and up, only 64 bit is supported.
+#      define LL_BIG_ENDIAN 1
+#      define LL_SOLARIS_ALIGNED_CPU 1     //  used to designate issues where SPARC alignment is addressed
+#      define LL_SOLARIS_NON_MESA_GL 1      //  The SPARC GL does not provide a MESA-based GL API
+#   endif
+#   include <sys/isa_defs.h> // ensure we know which end is up
+#endif // LL_SOLARIS
+
+#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386)))
+#define LL_LITTLE_ENDIAN 1
+#else
+#define LL_BIG_ENDIAN 1
+#endif
+
+// Per-compiler switches
+#ifdef __GNUC__
+#define LL_FORCE_INLINE inline __attribute__((always_inline))
+#else
+#define LL_FORCE_INLINE __forceinline
+#endif
+
+// Figure out differences between compilers
+#if defined(__GNUC__)
+	#define GCC_VERSION (__GNUC__ * 10000 \
+						+ __GNUC_MINOR__ * 100 \
+						+ __GNUC_PATCHLEVEL__)
+	#ifndef LL_GNUC
+		#define LL_GNUC 1
+	#endif
+#elif defined(__MSVC_VER__) || defined(_MSC_VER)
+	#ifndef LL_MSVC
+		#define LL_MSVC 1
+	#endif
+	#if _MSC_VER < 1400
+		#define LL_MSVC7 //Visual C++ 2003 or earlier
+	#endif
+#endif
+
+// Deal with minor differences on Unixy OSes.
+#if LL_DARWIN || LL_LINUX
+	// Different name, same functionality.
+	#define stricmp strcasecmp
+	#define strnicmp strncasecmp
+
+	// Not sure why this is different, but...
+	#ifndef MAX_PATH
+		#define MAX_PATH PATH_MAX
+	#endif	//	not MAX_PATH
+
+#endif
+
+
+// Static linking with apr on windows needs to be declared.
+#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
+#ifndef APR_DECLARE_STATIC
+#define APR_DECLARE_STATIC // For APR on Windows
+#endif
+#ifndef APU_DECLARE_STATIC
+#define APU_DECLARE_STATIC // For APR util on Windows
+#endif
+#endif
+
+#if defined(LL_WINDOWS)
+#define BOOST_REGEX_NO_LIB 1
+#define CURL_STATICLIB 1
+#ifndef XML_STATIC
+#define XML_STATIC
+#endif
+#endif	//	LL_WINDOWS
+
+
+// Deal with VC6 problems
+#if LL_MSVC
+#pragma warning( 3	     : 4701 )	// "local variable used without being initialized"  Treat this as level 3, not level 4.
+#pragma warning( 3	     : 4702 )	// "unreachable code"  Treat this as level 3, not level 4.
+#pragma warning( 3	     : 4189 )	// "local variable initialized but not referenced"  Treat this as level 3, not level 4.
+//#pragma warning( 3	: 4018 )	// "signed/unsigned mismatch"  Treat this as level 3, not level 4.
+#pragma warning( 3      :  4263 )	// 'function' : member function does not override any base class virtual member function
+#pragma warning( 3      :  4264 )	// "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden"
+#pragma warning( 3       : 4265 )	// "class has virtual functions, but destructor is not virtual"
+#pragma warning( 3      :  4266 )	// 'function' : no override available for virtual member function from base 'type'; function is hidden
+#pragma warning( disable : 4284 )	// silly MS warning deep inside their <map> include file
+#pragma warning( disable : 4503 )	// 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
+#pragma warning( disable : 4800 )	// 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
+#pragma warning( disable : 4996 )	// warning: deprecated
+
+// level 4 warnings that we need to disable:
+#pragma warning (disable : 4100) // unreferenced formal parameter
+#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) )
+#pragma warning (disable : 4244) // possible loss of data on conversions
+#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
+#pragma warning (disable : 4512) // assignment operator could not be generated
+#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) )
+
+#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
+#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class
+#endif	//	LL_MSVC
+
+#if LL_WINDOWS
+#define LL_DLLEXPORT __declspec(dllexport)
+#define LL_DLLIMPORT __declspec(dllimport)
+#elif LL_LINUX
+#define LL_DLLEXPORT __attribute__ ((visibility("default")))
+#define LL_DLLIMPORT
+#else
+#define LL_DLLEXPORT
+#define LL_DLLIMPORT
+#endif // LL_WINDOWS
+
+#if LL_COMMON_LINK_SHARED
+// CMake automagically defines llcommon_EXPORTS only when building llcommon
+// sources, and only when llcommon is a shared library (i.e. when
+// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
+// otherwise we can't distinguish between (non-llcommon source) and (llcommon
+// not shared).
+# if defined(llcommon_EXPORTS)
+#   define LL_COMMON_API LL_DLLEXPORT
+# else //llcommon_EXPORTS
+#   define LL_COMMON_API LL_DLLIMPORT
+# endif //llcommon_EXPORTS
+#else // LL_COMMON_LINK_SHARED
+# define LL_COMMON_API
+#endif // LL_COMMON_LINK_SHARED
+
+#endif	//	not LL_LINDEN_PREPROCESSOR_H
diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h
index a1b8e22691f4137fbde0e11338c77762d83c8222..880562157fbcdb6f4f6cd8a8481ec6e4993d71c6 100644
--- a/indra/llcommon/llprocesslauncher.h
+++ b/indra/llcommon/llprocesslauncher.h
@@ -42,7 +42,7 @@
 	It also keeps track of whether the process is still running, and can kill it if required.
 */
 
-class LLProcessLauncher
+class LL_COMMON_API LLProcessLauncher
 {
 	LOG_CLASS(LLProcessLauncher);
 public:
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index 3ba43e1e070db57c3ffa3d7b15744163e45b3988..8bfa5632a162ee4da4f0cd8587bb316c6914fe76 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -47,7 +47,7 @@
 // Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small
 //   It is assumed that LLQueuedThreads are rarely created/destroyed.
 
-class LLQueuedThread : public LLThread
+class LL_COMMON_API LLQueuedThread : public LLThread
 {
 	//------------------------------------------------------------------------
 public:
@@ -80,7 +80,7 @@ class LLQueuedThread : public LLThread
 	//------------------------------------------------------------------------
 public:
 
-	class QueuedRequest : public LLSimpleHashEntry<handle_t>
+	class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry<handle_t>
 	{
 		friend class LLQueuedThread;
 		
@@ -148,6 +148,7 @@ class LLQueuedThread : public LLThread
 		}
 	};
 
+
 	//------------------------------------------------------------------------
 	
 public:
diff --git a/indra/llcommon/llrand.h b/indra/llcommon/llrand.h
index d12597bb53e727f714c45f532ff38f5fc5e4b2df..30fec9b982b25234f7139bd3753b57230a22cf6a 100644
--- a/indra/llcommon/llrand.h
+++ b/indra/llcommon/llrand.h
@@ -65,32 +65,32 @@
 /**
  *@brief Generate a float from [0, RAND_MAX).
  */
-S32 ll_rand();
+S32 LL_COMMON_API ll_rand();
 
 /**
  *@brief Generate a float from [0, val) or (val, 0].
  */
-S32 ll_rand(S32 val);
+S32 LL_COMMON_API ll_rand(S32 val);
 
 /**
  *@brief Generate a float from [0, 1.0).
  */
-F32 ll_frand();
+F32 LL_COMMON_API ll_frand();
 
 /**
  *@brief Generate a float from [0, val) or (val, 0].
  */
-F32 ll_frand(F32 val);
+F32 LL_COMMON_API ll_frand(F32 val);
 
 /**
  *@brief Generate a double from [0, 1.0).
  */
-F64 ll_drand();
+F64 LL_COMMON_API ll_drand();
 
 /**
  *@brief Generate a double from [0, val) or (val, 0].
  */
-F64 ll_drand(F64 val);
+F64 LL_COMMON_API ll_drand(F64 val);
 
 /**
  * @brief typedefs for good boost lagged fibonacci.
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index d3597b454c87885f8fa449bd2c6651ba75feaab7..9ab844eb22ee03ff8647b9d736f226c72f5d2763 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -39,9 +39,9 @@
 // see llthread.h for LLThreadSafeRefCount
 //----------------------------------------------------------------------------
 
-class LLRefCount
+class LL_COMMON_API LLRefCount
 {
-protected:
+private:
 	LLRefCount(const LLRefCount& other); // no implementation
 private:
 	LLRefCount& operator=(const LLRefCount&); // no implementation
diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h
index 77b23d9051f1ffa0fe60e9c6d4a6d2d50ac1b6d9..1fc9925df9ca15c447c9d03bb29b31061d559b00 100644
--- a/indra/llcommon/llrun.h
+++ b/indra/llcommon/llrun.h
@@ -48,7 +48,7 @@ class LLRunnable;
  * which are scheduled to run on a repeating or one time basis.
  * @see LLRunnable
  */
-class LLRunner
+class LL_COMMON_API LLRunner
 {
 public:
 	/**
@@ -149,7 +149,7 @@ class LLRunner
  * something useful.
  * @see LLRunner
  */
-class LLRunnable
+class LL_COMMON_API LLRunnable
 {
 public:
 	LLRunnable();
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index d2845a3757e205dbd06cbbcb0b6a740f0b1cca7f..552bb57498e6280407fe02d4181d2fea920aed0a 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -89,7 +89,7 @@
 	@nosubgrouping
 */
 
-class LLSD
+class LL_COMMON_API LLSD
 {
 public:
 		LLSD();		///< initially Undefined
@@ -387,7 +387,7 @@ struct llsd_select_string : public std::unary_function<LLSD, LLSD::String>
 	}
 };
 
-std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
 
 /** QUESTIONS & TO DOS
 	- Would Binary be more convenient as usigned char* buffer semantics?
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 7463d1e5ddd345067d3ee7d2335ff9b1e84678a9..2f2b292189bf099373899d3eb48d0ddddc16d74c 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -44,7 +44,7 @@
  * @class LLSDParser
  * @brief Abstract base class for LLSD parsers.
  */
-class LLSDParser : public LLRefCount
+class LL_COMMON_API LLSDParser : public LLRefCount
 {
 protected:
 	/** 
@@ -221,7 +221,7 @@ class LLSDParser : public LLRefCount
  * @class LLSDNotationParser
  * @brief Parser which handles the original notation format for LLSD.
  */
-class LLSDNotationParser : public LLSDParser
+class LL_COMMON_API LLSDNotationParser : public LLSDParser
 {
 protected:
 	/** 
@@ -294,7 +294,7 @@ class LLSDNotationParser : public LLSDParser
  * @class LLSDXMLParser
  * @brief Parser which handles XML format LLSD.
  */
-class LLSDXMLParser : public LLSDParser
+class LL_COMMON_API LLSDXMLParser : public LLSDParser
 {
 protected:
 	/** 
@@ -342,7 +342,7 @@ class LLSDXMLParser : public LLSDParser
  * @class LLSDBinaryParser
  * @brief Parser which handles binary formatted LLSD.
  */
-class LLSDBinaryParser : public LLSDParser
+class LL_COMMON_API LLSDBinaryParser : public LLSDParser
 {
 protected:
 	/** 
@@ -407,7 +407,7 @@ class LLSDBinaryParser : public LLSDParser
  * @class LLSDFormatter
  * @brief Abstract base class for formatting LLSD.
  */
-class LLSDFormatter : public LLRefCount
+class LL_COMMON_API LLSDFormatter : public LLRefCount
 {
 protected:
 	/** 
@@ -479,7 +479,7 @@ class LLSDFormatter : public LLRefCount
  * @class LLSDNotationFormatter
  * @brief Formatter which outputs the original notation format for LLSD.
  */
-class LLSDNotationFormatter : public LLSDFormatter
+class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter
 {
 protected:
 	/** 
@@ -520,7 +520,7 @@ class LLSDNotationFormatter : public LLSDFormatter
  * @class LLSDXMLFormatter
  * @brief Formatter which outputs the LLSD as XML.
  */
-class LLSDXMLFormatter : public LLSDFormatter
+class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter
 {
 protected:
 	/** 
@@ -588,7 +588,7 @@ class LLSDXMLFormatter : public LLSDFormatter
  * Map: '{' + 4 byte integer size  every(key + value) + '}'<br>
  *  map keys are serialized as 'k' + 4 byte integer size + string
  */
-class LLSDBinaryFormatter : public LLSDFormatter
+class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter
 {
 protected:
 	/** 
@@ -638,9 +638,14 @@ class LLSDBinaryFormatter : public LLSDFormatter
  *	params << "[{'version':i1}," << LLSDOStreamer<LLSDNotationFormatter>(sd)
  *    << "]";
  *  </code>
+ *
+ * *NOTE - formerly this class inherited from its template parameter Formatter,
+ * but all insnatiations passed in LLRefCount subclasses.  This conflicted with
+ * the auto allocation intended for this class template (demonstrated in the
+ * example above).  -brad
  */
 template <class Formatter>
-class LLSDOStreamer : public Formatter
+class LLSDOStreamer
 {
 public:
 	/** 
@@ -661,7 +666,8 @@ class LLSDOStreamer : public Formatter
 		std::ostream& str,
 		const LLSDOStreamer<Formatter>& formatter)
 	{
-		formatter.format(formatter.mSD, str, formatter.mOptions);
+		LLPointer<Formatter> f = new Formatter;
+		f->format(formatter.mSD, str, formatter.mOptions);
 		return str;
 	}
 
@@ -677,7 +683,7 @@ typedef LLSDOStreamer<LLSDXMLFormatter>			LLSDXMLStreamer;
  * @class LLSDSerialize
  * @brief Serializer / deserializer for the various LLSD formats
  */
-class LLSDSerialize
+class LL_COMMON_API LLSDSerialize
 {
 public:
 	enum ELLSD_Serialize
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index c12ca350de53f301860ed57bd42c2f8e323a82fc..7e1c2e35e0da678d2fdf7d0acbfde9c001fa6173 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -37,6 +37,7 @@
 #include <deque>
 
 #include "apr_base64.h"
+#include <boost/regex.hpp>
 
 extern "C"
 {
@@ -777,10 +778,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
 		
 		case ELEMENT_BINARY:
 		{
-			S32 len = apr_base64_decode_len(mCurrentContent.c_str());
+			// Regex is expensive, but only fix for whitespace in base64,
+			// created by python and other non-linden systems - DEV-39358
+			// Fortunately we have very little binary passing now,
+			// so performance impact shold be negligible. + poppy 2009-09-04
+			boost::regex r;
+			r.assign("\\s");
+			std::string stripped = boost::regex_replace(mCurrentContent, r, "");
+			S32 len = apr_base64_decode_len(stripped.c_str());
 			std::vector<U8> data;
 			data.resize(len);
-			len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
+			len = apr_base64_decode_binary(&data[0], stripped.c_str());
 			data.resize(len);
 			value = data;
 			break;
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index 0202a033c3ccab7d5bd87f7d11701ad62f20d07c..c8d8030e87550363bdb0e46e5b9be14a2d20003d 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -46,6 +46,11 @@
 #endif
 
 #include "llsdserialize.h"
+#include "stringize.h"
+
+#include <map>
+#include <set>
+#include <boost/range.hpp>
 
 // U32
 LLSD ll_sd_from_U32(const U32 val)
@@ -313,3 +318,353 @@ BOOL compare_llsd_with_template(
 
 	return TRUE;
 }
+
+/*****************************************************************************
+*   Helpers for llsd_matches()
+*****************************************************************************/
+// raw data used for LLSD::Type lookup
+struct Data
+{
+    LLSD::Type type;
+    const char* name;
+} typedata[] =
+{
+#define def(type) { LLSD::type, #type + 4 }
+    def(TypeUndefined),
+    def(TypeBoolean),
+    def(TypeInteger),
+    def(TypeReal),
+    def(TypeString),
+    def(TypeUUID),
+    def(TypeDate),
+    def(TypeURI),
+    def(TypeBinary),
+    def(TypeMap),
+    def(TypeArray)
+#undef  def
+};
+
+// LLSD::Type lookup class into which we load the above static data
+class TypeLookup
+{
+    typedef std::map<LLSD::Type, std::string> MapType;
+
+public:
+    TypeLookup()
+    {
+        for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
+        {
+            mMap[di->type] = di->name;
+        }
+    }
+
+    std::string lookup(LLSD::Type type) const
+    {
+        MapType::const_iterator found = mMap.find(type);
+        if (found != mMap.end())
+        {
+            return found->second;
+        }
+        return STRINGIZE("<unknown LLSD type " << type << ">");
+    }
+
+private:
+    MapType mMap;
+};
+
+// static instance of the lookup class
+static const TypeLookup sTypes;
+
+// describe a mismatch; phrasing may want tweaking
+const std::string op(" required instead of ");
+
+// llsd_matches() wants to identify specifically where in a complex prototype
+// structure the mismatch occurred. This entails passing a prefix string,
+// empty for the top-level call. If the prototype contains an array of maps,
+// and the mismatch occurs in the second map in a key 'foo', we want to
+// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
+// want to omit the entire prefix -- including colon -- if the mismatch is at
+// top level. This helper accepts the (possibly empty) recursively-accumulated
+// prefix string, returning either empty or the original string with colon
+// appended.
+static std::string colon(const std::string& pfx)
+{
+    if (pfx.empty())
+        return pfx;
+    return pfx + ": ";
+}
+
+// param type for match_types
+typedef std::vector<LLSD::Type> TypeVector;
+
+// The scalar cases in llsd_matches() use this helper. In most cases, we can
+// accept not only the exact type specified in the prototype, but also other
+// types convertible to the expected type. That implies looping over an array
+// of such types. If the actual type doesn't match any of them, we want to
+// provide a list of acceptable conversions as well as the exact type, e.g.:
+// "Integer (or Boolean, Real, String) required instead of UUID". Both the
+// implementation and the calling logic are simplified by separating out the
+// expected type from the convertible types.
+static std::string match_types(LLSD::Type expect, // prototype.type()
+                               const TypeVector& accept, // types convertible to that type
+                               LLSD::Type actual,        // type we're checking
+                               const std::string& pfx)   // as for llsd_matches
+{
+    // Trivial case: if the actual type is exactly what we expect, we're good.
+    if (actual == expect)
+        return "";
+
+    // For the rest of the logic, build up a suitable error string as we go so
+    // we only have to make a single pass over the list of acceptable types.
+    // If we detect success along the way, we'll simply discard the partial
+    // error string.
+    std::ostringstream out;
+    out << colon(pfx) << sTypes.lookup(expect);
+
+    // If there are any convertible types, append that list.
+    if (! accept.empty())
+    {
+        out << " (";
+        const char* sep = "or ";
+        for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
+             ai != aend; ++ai, sep = ", ")
+        {
+            // Don't forget to return success if we match any of those types...
+            if (actual == *ai)
+                return "";
+            out << sep << sTypes.lookup(*ai);
+        }
+        out << ')';
+    }
+    // If we got this far, it's because 'actual' was not one of the acceptable
+    // types, so we must return an error. 'out' already contains colon(pfx)
+    // and the formatted list of acceptable types, so just append the mismatch
+    // phrase and the actual type.
+    out << op << sTypes.lookup(actual);
+    return out.str();
+}
+
+// see docstring in .h file
+std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
+{
+    // An undefined prototype means that any data is valid.
+    // An undefined slot in an array or map prototype means that any data
+    // may fill that slot.
+    if (prototype.isUndefined())
+        return "";
+    // A prototype array must match a data array with at least as many
+    // entries. Moreover, every prototype entry must match the
+    // corresponding data entry.
+    if (prototype.isArray())
+    {
+        if (! data.isArray())
+        {
+            return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
+        }
+        if (data.size() < prototype.size())
+        {
+            return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
+                             << "Array size " << data.size());
+        }
+        for (LLSD::Integer i = 0; i < prototype.size(); ++i)
+        {
+            std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
+            if (! match.empty())
+            {
+                return match;
+            }
+        }
+        return "";
+    }
+    // A prototype map must match a data map. Every key in the prototype
+    // must have a corresponding key in the data map; every value in the
+    // prototype must match the corresponding key's value in the data.
+    if (prototype.isMap())
+    {
+        if (! data.isMap())
+        {
+            return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
+        }
+        // If there are a number of keys missing from the data, it would be
+        // frustrating to a coder to discover them one at a time, with a big
+        // build each time. Enumerate all missing keys.
+        std::ostringstream out;
+        out << colon(pfx);
+        const char* init = "Map missing keys: ";
+        const char* sep = init;
+        for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
+        {
+            if (! data.has(mi->first))
+            {
+                out << sep << mi->first;
+                sep = ", ";
+            }
+        }
+        // So... are we missing any keys?
+        if (sep != init)
+        {
+            return out.str();
+        }
+        // Good, the data block contains all the keys required by the
+        // prototype. Now match the prototype entries.
+        for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
+        {
+            std::string match(llsd_matches(mi2->second, data[mi2->first],
+                                           STRINGIZE("['" << mi2->first << "']")));
+            if (! match.empty())
+            {
+                return match;
+            }
+        }
+        return "";
+    }
+    // A String prototype can match String, Boolean, Integer, Real, UUID,
+    // Date and URI, because any of these can be converted to String.
+    if (prototype.isString())
+    {
+        static LLSD::Type accept[] =
+        {
+            LLSD::TypeBoolean,
+            LLSD::TypeInteger,
+            LLSD::TypeReal,
+            LLSD::TypeUUID,
+            LLSD::TypeDate,
+            LLSD::TypeURI
+        };
+        return match_types(prototype.type(),
+                           TypeVector(boost::begin(accept), boost::end(accept)),
+                           data.type(),
+                           pfx);
+    }
+    // Boolean, Integer, Real match each other or String. TBD: ensure that
+    // a String value is numeric.
+    if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
+    {
+        static LLSD::Type all[] =
+        {
+            LLSD::TypeBoolean,
+            LLSD::TypeInteger,
+            LLSD::TypeReal,
+            LLSD::TypeString
+        };
+        // Funny business: shuffle the set of acceptable types to include all
+        // but the prototype's type. Get the acceptable types in a set.
+        std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
+        // Remove the prototype's type because we pass that separately.
+        rest.erase(prototype.type());
+        return match_types(prototype.type(),
+                           TypeVector(rest.begin(), rest.end()),
+                           data.type(),
+                           pfx);
+    }
+    // UUID, Date and URI match themselves or String.
+    if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
+    {
+        static LLSD::Type accept[] =
+        {
+            LLSD::TypeString
+        };
+        return match_types(prototype.type(),
+                           TypeVector(boost::begin(accept), boost::end(accept)),
+                           data.type(),
+                           pfx);
+    }
+    // We don't yet know the conversion semantics associated with any new LLSD
+    // data type that might be added, so until we've been extended to handle
+    // them, assume it's strict: the new type matches only itself. (This is
+    // true of Binary, which is why we don't handle that case separately.) Too
+    // bad LLSD doesn't define isConvertible(Type to, Type from).
+    return match_types(prototype.type(), TypeVector(), data.type(), pfx);
+}
+
+bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
+{
+    // We're comparing strict equality of LLSD representation rather than
+    // performing any conversions. So if the types aren't equal, the LLSD
+    // values aren't equal.
+    if (lhs.type() != rhs.type())
+    {
+        return false;
+    }
+
+    // Here we know both types are equal. Now compare values.
+    switch (lhs.type())
+    {
+    case LLSD::TypeUndefined:
+        // Both are TypeUndefined. There's nothing more to know.
+        return true;
+
+#define COMPARE_SCALAR(type)                                    \
+    case LLSD::Type##type:                                      \
+        /* LLSD::URI has operator!=() but not operator==() */   \
+        /* rely on the optimizer for all others */              \
+        return (! (lhs.as##type() != rhs.as##type()))
+
+    COMPARE_SCALAR(Boolean);
+    COMPARE_SCALAR(Integer);
+    // The usual caveats about comparing floating-point numbers apply. This is
+    // only useful when we expect identical bit representation for a given
+    // Real value, e.g. for integer-valued Reals.
+    COMPARE_SCALAR(Real);
+    COMPARE_SCALAR(String);
+    COMPARE_SCALAR(UUID);
+    COMPARE_SCALAR(Date);
+    COMPARE_SCALAR(URI);
+    COMPARE_SCALAR(Binary);
+
+#undef COMPARE_SCALAR
+
+    case LLSD::TypeArray:
+    {
+        LLSD::array_const_iterator
+            lai(lhs.beginArray()), laend(lhs.endArray()),
+            rai(rhs.beginArray()), raend(rhs.endArray());
+        // Compare array elements, walking the two arrays in parallel.
+        for ( ; lai != laend && rai != raend; ++lai, ++rai)
+        {
+            // If any one array element is unequal, the arrays are unequal.
+            if (! llsd_equals(*lai, *rai))
+                return false;
+        }
+        // Here we've reached the end of one or the other array. They're equal
+        // only if they're BOTH at end: that is, if they have equal length too.
+        return (lai == laend && rai == raend);
+    }
+
+    case LLSD::TypeMap:
+    {
+        // Build a set of all rhs keys.
+        std::set<LLSD::String> rhskeys;
+        for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
+             rmi != rmend; ++rmi)
+        {
+            rhskeys.insert(rmi->first);
+        }
+        // Now walk all the lhs keys.
+        for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
+             lmi != lmend; ++lmi)
+        {
+            // Try to erase this lhs key from the set of rhs keys. If rhs has
+            // no such key, the maps are unequal. erase(key) returns count of
+            // items erased.
+            if (rhskeys.erase(lmi->first) != 1)
+                return false;
+            // Both maps have the current key. Compare values.
+            if (! llsd_equals(lmi->second, rhs[lmi->first]))
+                return false;
+        }
+        // We've now established that all the lhs keys have equal values in
+        // both maps. The maps are equal unless rhs contains a superset of
+        // those keys.
+        return rhskeys.empty();
+    }
+
+    default:
+        // We expect that every possible type() value is specifically handled
+        // above. Failing to extend this switch to support a new LLSD type is
+        // an error that must be brought to the coder's attention.
+        LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << "): "
+            "unknown type " << lhs.type() << LL_ENDL;
+        return false;               // pacify the compiler
+    }
+}
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 501600f1d906a367c14c8b520f7bafd8062730bd..6a6c396687000edcfc7601ff2ff2e7cce7aeb287 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -35,62 +35,32 @@
 #ifndef LL_LLSDUTIL_H
 #define LL_LLSDUTIL_H
 
-#include "llsd.h"
-
-// vector3
-class LLVector3;
-LLSD ll_sd_from_vector3(const LLVector3& vec);
-LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0);
-
-// vector4
-class LLVector4;
-LLSD ll_sd_from_vector4(const LLVector4& vec);
-LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0);
-
-// vector3d (double)
-class LLVector3d;
-LLSD ll_sd_from_vector3d(const LLVector3d& vec);
-LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0);
-
-// vector2
-class LLVector2;
-LLSD ll_sd_from_vector2(const LLVector2& vec);
-LLVector2 ll_vector2_from_sd(const LLSD& sd);
-
-// Quaternion
-class LLQuaternion;
-LLSD ll_sd_from_quaternion(const LLQuaternion& quat);
-LLQuaternion ll_quaternion_from_sd(const LLSD& sd);
-
-// color4
-class LLColor4;
-LLSD ll_sd_from_color4(const LLColor4& c);
-LLColor4 ll_color4_from_sd(const LLSD& sd);
+class LLSD;
 
 // U32
-LLSD ll_sd_from_U32(const U32);
-U32 ll_U32_from_sd(const LLSD& sd);
+LL_COMMON_API LLSD ll_sd_from_U32(const U32);
+LL_COMMON_API U32 ll_U32_from_sd(const LLSD& sd);
 
 // U64
-LLSD ll_sd_from_U64(const U64);
-U64 ll_U64_from_sd(const LLSD& sd);
+LL_COMMON_API LLSD ll_sd_from_U64(const U64);
+LL_COMMON_API U64 ll_U64_from_sd(const LLSD& sd);
 
 // IP Address
-LLSD ll_sd_from_ipaddr(const U32);
-U32 ll_ipaddr_from_sd(const LLSD& sd);
+LL_COMMON_API LLSD ll_sd_from_ipaddr(const U32);
+LL_COMMON_API U32 ll_ipaddr_from_sd(const LLSD& sd);
 
 // Binary to string
-LLSD ll_string_from_binary(const LLSD& sd);
+LL_COMMON_API LLSD ll_string_from_binary(const LLSD& sd);
 
 //String to binary
-LLSD ll_binary_from_string(const LLSD& sd);
+LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
 
 // Serializes sd to static buffer and returns pointer, useful for gdb debugging.
-char* ll_print_sd(const LLSD& sd);
+LL_COMMON_API char* ll_print_sd(const LLSD& sd);
 
 // Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
-char* ll_pretty_print_sd_ptr(const LLSD* sd);
-char* ll_pretty_print_sd(const LLSD& sd);
+LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
+LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
 
 //compares the structure of an LLSD to a template LLSD and stores the
 //"valid" values in a 3rd LLSD. Default values
@@ -99,11 +69,69 @@ char* ll_pretty_print_sd(const LLSD& sd);
 //Returns false if the test is of same type but values differ in type
 //Otherwise, returns true
 
-BOOL compare_llsd_with_template(
+LL_COMMON_API BOOL compare_llsd_with_template(
 	const LLSD& llsd_to_test,
 	const LLSD& template_llsd,
 	LLSD& resultant_llsd);
 
+/**
+ * Recursively determine whether a given LLSD data block "matches" another
+ * LLSD prototype. The returned string is empty() on success, non-empty() on
+ * mismatch.
+ *
+ * This function tests structure (types) rather than data values. It is
+ * intended for when a consumer expects an LLSD block with a particular
+ * structure, and must succinctly detect whether the arriving block is
+ * well-formed. For instance, a test of the form:
+ * @code
+ * if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
+ * @endcode
+ * could instead be expressed by initializing a prototype LLSD map with the
+ * required keys and writing:
+ * @code
+ * if (! llsd_matches(prototype, data).empty())
+ * @endcode
+ *
+ * A non-empty return value is an error-message fragment intended to indicate
+ * to (English-speaking) developers where in the prototype structure the
+ * mismatch occurred.
+ *
+ * * If a slot in the prototype isUndefined(), then anything is valid at that
+ *   place in the real object. (Passing prototype == LLSD() matches anything
+ *   at all.)
+ * * An array in the prototype must match a data array at least that large.
+ *   (Additional entries in the data array are ignored.) Every isDefined()
+ *   entry in the prototype array must match the corresponding entry in the
+ *   data array.
+ * * A map in the prototype must match a map in the data. Every key in the
+ *   prototype map must match a corresponding key in the data map. (Additional
+ *   keys in the data map are ignored.) Every isDefined() value in the
+ *   prototype map must match the corresponding key's value in the data map.
+ * * Scalar values in the prototype are tested for @em type rather than value.
+ *   For instance, a String in the prototype matches any String at all. In
+ *   effect, storing an Integer at a particular place in the prototype asserts
+ *   that the caller intends to apply asInteger() to the corresponding slot in
+ *   the data.
+ * * A String in the prototype matches String, Boolean, Integer, Real, UUID,
+ *   Date and URI, because asString() applied to any of these produces a
+ *   meaningful result.
+ * * Similarly, a Boolean, Integer or Real in the prototype can match any of
+ *   Boolean, Integer or Real in the data -- or even String.
+ * * UUID matches UUID or String.
+ * * Date matches Date or String.
+ * * URI matches URI or String.
+ * * Binary in the prototype matches only Binary in the data.
+ *
+ * @TODO: when a Boolean, Integer or Real in the prototype matches a String in
+ * the data, we should examine the String @em value to ensure it can be
+ * meaningfully converted to the requested type. The same goes for UUID, Date
+ * and URI.
+ */
+LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
+
+/// Deep equality
+LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs);
+
 // Simple function to copy data out of input & output iterators if
 // there is no need for casting.
 template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
diff --git a/indra/llcommon/llsecondlifeurls.h b/indra/llcommon/llsecondlifeurls.h
index a2e5f0b9c60f6e3c385ae0a5113e675a2dfe792c..bd2f9f760435d663c07fe1bb604bf209f69c4455 100644
--- a/indra/llcommon/llsecondlifeurls.h
+++ b/indra/llcommon/llsecondlifeurls.h
@@ -34,49 +34,49 @@
 #define LL_LLSECONDLIFEURLS_H
 /*
 // Account registration web page
-extern const std::string CREATE_ACCOUNT_URL;
+LL_COMMON_API extern const std::string CREATE_ACCOUNT_URL;
 
 // Manage Account
-extern const std::string MANAGE_ACCOUNT;
+LL_COMMON_API extern const std::string MANAGE_ACCOUNT;
 
-extern const std::string AUCTION_URL; 
+LL_COMMON_API extern const std::string AUCTION_URL; 
 
-extern const std::string EVENTS_URL;
+LL_COMMON_API extern const std::string EVENTS_URL;
 */
 // Tier up to a new land level.
-extern const std::string TIER_UP_URL;
+LL_COMMON_API extern const std::string TIER_UP_URL;
 
 
 // Tier up to a new land level.
-extern const std::string LAND_URL;
+LL_COMMON_API extern const std::string LAND_URL;
 
 // How to get DirectX 9
-extern const std::string DIRECTX_9_URL;
+LL_COMMON_API extern const std::string DIRECTX_9_URL;
 
 /*
 // Upgrade from basic membership to premium membership
-extern const std::string UPGRADE_TO_PREMIUM_URL;
+LL_COMMON_API extern const std::string UPGRADE_TO_PREMIUM_URL;
 
 
 // Out of date VIA chipset
-extern const std::string VIA_URL;
+LL_COMMON_API extern const std::string VIA_URL;
 
 // Support URL
-extern const std::string SUPPORT_URL;
+LL_COMMON_API extern const std::string SUPPORT_URL;
 
 // Linden Blogs page
-extern const std::string BLOGS_URL;
+LL_COMMON_API extern const std::string BLOGS_URL;
 
 // Currency page
-extern const std::string BUY_CURRENCY_URL;
+LL_COMMON_API extern const std::string BUY_CURRENCY_URL;
 
 // LSL script wiki
-extern const std::string LSL_DOC_URL;
+LL_COMMON_API extern const std::string LSL_DOC_URL;
 
 // SL KnowledgeBase page
-extern const std::string SL_KB_URL;
+LL_COMMON_API extern const std::string SL_KB_URL;
 
 // Release Notes Redirect URL for Server and Viewer
-extern const std::string RELEASE_NOTES_BASE_URL;
+LL_COMMON_API extern const std::string RELEASE_NOTES_BASE_URL;
 */
 #endif
diff --git a/indra/llcommon/llsimplehash.h b/indra/llcommon/llsimplehash.h
index 0ba2a3014c7dd0c2f24cc82371bb495e498a815f..5df93b646ec31af12d59e0b4138297000aac58a3 100644
--- a/indra/llcommon/llsimplehash.h
+++ b/indra/llcommon/llsimplehash.h
@@ -64,7 +64,7 @@ class LLSimpleHashEntry
 };
 
 template <typename HASH_KEY_TYPE, int TABLE_SIZE>
-class LLSimpleHash
+class LL_COMMON_API LLSimpleHash
 {
 public:
 	LLSimpleHash()
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6b5feaf1c46a0553cab0e65f6a9ef6672fc54bde
--- /dev/null
+++ b/indra/llcommon/llsingleton.cpp
@@ -0,0 +1,38 @@
+/** 
+ * @file llsingleton.cpp
+ * @author Brad Kittenbrink
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llsingleton.h"
+
+std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;
+
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 2e7d845bf717e7a516b4ce38354db8b53e269a5d..f55fafadd8dff8ea44e9b41eec191d86879a9053 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -33,7 +33,41 @@
 
 #include "llerror.h"	// *TODO: eliminate this
 
+#include <typeinfo>
 #include <boost/noncopyable.hpp>
+#include <boost/any.hpp>
+
+/// @brief A global registry of all singletons to prevent duplicate allocations
+/// across shared library boundaries
+class LL_COMMON_API LLSingletonRegistry {
+	private:
+		typedef std::map<std::string, void *> TypeMap;
+		static TypeMap * sSingletonMap;
+
+		static void checkInit()
+		{
+			if(sSingletonMap == NULL)
+			{
+				sSingletonMap = new TypeMap();
+			}
+		}
+
+	public:
+		template<typename T> static void * & get()
+		{
+			std::string name(typeid(T).name());
+
+			checkInit();
+
+			// the first entry of the pair returned by insert will be either the existing
+			// iterator matching our key, or the newly inserted NULL initialized entry
+			// see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
+			TypeMap::iterator result =
+				sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
+
+			return result->second;
+		}
+};
 
 // LLSingleton implements the getInstance() method part of the Singleton
 // pattern. It can't make the derived class constructors protected, though, so
@@ -107,8 +141,17 @@ class LLSingleton : private boost::noncopyable
 
 	static SingletonInstanceData& getData()
 	{
-		static SingletonInstanceData data;
-		return data;
+		// this is static to cache the lookup results
+		static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
+
+		// *TODO - look into making this threadsafe
+		if(NULL == registry)
+		{
+			static SingletonInstanceData data;
+			registry = &data;
+		}
+
+		return *static_cast<SingletonInstanceData *>(registry);
 	}
 
 	static DERIVED_TYPE* getInstance()
diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp
index 4be91b5b11f48b8128f5ba50b796da73b4102a99..3cb074257bc8927e6f05e53c1aa3161f18707a94 100644
--- a/indra/llcommon/llstacktrace.cpp
+++ b/indra/llcommon/llstacktrace.cpp
@@ -1,141 +1,142 @@
-/** 
- * @file llstacktrace.cpp
- * @brief stack tracing functionality
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- * 
- * Copyright (c) 2001-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llstacktrace.h"
-
-#ifdef LL_WINDOWS
-
-#include <iostream>
-#include <sstream>
-
-#include "windows.h"
-#include "Dbghelp.h"
-
-typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
-    IN ULONG frames_to_skip,
-    IN ULONG frames_to_capture,
-    OUT PVOID *backtrace,
-    OUT PULONG backtrace_hash);
-
-static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
-   (RtlCaptureStackBackTrace_Function*)
-   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
-
-bool ll_get_stack_trace(std::vector<std::string>& lines)
-{
-	const S32 MAX_STACK_DEPTH = 32;
-	const S32 STRING_NAME_LENGTH = 200;
-	const S32 FRAME_SKIP = 2;
-	static BOOL symbolsLoaded = false;
-	static BOOL firstCall = true;
-
-	HANDLE hProc = GetCurrentProcess();
-
-	// load the symbols if they're not loaded
-	if(!symbolsLoaded && firstCall)
-	{
-		symbolsLoaded = SymInitialize(hProc, NULL, true);
-		firstCall = false;
-	}
-
-	// if loaded, get the call stack
-	if(symbolsLoaded)
-	{
-		// create the frames to hold the addresses
-		void* frames[MAX_STACK_DEPTH];
-		memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
-		S32 depth = 0;
-
-		// get the addresses
-		depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
-
-		IMAGEHLP_LINE64 line;
-		memset(&line, 0, sizeof(IMAGEHLP_LINE64));
-		line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
-
-		// create something to hold address info
-		PIMAGEHLP_SYMBOL64 pSym;
-		pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
-		memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
-		pSym->MaxNameLength = STRING_NAME_LENGTH;
-		pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
-
-		// get address info for each address frame
-		// and store
-		for(S32 i=0; i < depth; i++)
-		{
-			std::stringstream stack_line;
-			BOOL ret;
-
-			DWORD64 addr = (DWORD64)frames[i];
-			ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
-			if(ret)
-			{
-				stack_line << pSym->Name << " ";
-			}
-
-			DWORD dummy;
-			ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
-			if(ret)
-			{
-				std::string file_name = line.FileName;
-				std::string::size_type index = file_name.rfind("\\");
-				stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; 
-			}
-
-			lines.push_back(stack_line.str());
-		}
-		
-		free(pSym);
-
-		// TODO: figure out a way to cleanup symbol loading
-		// Not hugely necessary, however.
-		//SymCleanup(hProc);
-		return true;
-	}
-	else
-	{
-		lines.push_back("Stack Trace Failed.  PDB symbol info not loaded");
-	}
-
-	return false;
-}
-
-#else
-
-bool ll_get_stack_trace(std::vector<std::string>& lines)
-{
-	return false;
-}
-
-#endif
-
+/** 
+ * @file llstacktrace.cpp
+ * @brief stack tracing functionality
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llstacktrace.h"
+
+#ifdef LL_WINDOWS
+
+#include <iostream>
+#include <sstream>
+
+#include "windows.h"
+#include "Dbghelp.h"
+
+typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
+    IN ULONG frames_to_skip,
+    IN ULONG frames_to_capture,
+    OUT PVOID *backtrace,
+    OUT PULONG backtrace_hash);
+
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+   (RtlCaptureStackBackTrace_Function*)
+   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+
+bool ll_get_stack_trace(std::vector<std::string>& lines)
+{
+	const S32 MAX_STACK_DEPTH = 32;
+	const S32 STRING_NAME_LENGTH = 200;
+	const S32 FRAME_SKIP = 2;
+	static BOOL symbolsLoaded = false;
+	static BOOL firstCall = true;
+
+	HANDLE hProc = GetCurrentProcess();
+
+	// load the symbols if they're not loaded
+	if(!symbolsLoaded && firstCall)
+	{
+		symbolsLoaded = SymInitialize(hProc, NULL, true);
+		firstCall = false;
+	}
+
+	// if loaded, get the call stack
+	if(symbolsLoaded)
+	{
+		// create the frames to hold the addresses
+		void* frames[MAX_STACK_DEPTH];
+		memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
+		S32 depth = 0;
+
+		// get the addresses
+		depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
+
+		IMAGEHLP_LINE64 line;
+		memset(&line, 0, sizeof(IMAGEHLP_LINE64));
+		line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+		// create something to hold address info
+		PIMAGEHLP_SYMBOL64 pSym;
+		pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
+		memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
+		pSym->MaxNameLength = STRING_NAME_LENGTH;
+		pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+
+		// get address info for each address frame
+		// and store
+		for(S32 i=0; i < depth; i++)
+		{
+			std::stringstream stack_line;
+			BOOL ret;
+
+			DWORD64 addr = (DWORD64)frames[i];
+			ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
+			if(ret)
+			{
+				stack_line << pSym->Name << " ";
+			}
+
+			DWORD dummy;
+			ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
+			if(ret)
+			{
+				std::string file_name = line.FileName;
+				std::string::size_type index = file_name.rfind("\\");
+				stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; 
+			}
+
+			lines.push_back(stack_line.str());
+		}
+		
+		free(pSym);
+
+		// TODO: figure out a way to cleanup symbol loading
+		// Not hugely necessary, however.
+		//SymCleanup(hProc);
+		return true;
+	}
+	else
+	{
+		lines.push_back("Stack Trace Failed.  PDB symbol info not loaded");
+	}
+
+	return false;
+}
+
+#else
+
+bool ll_get_stack_trace(std::vector<std::string>& lines)
+{
+	return false;
+}
+
+#endif
+
diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h
index 609b934a9745616974c1a36934561650110e0077..b84b1aa6ade73d81ad6fb642f37b46c7904fbadb 100644
--- a/indra/llcommon/llstacktrace.h
+++ b/indra/llcommon/llstacktrace.h
@@ -1,44 +1,44 @@
-/** 
- * @file llstacktrace.h
- * @brief stack trace functions
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- * 
- * Copyright (c) 2001-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_LLSTACKTRACE_H
-#define LL_LLSTACKTRACE_H
-
-#include "stdtypes.h"
-#include <vector>
-#include <string>
-
-bool ll_get_stack_trace(std::vector<std::string>& lines);
-
-#endif
-
+/** 
+ * @file llstacktrace.h
+ * @brief stack trace functions
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLSTACKTRACE_H
+#define LL_LLSTACKTRACE_H
+
+#include "stdtypes.h"
+#include <vector>
+#include <string>
+
+LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines);
+
+#endif
+
diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp
index 90dae117937254d03e8f2fabe78bc8ed23c6cecd..0bd2609f4a9ab462cbc4eecd483bbba2c680a240 100644
--- a/indra/llcommon/llstat.cpp
+++ b/indra/llcommon/llstat.cpp
@@ -43,7 +43,7 @@
 
 
 // statics
-BOOL            LLPerfBlock::sStatsEnabled = FALSE;    // Flag for detailed information
+S32	            LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS;       // Control what is being recorded
 LLPerfBlock::stat_map_t    LLPerfBlock::sStatMap;    // Map full path string to LLStatTime objects, tracks all active objects
 std::string        LLPerfBlock::sCurrentStatPath = "";    // Something like "/total_time/physics/physics step"
 LLStat::stat_map_t LLStat::sStatList;
@@ -130,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
 
     F32 duration = 0.f;
     F32 interval = 0.f;
+	S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
 
     const char * w = "duration";
     if (stats_config.has(w))
@@ -141,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
     {
         interval = (F32)stats_config[w].asReal();
     } 
+    w = "flags";
+    if (stats_config.has(w))
+    {
+		flags = (S32)stats_config[w].asInteger();
+		if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
+			duration > 0)
+		{   // No flags passed in, but have a duration, so reset to basic stats
+			flags = LLPerfBlock::LLSTATS_BASIC_STATS;
+		}
+    } 
 
-    mStatsp->setReportPerformanceDuration( duration );
+    mStatsp->setReportPerformanceDuration( duration, flags );
     mStatsp->setReportPerformanceInterval( interval );
 
     if ( duration > 0 )
@@ -254,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
     }
 }
 
-// Set length of performance stat recording
-void    LLPerfStats::setReportPerformanceDuration( F32 seconds )
+// Set length of performance stat recording.  
+// If turning stats on, caller must provide flags
+void    LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
 { 
 	if ( seconds <= 0.f )
 	{
 		mReportPerformanceStatEnd = 0.0;
-		LLPerfBlock::setStatsEnabled( FALSE );
+		LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS);		// Make sure all recording is off
 		mFrameStatsFile.close();
 		LLPerfBlock::clearDynamicStats();
 	}
@@ -269,8 +281,8 @@ void    LLPerfStats::setReportPerformanceDuration( F32 seconds )
 		mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
 		// Clear failure flag to try and create the log file once
 		mFrameStatsFileFailure = FALSE;
-		LLPerfBlock::setStatsEnabled( TRUE );
 		mSkipFirstFrameStats = TRUE;		// Skip the first report (at the end of this frame)
+		LLPerfBlock::setStatsFlags(flags);
 	}
 }
 
@@ -612,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
     }
 }
 
-// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
-// These are also turned on or off via the switch passed in
-LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
+// Use this constructor for normal, optional LLPerfBlock time slices
+LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
 {
-    if (!sStatsEnabled) return;
+    if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
+	{	// These are off unless the base set is enabled
+		return;
+	}
+
+	initDynamicStat(key);
+}
+
+	
+// Use this constructor for dynamically created LLPerfBlock time slices
+// that are only enabled by specific control flags
+LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
+{
+    if ((sStatsFlags & flags) == 0)
+	{
+		return;
+	}
 
     if (NULL == key2 || strlen(key2) == 0)
     {
@@ -630,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
     }
 }
 
+// Set up the result data map if dynamic stats are enabled
 void LLPerfBlock::initDynamicStat(const std::string& key)
 {
     // Early exit if dynamic stats aren't enabled.
-    if (!sStatsEnabled) return;
+    if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS) 
+		return;
 
     mLastPath = sCurrentStatPath;		// Save and restore current path
     sCurrentStatPath += "/" + key;		// Add key to current path
diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h
index bad18f46a0aea70e8abfeacca42703f96a86553c..bd73c9a6bb50af848082725f643b589ae9e90838 100644
--- a/indra/llcommon/llstat.h
+++ b/indra/llcommon/llstat.h
@@ -52,7 +52,7 @@ class	LLSD;
 // amounts of time with very low memory cost.
 //
 
-class LLStatAccum
+class LL_COMMON_API LLStatAccum
 {
 protected:
 	LLStatAccum(bool use_frame_timer);
@@ -116,7 +116,7 @@ class LLStatAccum
 	F64 	mLastSampleValue;
 };
 
-class LLStatMeasure : public LLStatAccum
+class LL_COMMON_API LLStatMeasure : public LLStatAccum
 	// gathers statistics about things that are measured
 	// ex.: tempature, time dilation
 {
@@ -131,7 +131,7 @@ class LLStatMeasure : public LLStatAccum
 };
 
 
-class LLStatRate : public LLStatAccum
+class LL_COMMON_API LLStatRate : public LLStatAccum
 	// gathers statistics about things that can be counted over time
 	// ex.: LSL instructions executed, messages sent, simulator frames completed
 	// renders it in terms of rate of thing per second
@@ -147,7 +147,7 @@ class LLStatRate : public LLStatAccum
 };
 
 
-class LLStatTime : public LLStatAccum
+class LL_COMMON_API LLStatTime : public LLStatAccum
 	// gathers statistics about time spent in a block of code
 	// measure average duration per second in the block
 {
@@ -178,7 +178,7 @@ class LLStatTime : public LLStatAccum
 
 
 // Use this class on the stack to record statistics about an area of code
-class LLPerfBlock
+class LL_COMMON_API LLPerfBlock
 {
 public:
     struct StatEntry
@@ -192,14 +192,23 @@ class LLPerfBlock
 	// Use this constructor for pre-defined LLStatTime objects
 	LLPerfBlock(LLStatTime* stat);
 
-	// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
-	LLPerfBlock( const char* key1, const char* key2 = NULL);
+	// Use this constructor for normal, optional LLPerfBlock time slices
+	LLPerfBlock( const char* key );
 
+	// Use this constructor for dynamically created LLPerfBlock time slices
+	// that are only enabled by specific control flags
+	LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
 
 	~LLPerfBlock();
 
-	static void setStatsEnabled( BOOL enable )		{ sStatsEnabled = enable;	};
-	static S32  getStatsEnabled()					{ return sStatsEnabled;		};
+	enum
+	{	// Stats bitfield flags
+		LLSTATS_NO_OPTIONAL_STATS	= 0x00,		// No optional stats gathering, just pre-defined LLStatTime objects
+		LLSTATS_BASIC_STATS			= 0x01,		// Gather basic optional runtime stats
+		LLSTATS_SCRIPT_FUNCTIONS	= 0x02,		// Include LSL function calls
+	};
+	static void setStatsFlags( S32 flags )	{ sStatsFlags = flags;	};
+	static S32  getStatsFlags()				{ return sStatsFlags;	};
 
 	static void clearDynamicStats();		// Reset maps to clear out dynamic objects
 	static void addStatsToLLSDandReset( LLSD & stats,		// Get current information and clear time bin
@@ -213,14 +222,14 @@ class LLPerfBlock
 	LLStatTime * 			mPredefinedStat;		// LLStatTime object to get data
 	StatEntry *				mDynamicStat;   		// StatEntryobject to get data
 
-	static BOOL				sStatsEnabled;			// Normally FALSE
+	static S32				sStatsFlags;			// Control what is being recorded
     static stat_map_t		sStatMap;				// Map full path string to LLStatTime objects
 	static std::string		sCurrentStatPath;		// Something like "frame/physics/physics step"
 };
 
 // ----------------------------------------------------------------------------
 
-class LLPerfStats
+class LL_COMMON_API LLPerfStats
 {
 public:
     LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
@@ -236,7 +245,7 @@ class LLPerfStats
     BOOL    frameStatsIsRunning()                                { return (mReportPerformanceStatEnd > 0.);        };
     F32     getReportPerformanceInterval() const                { return mReportPerformanceStatInterval;        };
     void    setReportPerformanceInterval( F32 interval )        { mReportPerformanceStatInterval = interval;    };
-    void    setReportPerformanceDuration( F32 seconds );
+    void    setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
     void    setProcessName(const std::string& process_name) { mProcessName = process_name; }
     void    setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
 
@@ -256,7 +265,7 @@ class LLPerfStats
 };
 
 // ----------------------------------------------------------------------------
-class LLStat
+class LL_COMMON_API LLStat
 {
 private:
 	typedef std::multimap<std::string, LLStat*> stat_map_t;
diff --git a/indra/llcommon/llstreamtools.h b/indra/llcommon/llstreamtools.h
index a6dc4d51e27acc7fc920dcee88c26867063c69ad..f64e76140936842b82ad9269c8c3cbbe320833ae 100644
--- a/indra/llcommon/llstreamtools.h
+++ b/indra/llcommon/llstreamtools.h
@@ -39,23 +39,23 @@
 // unless specifed otherwise these all return input_stream.good()
 
 // skips spaces and tabs
-bool skip_whitespace(std::istream& input_stream);
+LL_COMMON_API bool skip_whitespace(std::istream& input_stream);
 
 // skips whitespace and newlines
-bool skip_emptyspace(std::istream& input_stream);
+LL_COMMON_API bool skip_emptyspace(std::istream& input_stream);
 
 // skips emptyspace and lines that start with a #
-bool skip_comments_and_emptyspace(std::istream& input_stream);
+LL_COMMON_API bool skip_comments_and_emptyspace(std::istream& input_stream);
 
 // skips to character after next newline
-bool skip_line(std::istream& input_stream);
+LL_COMMON_API bool skip_line(std::istream& input_stream);
 
 // skips to beginning of next non-emptyspace
-bool skip_to_next_word(std::istream& input_stream);
+LL_COMMON_API bool skip_to_next_word(std::istream& input_stream);
 
 // skips to character after the end of next keyword 
 // a 'keyword' is defined as the first word on a line
-bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream);
+LL_COMMON_API bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream);
 
 // skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug 
 // in windows iostream
@@ -65,14 +65,14 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
 
 // characters are pulled out of input_stream and appended to output_string
 // returns result of input_stream.good() after characters are pulled
-bool get_word(std::string& output_string, std::istream& input_stream);
-bool get_line(std::string& output_string, std::istream& input_stream);
+LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream);
+LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream);
 
 // characters are pulled out of input_stream (up to a max of 'n')
 // and appended to output_string 
 // returns result of input_stream.good() after characters are pulled
-bool get_word(std::string& output_string, std::istream& input_stream, int n);
-bool get_line(std::string& output_string, std::istream& input_stream, int n);
+LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream, int n);
+LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream, int n);
 
 // unget_line() is disabled -- might tickle corruption bug in windows iostream
 //// backs up the input_stream by line_size + 1 characters
@@ -82,28 +82,28 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n);
 
 // removes the last char in 'line' if it matches 'c'
 // returns true if removed last char
-bool remove_last_char(char c, std::string& line);
+LL_COMMON_API bool remove_last_char(char c, std::string& line);
 
 // replaces escaped characters with the correct characters from left to right
 // "\\" ---> '\\' 
 // "\n" ---> '\n' 
-void unescape_string(std::string& line);
+LL_COMMON_API void unescape_string(std::string& line);
 
 // replaces unescaped characters with expanded equivalents from left to right
 // '\\' ---> "\\" 
 // '\n' ---> "\n" 
-void escape_string(std::string& line);
+LL_COMMON_API void escape_string(std::string& line);
 
 // replaces each '\n' character with ' '
-void replace_newlines_with_whitespace(std::string& line);
+LL_COMMON_API void replace_newlines_with_whitespace(std::string& line);
 
 // erases any double-quote characters in line
-void remove_double_quotes(std::string& line);
+LL_COMMON_API void remove_double_quotes(std::string& line);
 
 // the 'keyword' is defined as the first word on a line
 // the 'value' is everything after the keyword on the same line
 // starting at the first non-whitespace and ending right before the newline
-void get_keyword_and_value(std::string& keyword, 
+LL_COMMON_API void get_keyword_and_value(std::string& keyword, 
 						   std::string& value, 
 						   const std::string& line);
 
@@ -111,13 +111,13 @@ void get_keyword_and_value(std::string& keyword,
 // read anymore or until we hit the count.  Some istream
 // implimentations have a max that they will read.
 // Returns the number of bytes read.
-std::streamsize fullread(
+LL_COMMON_API std::streamsize fullread(
 	std::istream& istr,
 	char* buf,
 	std::streamsize requested);
 
 
-std::istream& operator>>(std::istream& str, const char *tocheck);
+LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck);
 
 #endif
 
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index eca7e922fd4d792a2b1e6c72729d9d82a5efa5ae..0f2f05a0d8e9e9a244f20bb6fdf0099e83f8d994 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -1,1290 +1,1297 @@
-/** 
- * @file llstring.h
- * @brief String utility functions and std::string class.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- * 
- * Copyright (c) 2001-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLSTRING_H
-#define LL_LLSTRING_H
-
-#include <string>
-#include <cstdio>
-#include <locale>
-#include <iomanip>
-#include "llsd.h"
-#include "llfasttimer.h"
-
-#if LL_LINUX || LL_SOLARIS
-#include <wctype.h>
-#include <wchar.h>
-#endif
-
-#include <string.h>
-
-#if LL_SOLARIS
-// stricmp and strnicmp do not exist on Solaris:
-#define stricmp strcasecmp
-#define strnicmp strncasecmp
-#endif
-
-const char LL_UNKNOWN_CHAR = '?';
-
-#if LL_DARWIN || LL_LINUX || LL_SOLARIS
-// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already)
-#include <cstring>
-
-namespace std
-{
-template<>
-struct char_traits<U16>
-{
-	typedef U16 		char_type;
-	typedef int 	    int_type;
-	typedef streampos 	pos_type;
-	typedef streamoff 	off_type;
-	typedef mbstate_t 	state_type;
-	
-	static void 
-		assign(char_type& __c1, const char_type& __c2)
-	{ __c1 = __c2; }
-	
-	static bool 
-		eq(const char_type& __c1, const char_type& __c2)
-	{ return __c1 == __c2; }
-	
-	static bool 
-		lt(const char_type& __c1, const char_type& __c2)
-	{ return __c1 < __c2; }
-	
-	static int 
-		compare(const char_type* __s1, const char_type* __s2, size_t __n)
-	{ return memcmp(__s1, __s2, __n * sizeof(char_type)); }
-	
-	static size_t
-		length(const char_type* __s)
-	{
-		const char_type *cur_char = __s;
-		while (*cur_char != 0)
-		{
-			++cur_char;
-		}
-		return cur_char - __s;
-	}
-	
-	static const char_type* 
-		find(const char_type* __s, size_t __n, const char_type& __a)
-	{ return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); }
-	
-	static char_type* 
-		move(char_type* __s1, const char_type* __s2, size_t __n)
-	{ return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); }
-	
-	static char_type* 
-		copy(char_type* __s1, const char_type* __s2, size_t __n)
-	{  return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); }	/* Flawfinder: ignore */
-	
-	static char_type* 
-		assign(char_type* __s, size_t __n, char_type __a)
-	{ 
-		// This isn't right.
-		//return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); 
-		
-		// I don't think there's a standard 'memset' for 16-bit values.
-		// Do this the old-fashioned way.
-		
-		size_t __i;
-		for(__i = 0; __i < __n; __i++)
-		{
-			__s[__i] = __a;
-		}
-		return __s; 
-	}
-	
-	static char_type 
-		to_char_type(const int_type& __c)
-	{ return static_cast<char_type>(__c); }
-	
-	static int_type 
-		to_int_type(const char_type& __c)
-	{ return static_cast<int_type>(__c); }
-	
-	static bool 
-		eq_int_type(const int_type& __c1, const int_type& __c2)
-	{ return __c1 == __c2; }
-	
-	static int_type 
-		eof() { return static_cast<int_type>(EOF); }
-	
-	static int_type 
-		not_eof(const int_type& __c)
-      { return (__c == eof()) ? 0 : __c; }
-  };
-};
-#endif
-
-class LLStringOps
-{
-private:
-	static long sltOffset;
-	static long localTimeOffset;
-	static bool daylightSavings;
-	static std::map<std::string, std::string> datetimeToCodes;
-
-public:
-	static char toUpper(char elem) { return toupper((unsigned char)elem); }
-	static llwchar toUpper(llwchar elem) { return towupper(elem); }
-	
-	static char toLower(char elem) { return tolower((unsigned char)elem); }
-	static llwchar toLower(llwchar elem) { return towlower(elem); }
-
-	static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
-	static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
-
-	static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
-	static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
-
-	static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
-	static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
-
-	static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
-	static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
-
-	static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
-	static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
-
-	static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
-	static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
-
-	static S32	collate(const char* a, const char* b) { return strcoll(a, b); }
-	static S32	collate(const llwchar* a, const llwchar* b);
-
-	static void setupDatetimeInfo (bool daylight);
-	static long getSltOffset (void) {return sltOffset;}
-	static long getLocalTimeOffset (void) {return localTimeOffset;}
-	static bool getDaylightSavings (void) {return daylightSavings;}
-	static std::string getDatetimeCode (std::string key);
-};
-
-/**
- * @brief Return a string constructed from in without crashing if the
- * pointer is NULL.
- */
-std::string ll_safe_string(const char* in);
-std::string ll_safe_string(const char* in, S32 maxlen);
-
-
-// Allowing assignments from non-strings into format_map_t is apparently
-// *really* error-prone, so subclass std::string with just basic c'tors.
-class LLFormatMapString
-{
-public:
-	LLFormatMapString() {};
-	LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {};
-	LLFormatMapString(const std::string& s) : mString(s) {};
-	operator std::string() const { return mString; }
-	bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
-	std::size_t length() const { return mString.length(); }
-	
-private:
-	std::string mString;
-};
-
-template <class T>
-class LLStringUtilBase
-{
-private:
-	static std::string sLocale;
-
-public:
-	typedef typename std::basic_string<T>::size_type size_type;
-	
-public:
-	/////////////////////////////////////////////////////////////////////////////////////////
-	// Static Utility functions that operate on std::strings
-
-	static std::basic_string<T> null;
-	
-	typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
-	static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
-	static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
-	static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
-	static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
-	static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
-	static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
-	static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
-	static void setLocale (std::string inLocale) {sLocale = inLocale;};
-	static std::string getLocale (void) {return sLocale;};
-	
-	static bool isValidIndex(const std::basic_string<T>& string, size_type i)
-	{
-		return !string.empty() && (0 <= i) && (i <= string.size());
-	}
-
-	static void	trimHead(std::basic_string<T>& string);
-	static void	trimTail(std::basic_string<T>& string);
-	static void	trim(std::basic_string<T>& string)	{ trimHead(string); trimTail(string); }
-	static void truncate(std::basic_string<T>& string, size_type count);
-
-	static void	toUpper(std::basic_string<T>& string);
-	static void	toLower(std::basic_string<T>& string);
-	
-	// True if this is the head of s.
-	static BOOL	isHead( const std::basic_string<T>& string, const T* s ); 
-
-	/**
-	 * @brief Returns true if string starts with substr
-	 *
-	 * If etither string or substr are empty, this method returns false.
-	 */
-	static bool startsWith(
-		const std::basic_string<T>& string,
-		const std::basic_string<T>& substr);
-
-	/**
-	 * @brief Returns true if string ends in substr
-	 *
-	 * If etither string or substr are empty, this method returns false.
-	 */
-	static bool endsWith(
-		const std::basic_string<T>& string,
-		const std::basic_string<T>& substr);
-
-	static void	addCRLF(std::basic_string<T>& string);
-	static void	removeCRLF(std::basic_string<T>& string);
-
-	static void	replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
-	static void	replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
-	static void	replaceChar( std::basic_string<T>& string, T target, T replacement );
-	static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement );
-	
-	static BOOL	containsNonprintable(const std::basic_string<T>& string);
-	static void	stripNonprintable(std::basic_string<T>& string);
-
-	/**
-	 * @brief Unsafe way to make ascii characters. You should probably
-	 * only call this when interacting with the host operating system.
-	 * The 1 byte std::string does not work correctly.
-	 * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
-	 * should work.
-	 */
-	static void _makeASCII(std::basic_string<T>& string);
-
-	// Conversion to other data types
-	static BOOL	convertToBOOL(const std::basic_string<T>& string, BOOL& value);
-	static BOOL	convertToU8(const std::basic_string<T>& string, U8& value);
-	static BOOL	convertToS8(const std::basic_string<T>& string, S8& value);
-	static BOOL	convertToS16(const std::basic_string<T>& string, S16& value);
-	static BOOL	convertToU16(const std::basic_string<T>& string, U16& value);
-	static BOOL	convertToU32(const std::basic_string<T>& string, U32& value);
-	static BOOL	convertToS32(const std::basic_string<T>& string, S32& value);
-	static BOOL	convertToF32(const std::basic_string<T>& string, F32& value);
-	static BOOL	convertToF64(const std::basic_string<T>& string, F64& value);
-
-	/////////////////////////////////////////////////////////////////////////////////////////
-	// Utility functions for working with char*'s and strings
-
-	// Like strcmp but also handles empty strings. Uses
-	// current locale.
-	static S32		compareStrings(const T* lhs, const T* rhs);
-	static S32		compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
-	
-	// case insensitive version of above. Uses current locale on
-	// Win32, and falls back to a non-locale aware comparison on
-	// Linux.
-	static S32		compareInsensitive(const T* lhs, const T* rhs);
-	static S32		compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
-
-	// Case sensitive comparison with good handling of numbers.  Does not use current locale.
-	// a.k.a. strdictcmp()
-	static S32		compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
-
-	// Case *in*sensitive comparison with good handling of numbers.  Does not use current locale.
-	// a.k.a. strdictcmp()
-	static S32		compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
-
-	// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
-	static BOOL		precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
-
-	// A replacement for strncpy.
-	// If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds
-	// up to dst_size-1 characters of src.
-	static void		copy(T* dst, const T* src, size_type dst_size);
-	
-	// Copies src into dst at a given offset.  
-	static void		copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
-	
-	static bool		isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
-
-
-#ifdef _DEBUG	
-	static void		testHarness();
-#endif
-
-private:
-	static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
-};
-
-template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
-template<class T> std::string LLStringUtilBase<T>::sLocale;
-
-typedef LLStringUtilBase<char> LLStringUtil;
-typedef LLStringUtilBase<llwchar> LLWStringUtil;
-typedef std::basic_string<llwchar> LLWString;
-
-//@ Use this where we want to disallow input in the form of "foo"
-//  This is used to catch places where english text is embedded in the code
-//  instead of in a translatable XUI file.
-class LLStringExplicit : public std::string
-{
-public:
-	explicit LLStringExplicit(const char* s) : std::string(s) {}
-	LLStringExplicit(const std::string& s) : std::string(s) {}
-	LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {}
-};
-
-struct LLDictionaryLess
-{
-public:
-	bool operator()(const std::string& a, const std::string& b)
-	{
-		return (LLStringUtil::precedesDict(a, b) ? true : false);
-	}
-};
-
-
-/**
- * Simple support functions
- */
-
-/**
- * @brief chop off the trailing characters in a string.
- *
- * This function works on bytes rather than glyphs, so this will
- * incorrectly truncate non-single byte strings.
- * Use utf8str_truncate() for utf8 strings
- * @return a copy of in string minus the trailing count bytes.
- */
-inline std::string chop_tail_copy(
-	const std::string& in,
-	std::string::size_type count)
-{
-	return std::string(in, 0, in.length() - count);
-}
-
-/**
- * @brief This translates a nybble stored as a hex value from 0-f back
- * to a nybble in the low order bits of the return byte.
- */
-U8 hex_as_nybble(char hex);
-
-/**
- * @brief read the contents of a file into a string.
- *
- * Since this function has no concept of character encoding, most
- * anything you do with this method ill-advised. Please avoid.
- * @param str [out] The string which will have.
- * @param filename The full name of the file to read.
- * @return Returns true on success. If false, str is unmodified.
- */
-bool _read_file_into_string(std::string& str, const std::string& filename);
-bool iswindividual(llwchar elem);
-
-/**
- * Unicode support
- */
-
-// Make the incoming string a utf8 string. Replaces any unknown glyph
-// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest
-// of the data may not be recovered.
-std::string rawstr_to_utf8(const std::string& raw);
-
-//
-// We should never use UTF16 except when communicating with Win32!
-//
-typedef std::basic_string<U16> llutf16string;
-
-LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
-LLWString utf16str_to_wstring(const llutf16string &utf16str);
-
-llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
-llutf16string wstring_to_utf16str(const LLWString &utf32str);
-
-llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
-llutf16string utf8str_to_utf16str ( const std::string& utf8str );
-
-LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
-LLWString utf8str_to_wstring(const std::string &utf8str);
-// Same function, better name. JC
-inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
-
-//
-S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
-
-std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
-std::string wstring_to_utf8str(const LLWString &utf32str);
-
-std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
-std::string utf16str_to_utf8str(const llutf16string &utf16str);
-
-// Length of this UTF32 string in bytes when transformed to UTF8
-S32 wstring_utf8_length(const LLWString& wstr); 
-
-// Length in bytes of this wide char in a UTF8 string
-S32 wchar_utf8_length(const llwchar wc); 
-
-std::string utf8str_tolower(const std::string& utf8str);
-
-// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
-S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
-
-// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
-S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
-
-// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
-S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
-
-/**
- * @brief Properly truncate a utf8 string to a maximum byte count.
- * 
- * The returned string may be less than max_len if the truncation
- * happens in the middle of a glyph. If max_len is longer than the
- * string passed in, the return value == utf8str.
- * @param utf8str A valid utf8 string to truncate.
- * @param max_len The maximum number of bytes in the return value.
- * @return Returns a valid utf8 string with byte count <= max_len.
- */
-std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
-
-std::string utf8str_trim(const std::string& utf8str);
-
-S32 utf8str_compare_insensitive(
-	const std::string& lhs,
-	const std::string& rhs);
-
-/**
- * @brief Replace all occurences of target_char with replace_char
- *
- * @param utf8str A utf8 string to process.
- * @param target_char The wchar to be replaced
- * @param replace_char The wchar which is written on replace
- */
-std::string utf8str_substChar(
-	const std::string& utf8str,
-	const llwchar target_char,
-	const llwchar replace_char);
-
-std::string utf8str_makeASCII(const std::string& utf8str);
-
-// Hack - used for evil notecards.
-std::string mbcsstring_makeASCII(const std::string& str); 
-
-std::string utf8str_removeCRLF(const std::string& utf8str);
-
-
-#if LL_WINDOWS
-/* @name Windows string helpers
- */
-//@{
-
-/**
- * @brief Implementation the expected snprintf interface.
- *
- * If the size of the passed in buffer is not large enough to hold the string,
- * two bad things happen:
- * 1. resulting formatted string is NOT null terminated
- * 2. Depending on the platform, the return value could be a) the required
- *    size of the buffer to copy the entire formatted string or b) -1.
- *    On Windows with VS.Net 2003, it returns -1 e.g. 
- *
- * safe_snprintf always adds a NULL terminator so that the caller does not
- * need to check for return value or need to add the NULL terminator.
- * It does not, however change the return value - to let the caller know
- * that the passed in buffer size was not large enough to hold the
- * formatted string.
- *
- */
-int safe_snprintf(char* str, size_t size, const char* format, ...);
-
-/**
- * @brief Convert a wide string to std::string
- *
- * This replaces the unsafe W2A macro from ATL.
- */
-std::string ll_convert_wide_to_string(const wchar_t* in);
-
-//@}
-#endif // LL_WINDOWS
-
-/**
- * Many of the 'strip' and 'replace' methods of LLStringUtilBase need
- * specialization to work with the signed char type.
- * Sadly, it is not possible (AFAIK) to specialize a single method of
- * a template class.
- * That stuff should go here.
- */
-namespace LLStringFn
-{
-	/**
-	 * @brief Replace all non-printable characters with replacement in
-	 * string.
-	 * NOTE - this will zap non-ascii
-	 *
-	 * @param [in,out] string the to modify. out value is the string
-	 * with zero non-printable characters.
-	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
-	 */
-	void replace_nonprintable_in_ascii(
-		std::basic_string<char>& string,
-		char replacement);
-
-
-	/**
-	 * @brief Replace all non-printable characters and pipe characters
-	 * with replacement in a string.
-	 * NOTE - this will zap non-ascii
-	 *
-	 * @param [in,out] the string to modify. out value is the string
-	 * with zero non-printable characters and zero pipe characters.
-	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
-	 */
-	void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
-									   char replacement);
-
-
-	/**
-	 * @brief Remove all characters that are not allowed in XML 1.0.
-	 * Returns a copy of the string with those characters removed.
-	 * Works with US ASCII and UTF-8 encoded strings.  JC
-	 */
-	std::string strip_invalid_xml(const std::string& input);
-
-
-	/**
-	 * @brief Replace all control characters (0 <= c < 0x20) with replacement in
-	 * string.   This is safe for utf-8
-	 *
-	 * @param [in,out] string the to modify. out value is the string
-	 * with zero non-printable characters.
-	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
-	 */
-	void replace_ascii_controlchars(
-		std::basic_string<char>& string,
-		char replacement);
-}
-
-////////////////////////////////////////////////////////////
-// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
-// There is no LLWStringUtil::format implementation currently.
-// Calling thse for anything other than LLStringUtil will produce link errors.
-
-////////////////////////////////////////////////////////////
-
-
-// static
-template<class T> 
-S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
-{	
-	S32 result;
-	if( lhs == rhs )
-	{
-		result = 0;
-	}
-	else
-	if ( !lhs || !lhs[0] )
-	{
-		result = ((!rhs || !rhs[0]) ? 0 : 1);
-	}
-	else
-	if ( !rhs || !rhs[0])
-	{
-		result = -1;
-	}
-	else
-	{
-		result = LLStringOps::collate(lhs, rhs);
-	}
-	return result;
-}
-
-//static 
-template<class T> 
-S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
-{
-	return LLStringOps::collate(lhs.c_str(), rhs.c_str());
-}
-
-// static
-template<class T> 
-S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
-{
-	S32 result;
-	if( lhs == rhs )
-	{
-		result = 0;
-	}
-	else
-	if ( !lhs || !lhs[0] )
-	{
-		result = ((!rhs || !rhs[0]) ? 0 : 1);
-	}
-	else
-	if ( !rhs || !rhs[0] )
-	{
-		result = -1;
-	}
-	else
-	{
-		std::basic_string<T> lhs_string(lhs);
-		std::basic_string<T> rhs_string(rhs);
-		LLStringUtilBase<T>::toUpper(lhs_string);
-		LLStringUtilBase<T>::toUpper(rhs_string);
-		result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
-	}
-	return result;
-}
-
-//static 
-template<class T> 
-S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
-{
-	std::basic_string<T> lhs_string(lhs);
-	std::basic_string<T> rhs_string(rhs);
-	LLStringUtilBase<T>::toUpper(lhs_string);
-	LLStringUtilBase<T>::toUpper(rhs_string);
-	return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
-}
-
-// Case sensitive comparison with good handling of numbers.  Does not use current locale.
-// a.k.a. strdictcmp()
-
-//static 
-template<class T>
-S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
-{
-	const T* a = astr.c_str();
-	const T* b = bstr.c_str();
-	T ca, cb;
-	S32 ai, bi, cnt = 0;
-	S32 bias = 0;
-
-	ca = *(a++);
-	cb = *(b++);
-	while( ca && cb ){
-		if( bias==0 ){
-			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; }
-			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; }
-		}else{
-			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
-			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
-		}
-		if( LLStringOps::isDigit(ca) ){
-			if( cnt-->0 ){
-				if( cb!=ca ) break;
-			}else{
-				if( !LLStringOps::isDigit(cb) ) break;
-				for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
-				for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
-				if( ai<bi ){ ca=0; break; }
-				if( bi<ai ){ cb=0; break; }
-				if( ca!=cb ) break;
-				cnt = ai;
-			}
-		}else if( ca!=cb ){   break;
-		}
-		ca = *(a++);
-		cb = *(b++);
-	}
-	if( ca==cb ) ca += bias;
-	return ca-cb;
-}
-
-// static
-template<class T>
-S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
-{
-	const T* a = astr.c_str();
-	const T* b = bstr.c_str();
-	T ca, cb;
-	S32 ai, bi, cnt = 0;
-
-	ca = *(a++);
-	cb = *(b++);
-	while( ca && cb ){
-		if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
-		if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
-		if( LLStringOps::isDigit(ca) ){
-			if( cnt-->0 ){
-				if( cb!=ca ) break;
-			}else{
-				if( !LLStringOps::isDigit(cb) ) break;
-				for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
-				for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
-				if( ai<bi ){ ca=0; break; }
-				if( bi<ai ){ cb=0; break; }
-				if( ca!=cb ) break;
-				cnt = ai;
-			}
-		}else if( ca!=cb ){   break;
-		}
-		ca = *(a++);
-		cb = *(b++);
-	}
-	return ca-cb;
-}
-
-// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
-// static 
-template<class T> 
-BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
-{
-	if( a.size() && b.size() )
-	{
-		return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
-	}
-	else
-	{
-		return (!b.empty());
-	}
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)	
-{ 
-	if( !string.empty() )
-	{ 
-		std::transform(
-			string.begin(),
-			string.end(),
-			string.begin(),
-			(T(*)(T)) &LLStringOps::toUpper);
-	}
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
-{ 
-	if( !string.empty() )
-	{ 
-		std::transform(
-			string.begin(),
-			string.end(),
-			string.begin(),
-			(T(*)(T)) &LLStringOps::toLower);
-	}
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
-{			
-	if( !string.empty() )
-	{
-		size_type i = 0;
-		while( i < string.length() && LLStringOps::isSpace( string[i] ) )
-		{
-			i++;
-		}
-		string.erase(0, i);
-	}
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
-{			
-	if( string.size() )
-	{
-		size_type len = string.length();
-		size_type i = len;
-		while( i > 0 && LLStringOps::isSpace( string[i-1] ) )
-		{
-			i--;
-		}
-
-		string.erase( i, len - i );
-	}
-}
-
-
-// Replace line feeds with carriage return-line feed pairs.
-//static
-template<class T>
-void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
-{
-	const T LF = 10;
-	const T CR = 13;
-
-	// Count the number of line feeds
-	size_type count = 0;
-	size_type len = string.size();
-	size_type i;
-	for( i = 0; i < len; i++ )
-	{
-		if( string[i] == LF )
-		{
-			count++;
-		}
-	}
-
-	// Insert a carriage return before each line feed
-	if( count )
-	{
-		size_type size = len + count;
-		T *t = new T[size];
-		size_type j = 0;
-		for( i = 0; i < len; ++i )
-		{
-			if( string[i] == LF )
-			{
-				t[j] = CR;
-				++j;
-			}
-			t[j] = string[i];
-			++j;
-		}
-
-		string.assign(t, size);
-	}
-}
-
-// Remove all carriage returns
-//static
-template<class T> 
-void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
-{
-	const T CR = 13;
-
-	size_type cr_count = 0;
-	size_type len = string.size();
-	size_type i;
-	for( i = 0; i < len - cr_count; i++ )
-	{
-		if( string[i+cr_count] == CR )
-		{
-			cr_count++;
-		}
-
-		string[i] = string[i+cr_count];
-	}
-	string.erase(i, cr_count);
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
-{
-	size_type found_pos = 0;
-	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) 
-	{
-		string[found_pos] = replacement;
-		found_pos++; // avoid infinite defeat if target == replacement
-	}
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement )
-{
-	size_type found_pos = 0;
-	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
-	{
-		string.replace( found_pos, target.length(), replacement );
-		found_pos += replacement.length(); // avoid infinite defeat if replacement contains target
-	}
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
-{
-	const char LF = 10;
-	const S8 MIN = 32;
-//	const S8 MAX = 127;
-
-	size_type len = string.size();
-	for( size_type i = 0; i < len; i++ )
-	{
-		// No need to test MAX < mText[i] because we treat mText[i] as a signed char,
-		// which has a max value of 127.
-		if( ( S8(string[i]) < MIN ) && (string[i] != LF) )
-		{
-			string[i] = replacement;
-		}
-	}
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
-{
-	const T TAB = '\t';
-	const T SPACE = ' ';
-
-	std::basic_string<T> out_str;
-	// Replace tabs with spaces
-	for (size_type i = 0; i < str.length(); i++)
-	{
-		if (str[i] == TAB)
-		{
-			for (size_type j = 0; j < spaces_per_tab; j++)
-				out_str += SPACE;
-		}
-		else
-		{
-			out_str += str[i];
-		}
-	}
-	str = out_str;
-}
-
-//static
-template<class T> 
-BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
-{
-	const char MIN = 32;
-	BOOL rv = FALSE;
-	for (size_type i = 0; i < string.size(); i++)
-	{
-		if(string[i] < MIN)
-		{
-			rv = TRUE;
-			break;
-		}
-	}
-	return rv;
-}
-
-//static
-template<class T> 
-void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
-{
-	const char MIN = 32;
-	size_type j = 0;
-	if (string.empty())
-	{
-		return;
-	}
-	size_t src_size = string.size();
-	char* c_string = new char[src_size + 1];
-	if(c_string == NULL)
-	{
-		return;
-	}
-	copy(c_string, string.c_str(), src_size+1);
-	char* write_head = &c_string[0];
-	for (size_type i = 0; i < src_size; i++)
-	{
-		char* read_head = &string[i];
-		write_head = &c_string[j];
-		if(!(*read_head < MIN))
-		{
-			*write_head = *read_head;
-			++j;
-		}
-	}
-	c_string[j]= '\0';
-	string = c_string;
-	delete []c_string;
-}
-
-template<class T> 
-void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
-{
-	// Replace non-ASCII chars with LL_UNKNOWN_CHAR
-	for (size_type i = 0; i < string.length(); i++)
-	{
-		if (string[i] > 0x7f)
-		{
-			string[i] = LL_UNKNOWN_CHAR;
-		}
-	}
-}
-
-// static
-template<class T> 
-void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
-{
-	if( dst_size > 0 )
-	{
-		size_type min_len = 0;
-		if( src )
-		{
-			min_len = llmin( dst_size - 1, strlen( src ) );  /* Flawfinder: ignore */
-			memcpy(dst, src, min_len * sizeof(T));		/* Flawfinder: ignore */
-		}
-		dst[min_len] = '\0';
-	}
-}
-
-// static
-template<class T> 
-void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
-{
-	if ( offset == dst.length() )
-	{
-		// special case - append to end of string and avoid expensive
-		// (when strings are large) string manipulations
-		dst += src;
-	}
-	else
-	{
-		std::basic_string<T> tail = dst.substr(offset);
-
-		dst = dst.substr(0, offset);
-		dst += src;
-		dst += tail;
-	};
-}
-
-// True if this is the head of s.
-//static
-template<class T> 
-BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s ) 
-{ 
-	if( string.empty() )
-	{
-		// Early exit
-		return FALSE;
-	}
-	else
-	{
-		return (strncmp( s, string.c_str(), string.size() ) == 0);
-	}
-}
-
-// static
-template<class T> 
-bool LLStringUtilBase<T>::startsWith(
-	const std::basic_string<T>& string,
-	const std::basic_string<T>& substr)
-{
-	if(string.empty() || (substr.empty())) return false;
-	if(0 == string.find(substr)) return true;
-	return false;
-}
-
-// static
-template<class T> 
-bool LLStringUtilBase<T>::endsWith(
-	const std::basic_string<T>& string,
-	const std::basic_string<T>& substr)
-{
-	if(string.empty() || (substr.empty())) return false;
-	std::string::size_type idx = string.rfind(substr);
-	if(std::string::npos == idx) return false;
-	return (idx == (string.size() - substr.size()));
-}
-
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
-{
-	if( string.empty() )
-	{
-		return FALSE;
-	}
-
-	std::basic_string<T> temp( string );
-	trim(temp);
-	if( 
-		(temp == "1") || 
-		(temp == "T") || 
-		(temp == "t") || 
-		(temp == "TRUE") || 
-		(temp == "true") || 
-		(temp == "True") )
-	{
-		value = TRUE;
-		return TRUE;
-	}
-	else
-	if( 
-		(temp == "0") || 
-		(temp == "F") || 
-		(temp == "f") || 
-		(temp == "FALSE") || 
-		(temp == "false") || 
-		(temp == "False") )
-	{
-		value = FALSE;
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value) 
-{
-	S32 value32 = 0;
-	BOOL success = convertToS32(string, value32);
-	if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) )
-	{
-		value = (U8) value32;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value) 
-{
-	S32 value32 = 0;
-	BOOL success = convertToS32(string, value32);
-	if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) )
-	{
-		value = (S8) value32;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value) 
-{
-	S32 value32 = 0;
-	BOOL success = convertToS32(string, value32);
-	if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) )
-	{
-		value = (S16) value32;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value) 
-{
-	S32 value32 = 0;
-	BOOL success = convertToS32(string, value32);
-	if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) )
-	{
-		value = (U16) value32;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) 
-{
-	if( string.empty() )
-	{
-		return FALSE;
-	}
-
-	std::basic_string<T> temp( string );
-	trim(temp);
-	U32 v;
-	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
-	if(i_stream >> v)
-	{
-		value = v;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) 
-{
-	if( string.empty() )
-	{
-		return FALSE;
-	}
-
-	std::basic_string<T> temp( string );
-	trim(temp);
-	S32 v;
-	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
-	if(i_stream >> v)
-	{
-		//TODO: figure out overflow and underflow reporting here
-		//if((LONG_MAX == v) || (LONG_MIN == v))
-		//{
-		//	// Underflow or overflow
-		//	return FALSE;
-		//}
-
-		value = v;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value) 
-{
-	F64 value64 = 0.0;
-	BOOL success = convertToF64(string, value64);
-	if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) )
-	{
-		value = (F32) value64;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
-{
-	if( string.empty() )
-	{
-		return FALSE;
-	}
-
-	std::basic_string<T> temp( string );
-	trim(temp);
-	F64 v;
-	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
-	if(i_stream >> v)
-	{
-		//TODO: figure out overflow and underflow reporting here
-		//if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) )
-		//{
-		//	// Underflow or overflow
-		//	return FALSE;
-		//}
-
-		value = v;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-template<class T> 
-void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
-{
-	size_type cur_size = string.size();
-	string.resize(count < cur_size ? count : cur_size);
-}
-
-#endif  // LL_STRING_H
+/** 
+ * @file llstring.h
+ * @brief String utility functions and std::string class.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSTRING_H
+#define LL_LLSTRING_H
+
+#include <string>
+#include <cstdio>
+#include <locale>
+#include <iomanip>
+#include "llsd.h"
+#include "llfasttimer.h"
+
+#if LL_LINUX || LL_SOLARIS
+#include <wctype.h>
+#include <wchar.h>
+#endif
+
+#include <string.h>
+
+#if LL_SOLARIS
+// stricmp and strnicmp do not exist on Solaris:
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+const char LL_UNKNOWN_CHAR = '?';
+
+#if LL_DARWIN || LL_LINUX || LL_SOLARIS
+// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already)
+#include <cstring>
+
+namespace std
+{
+template<>
+struct char_traits<U16>
+{
+	typedef U16 		char_type;
+	typedef int 	    int_type;
+	typedef streampos 	pos_type;
+	typedef streamoff 	off_type;
+	typedef mbstate_t 	state_type;
+	
+	static void 
+		assign(char_type& __c1, const char_type& __c2)
+	{ __c1 = __c2; }
+	
+	static bool 
+		eq(const char_type& __c1, const char_type& __c2)
+	{ return __c1 == __c2; }
+	
+	static bool 
+		lt(const char_type& __c1, const char_type& __c2)
+	{ return __c1 < __c2; }
+	
+	static int 
+		compare(const char_type* __s1, const char_type* __s2, size_t __n)
+	{ return memcmp(__s1, __s2, __n * sizeof(char_type)); }
+	
+	static size_t
+		length(const char_type* __s)
+	{
+		const char_type *cur_char = __s;
+		while (*cur_char != 0)
+		{
+			++cur_char;
+		}
+		return cur_char - __s;
+	}
+	
+	static const char_type* 
+		find(const char_type* __s, size_t __n, const char_type& __a)
+	{ return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); }
+	
+	static char_type* 
+		move(char_type* __s1, const char_type* __s2, size_t __n)
+	{ return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); }
+	
+	static char_type* 
+		copy(char_type* __s1, const char_type* __s2, size_t __n)
+	{  return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); }	/* Flawfinder: ignore */
+	
+	static char_type* 
+		assign(char_type* __s, size_t __n, char_type __a)
+	{ 
+		// This isn't right.
+		//return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); 
+		
+		// I don't think there's a standard 'memset' for 16-bit values.
+		// Do this the old-fashioned way.
+		
+		size_t __i;
+		for(__i = 0; __i < __n; __i++)
+		{
+			__s[__i] = __a;
+		}
+		return __s; 
+	}
+	
+	static char_type 
+		to_char_type(const int_type& __c)
+	{ return static_cast<char_type>(__c); }
+	
+	static int_type 
+		to_int_type(const char_type& __c)
+	{ return static_cast<int_type>(__c); }
+	
+	static bool 
+		eq_int_type(const int_type& __c1, const int_type& __c2)
+	{ return __c1 == __c2; }
+	
+	static int_type 
+		eof() { return static_cast<int_type>(EOF); }
+	
+	static int_type 
+		not_eof(const int_type& __c)
+      { return (__c == eof()) ? 0 : __c; }
+  };
+};
+#endif
+
+class LL_COMMON_API LLStringOps
+{
+private:
+	static long sltOffset;
+	static long localTimeOffset;
+	static bool daylightSavings;
+	static std::map<std::string, std::string> datetimeToCodes;
+
+public:
+	static char toUpper(char elem) { return toupper((unsigned char)elem); }
+	static llwchar toUpper(llwchar elem) { return towupper(elem); }
+	
+	static char toLower(char elem) { return tolower((unsigned char)elem); }
+	static llwchar toLower(llwchar elem) { return towlower(elem); }
+
+	static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
+	static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
+
+	static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
+	static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
+
+	static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
+	static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
+
+	static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
+	static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
+
+	static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
+	static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
+
+	static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
+	static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
+
+	static S32	collate(const char* a, const char* b) { return strcoll(a, b); }
+	static S32	collate(const llwchar* a, const llwchar* b);
+
+	static void setupDatetimeInfo (bool daylight);
+	static long getSltOffset (void) {return sltOffset;}
+	static long getLocalTimeOffset (void) {return localTimeOffset;}
+	static bool getDaylightSavings (void) {return daylightSavings;}
+	static std::string getDatetimeCode (std::string key);
+};
+
+/**
+ * @brief Return a string constructed from in without crashing if the
+ * pointer is NULL.
+ */
+LL_COMMON_API std::string ll_safe_string(const char* in);
+LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen);
+
+
+// Allowing assignments from non-strings into format_map_t is apparently
+// *really* error-prone, so subclass std::string with just basic c'tors.
+class LLFormatMapString
+{
+public:
+	LLFormatMapString() {};
+	LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {};
+	LLFormatMapString(const std::string& s) : mString(s) {};
+	operator std::string() const { return mString; }
+	bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
+	std::size_t length() const { return mString.length(); }
+	
+private:
+	std::string mString;
+};
+
+template <class T>
+class LLStringUtilBase
+{
+private:
+	static std::string sLocale;
+
+public:
+	typedef typename std::basic_string<T>::size_type size_type;
+	
+public:
+	/////////////////////////////////////////////////////////////////////////////////////////
+	// Static Utility functions that operate on std::strings
+
+	static std::basic_string<T> null;
+	
+	typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
+	LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
+	LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
+	LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
+	LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
+	LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
+	LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
+	LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
+	static void setLocale (std::string inLocale) {sLocale = inLocale;};
+	static std::string getLocale (void) {return sLocale;};
+	
+	static bool isValidIndex(const std::basic_string<T>& string, size_type i)
+	{
+		return !string.empty() && (0 <= i) && (i <= string.size());
+	}
+
+	static void	trimHead(std::basic_string<T>& string);
+	static void	trimTail(std::basic_string<T>& string);
+	static void	trim(std::basic_string<T>& string)	{ trimHead(string); trimTail(string); }
+	static void truncate(std::basic_string<T>& string, size_type count);
+
+	static void	toUpper(std::basic_string<T>& string);
+	static void	toLower(std::basic_string<T>& string);
+	
+	// True if this is the head of s.
+	static BOOL	isHead( const std::basic_string<T>& string, const T* s ); 
+
+	/**
+	 * @brief Returns true if string starts with substr
+	 *
+	 * If etither string or substr are empty, this method returns false.
+	 */
+	static bool startsWith(
+		const std::basic_string<T>& string,
+		const std::basic_string<T>& substr);
+
+	/**
+	 * @brief Returns true if string ends in substr
+	 *
+	 * If etither string or substr are empty, this method returns false.
+	 */
+	static bool endsWith(
+		const std::basic_string<T>& string,
+		const std::basic_string<T>& substr);
+
+	static void	addCRLF(std::basic_string<T>& string);
+	static void	removeCRLF(std::basic_string<T>& string);
+
+	static void	replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
+	static void	replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
+	static void	replaceChar( std::basic_string<T>& string, T target, T replacement );
+	static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement );
+	
+	static BOOL	containsNonprintable(const std::basic_string<T>& string);
+	static void	stripNonprintable(std::basic_string<T>& string);
+
+	/**
+	 * @brief Unsafe way to make ascii characters. You should probably
+	 * only call this when interacting with the host operating system.
+	 * The 1 byte std::string does not work correctly.
+	 * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
+	 * should work.
+	 */
+	static void _makeASCII(std::basic_string<T>& string);
+
+	// Conversion to other data types
+	static BOOL	convertToBOOL(const std::basic_string<T>& string, BOOL& value);
+	static BOOL	convertToU8(const std::basic_string<T>& string, U8& value);
+	static BOOL	convertToS8(const std::basic_string<T>& string, S8& value);
+	static BOOL	convertToS16(const std::basic_string<T>& string, S16& value);
+	static BOOL	convertToU16(const std::basic_string<T>& string, U16& value);
+	static BOOL	convertToU32(const std::basic_string<T>& string, U32& value);
+	static BOOL	convertToS32(const std::basic_string<T>& string, S32& value);
+	static BOOL	convertToF32(const std::basic_string<T>& string, F32& value);
+	static BOOL	convertToF64(const std::basic_string<T>& string, F64& value);
+
+	/////////////////////////////////////////////////////////////////////////////////////////
+	// Utility functions for working with char*'s and strings
+
+	// Like strcmp but also handles empty strings. Uses
+	// current locale.
+	static S32		compareStrings(const T* lhs, const T* rhs);
+	static S32		compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
+	
+	// case insensitive version of above. Uses current locale on
+	// Win32, and falls back to a non-locale aware comparison on
+	// Linux.
+	static S32		compareInsensitive(const T* lhs, const T* rhs);
+	static S32		compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
+
+	// Case sensitive comparison with good handling of numbers.  Does not use current locale.
+	// a.k.a. strdictcmp()
+	static S32		compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
+
+	// Case *in*sensitive comparison with good handling of numbers.  Does not use current locale.
+	// a.k.a. strdictcmp()
+	static S32		compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
+
+	// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
+	static BOOL		precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
+
+	// A replacement for strncpy.
+	// If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds
+	// up to dst_size-1 characters of src.
+	static void		copy(T* dst, const T* src, size_type dst_size);
+	
+	// Copies src into dst at a given offset.  
+	static void		copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
+	
+	static bool		isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
+
+
+#ifdef _DEBUG	
+	LL_COMMON_API static void		testHarness();
+#endif
+
+private:
+	LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
+};
+
+template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
+template<class T> std::string LLStringUtilBase<T>::sLocale;
+
+typedef LLStringUtilBase<char> LLStringUtil;
+typedef LLStringUtilBase<llwchar> LLWStringUtil;
+typedef std::basic_string<llwchar> LLWString;
+
+//@ Use this where we want to disallow input in the form of "foo"
+//  This is used to catch places where english text is embedded in the code
+//  instead of in a translatable XUI file.
+class LLStringExplicit : public std::string
+{
+public:
+	explicit LLStringExplicit(const char* s) : std::string(s) {}
+	LLStringExplicit(const std::string& s) : std::string(s) {}
+	LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {}
+};
+
+struct LLDictionaryLess
+{
+public:
+	bool operator()(const std::string& a, const std::string& b)
+	{
+		return (LLStringUtil::precedesDict(a, b) ? true : false);
+	}
+};
+
+
+/**
+ * Simple support functions
+ */
+
+/**
+ * @brief chop off the trailing characters in a string.
+ *
+ * This function works on bytes rather than glyphs, so this will
+ * incorrectly truncate non-single byte strings.
+ * Use utf8str_truncate() for utf8 strings
+ * @return a copy of in string minus the trailing count bytes.
+ */
+inline std::string chop_tail_copy(
+	const std::string& in,
+	std::string::size_type count)
+{
+	return std::string(in, 0, in.length() - count);
+}
+
+/**
+ * @brief This translates a nybble stored as a hex value from 0-f back
+ * to a nybble in the low order bits of the return byte.
+ */
+LL_COMMON_API U8 hex_as_nybble(char hex);
+
+/**
+ * @brief read the contents of a file into a string.
+ *
+ * Since this function has no concept of character encoding, most
+ * anything you do with this method ill-advised. Please avoid.
+ * @param str [out] The string which will have.
+ * @param filename The full name of the file to read.
+ * @return Returns true on success. If false, str is unmodified.
+ */
+LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename);
+LL_COMMON_API bool iswindividual(llwchar elem);
+
+/**
+ * Unicode support
+ */
+
+// Make the incoming string a utf8 string. Replaces any unknown glyph
+// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest
+// of the data may not be recovered.
+LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
+
+//
+// We should never use UTF16 except when communicating with Win32!
+//
+typedef std::basic_string<U16> llutf16string;
+
+LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
+LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
+
+LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
+LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
+
+LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
+LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
+
+LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
+LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
+// Same function, better name. JC
+inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
+
+//
+LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
+
+LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
+LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
+
+LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
+LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
+
+// Length of this UTF32 string in bytes when transformed to UTF8
+LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); 
+
+// Length in bytes of this wide char in a UTF8 string
+LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); 
+
+LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str);
+
+// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
+LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
+
+// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
+LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
+
+// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
+LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
+
+/**
+ * @brief Properly truncate a utf8 string to a maximum byte count.
+ * 
+ * The returned string may be less than max_len if the truncation
+ * happens in the middle of a glyph. If max_len is longer than the
+ * string passed in, the return value == utf8str.
+ * @param utf8str A valid utf8 string to truncate.
+ * @param max_len The maximum number of bytes in the return value.
+ * @return Returns a valid utf8 string with byte count <= max_len.
+ */
+LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
+
+LL_COMMON_API std::string utf8str_trim(const std::string& utf8str);
+
+LL_COMMON_API S32 utf8str_compare_insensitive(
+	const std::string& lhs,
+	const std::string& rhs);
+
+/**
+ * @brief Replace all occurences of target_char with replace_char
+ *
+ * @param utf8str A utf8 string to process.
+ * @param target_char The wchar to be replaced
+ * @param replace_char The wchar which is written on replace
+ */
+LL_COMMON_API std::string utf8str_substChar(
+	const std::string& utf8str,
+	const llwchar target_char,
+	const llwchar replace_char);
+
+LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str);
+
+// Hack - used for evil notecards.
+LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); 
+
+LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
+
+
+#if LL_WINDOWS
+/* @name Windows string helpers
+ */
+//@{
+
+/**
+ * @brief Implementation the expected snprintf interface.
+ *
+ * If the size of the passed in buffer is not large enough to hold the string,
+ * two bad things happen:
+ * 1. resulting formatted string is NOT null terminated
+ * 2. Depending on the platform, the return value could be a) the required
+ *    size of the buffer to copy the entire formatted string or b) -1.
+ *    On Windows with VS.Net 2003, it returns -1 e.g. 
+ *
+ * safe_snprintf always adds a NULL terminator so that the caller does not
+ * need to check for return value or need to add the NULL terminator.
+ * It does not, however change the return value - to let the caller know
+ * that the passed in buffer size was not large enough to hold the
+ * formatted string.
+ *
+ */
+
+// Deal with the differeneces on Windows
+namespace snprintf_hack
+{
+	LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...);
+}
+
+using snprintf_hack::snprintf;
+
+/**
+ * @brief Convert a wide string to std::string
+ *
+ * This replaces the unsafe W2A macro from ATL.
+ */
+LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in);
+
+//@}
+#endif // LL_WINDOWS
+
+/**
+ * Many of the 'strip' and 'replace' methods of LLStringUtilBase need
+ * specialization to work with the signed char type.
+ * Sadly, it is not possible (AFAIK) to specialize a single method of
+ * a template class.
+ * That stuff should go here.
+ */
+namespace LLStringFn
+{
+	/**
+	 * @brief Replace all non-printable characters with replacement in
+	 * string.
+	 * NOTE - this will zap non-ascii
+	 *
+	 * @param [in,out] string the to modify. out value is the string
+	 * with zero non-printable characters.
+	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
+	 */
+	LL_COMMON_API void replace_nonprintable_in_ascii(
+		std::basic_string<char>& string,
+		char replacement);
+
+
+	/**
+	 * @brief Replace all non-printable characters and pipe characters
+	 * with replacement in a string.
+	 * NOTE - this will zap non-ascii
+	 *
+	 * @param [in,out] the string to modify. out value is the string
+	 * with zero non-printable characters and zero pipe characters.
+	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
+	 */
+	LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
+									   char replacement);
+
+
+	/**
+	 * @brief Remove all characters that are not allowed in XML 1.0.
+	 * Returns a copy of the string with those characters removed.
+	 * Works with US ASCII and UTF-8 encoded strings.  JC
+	 */
+	LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
+
+
+	/**
+	 * @brief Replace all control characters (0 <= c < 0x20) with replacement in
+	 * string.   This is safe for utf-8
+	 *
+	 * @param [in,out] string the to modify. out value is the string
+	 * with zero non-printable characters.
+	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
+	 */
+	LL_COMMON_API void replace_ascii_controlchars(
+		std::basic_string<char>& string,
+		char replacement);
+}
+
+////////////////////////////////////////////////////////////
+// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
+// There is no LLWStringUtil::format implementation currently.
+// Calling thse for anything other than LLStringUtil will produce link errors.
+
+////////////////////////////////////////////////////////////
+
+
+// static
+template<class T> 
+S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
+{	
+	S32 result;
+	if( lhs == rhs )
+	{
+		result = 0;
+	}
+	else
+	if ( !lhs || !lhs[0] )
+	{
+		result = ((!rhs || !rhs[0]) ? 0 : 1);
+	}
+	else
+	if ( !rhs || !rhs[0])
+	{
+		result = -1;
+	}
+	else
+	{
+		result = LLStringOps::collate(lhs, rhs);
+	}
+	return result;
+}
+
+//static 
+template<class T> 
+S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
+{
+	return LLStringOps::collate(lhs.c_str(), rhs.c_str());
+}
+
+// static
+template<class T> 
+S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
+{
+	S32 result;
+	if( lhs == rhs )
+	{
+		result = 0;
+	}
+	else
+	if ( !lhs || !lhs[0] )
+	{
+		result = ((!rhs || !rhs[0]) ? 0 : 1);
+	}
+	else
+	if ( !rhs || !rhs[0] )
+	{
+		result = -1;
+	}
+	else
+	{
+		std::basic_string<T> lhs_string(lhs);
+		std::basic_string<T> rhs_string(rhs);
+		LLStringUtilBase<T>::toUpper(lhs_string);
+		LLStringUtilBase<T>::toUpper(rhs_string);
+		result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
+	}
+	return result;
+}
+
+//static 
+template<class T> 
+S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
+{
+	std::basic_string<T> lhs_string(lhs);
+	std::basic_string<T> rhs_string(rhs);
+	LLStringUtilBase<T>::toUpper(lhs_string);
+	LLStringUtilBase<T>::toUpper(rhs_string);
+	return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
+}
+
+// Case sensitive comparison with good handling of numbers.  Does not use current locale.
+// a.k.a. strdictcmp()
+
+//static 
+template<class T>
+S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
+{
+	const T* a = astr.c_str();
+	const T* b = bstr.c_str();
+	T ca, cb;
+	S32 ai, bi, cnt = 0;
+	S32 bias = 0;
+
+	ca = *(a++);
+	cb = *(b++);
+	while( ca && cb ){
+		if( bias==0 ){
+			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; }
+			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; }
+		}else{
+			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
+			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
+		}
+		if( LLStringOps::isDigit(ca) ){
+			if( cnt-->0 ){
+				if( cb!=ca ) break;
+			}else{
+				if( !LLStringOps::isDigit(cb) ) break;
+				for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
+				for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
+				if( ai<bi ){ ca=0; break; }
+				if( bi<ai ){ cb=0; break; }
+				if( ca!=cb ) break;
+				cnt = ai;
+			}
+		}else if( ca!=cb ){   break;
+		}
+		ca = *(a++);
+		cb = *(b++);
+	}
+	if( ca==cb ) ca += bias;
+	return ca-cb;
+}
+
+// static
+template<class T>
+S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
+{
+	const T* a = astr.c_str();
+	const T* b = bstr.c_str();
+	T ca, cb;
+	S32 ai, bi, cnt = 0;
+
+	ca = *(a++);
+	cb = *(b++);
+	while( ca && cb ){
+		if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
+		if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
+		if( LLStringOps::isDigit(ca) ){
+			if( cnt-->0 ){
+				if( cb!=ca ) break;
+			}else{
+				if( !LLStringOps::isDigit(cb) ) break;
+				for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
+				for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
+				if( ai<bi ){ ca=0; break; }
+				if( bi<ai ){ cb=0; break; }
+				if( ca!=cb ) break;
+				cnt = ai;
+			}
+		}else if( ca!=cb ){   break;
+		}
+		ca = *(a++);
+		cb = *(b++);
+	}
+	return ca-cb;
+}
+
+// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
+// static 
+template<class T> 
+BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
+{
+	if( a.size() && b.size() )
+	{
+		return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
+	}
+	else
+	{
+		return (!b.empty());
+	}
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)	
+{ 
+	if( !string.empty() )
+	{ 
+		std::transform(
+			string.begin(),
+			string.end(),
+			string.begin(),
+			(T(*)(T)) &LLStringOps::toUpper);
+	}
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
+{ 
+	if( !string.empty() )
+	{ 
+		std::transform(
+			string.begin(),
+			string.end(),
+			string.begin(),
+			(T(*)(T)) &LLStringOps::toLower);
+	}
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
+{			
+	if( !string.empty() )
+	{
+		size_type i = 0;
+		while( i < string.length() && LLStringOps::isSpace( string[i] ) )
+		{
+			i++;
+		}
+		string.erase(0, i);
+	}
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
+{			
+	if( string.size() )
+	{
+		size_type len = string.length();
+		size_type i = len;
+		while( i > 0 && LLStringOps::isSpace( string[i-1] ) )
+		{
+			i--;
+		}
+
+		string.erase( i, len - i );
+	}
+}
+
+
+// Replace line feeds with carriage return-line feed pairs.
+//static
+template<class T>
+void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
+{
+	const T LF = 10;
+	const T CR = 13;
+
+	// Count the number of line feeds
+	size_type count = 0;
+	size_type len = string.size();
+	size_type i;
+	for( i = 0; i < len; i++ )
+	{
+		if( string[i] == LF )
+		{
+			count++;
+		}
+	}
+
+	// Insert a carriage return before each line feed
+	if( count )
+	{
+		size_type size = len + count;
+		T *t = new T[size];
+		size_type j = 0;
+		for( i = 0; i < len; ++i )
+		{
+			if( string[i] == LF )
+			{
+				t[j] = CR;
+				++j;
+			}
+			t[j] = string[i];
+			++j;
+		}
+
+		string.assign(t, size);
+	}
+}
+
+// Remove all carriage returns
+//static
+template<class T> 
+void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
+{
+	const T CR = 13;
+
+	size_type cr_count = 0;
+	size_type len = string.size();
+	size_type i;
+	for( i = 0; i < len - cr_count; i++ )
+	{
+		if( string[i+cr_count] == CR )
+		{
+			cr_count++;
+		}
+
+		string[i] = string[i+cr_count];
+	}
+	string.erase(i, cr_count);
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
+{
+	size_type found_pos = 0;
+	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) 
+	{
+		string[found_pos] = replacement;
+		found_pos++; // avoid infinite defeat if target == replacement
+	}
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement )
+{
+	size_type found_pos = 0;
+	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
+	{
+		string.replace( found_pos, target.length(), replacement );
+		found_pos += replacement.length(); // avoid infinite defeat if replacement contains target
+	}
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
+{
+	const char LF = 10;
+	const S8 MIN = 32;
+//	const S8 MAX = 127;
+
+	size_type len = string.size();
+	for( size_type i = 0; i < len; i++ )
+	{
+		// No need to test MAX < mText[i] because we treat mText[i] as a signed char,
+		// which has a max value of 127.
+		if( ( S8(string[i]) < MIN ) && (string[i] != LF) )
+		{
+			string[i] = replacement;
+		}
+	}
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
+{
+	const T TAB = '\t';
+	const T SPACE = ' ';
+
+	std::basic_string<T> out_str;
+	// Replace tabs with spaces
+	for (size_type i = 0; i < str.length(); i++)
+	{
+		if (str[i] == TAB)
+		{
+			for (size_type j = 0; j < spaces_per_tab; j++)
+				out_str += SPACE;
+		}
+		else
+		{
+			out_str += str[i];
+		}
+	}
+	str = out_str;
+}
+
+//static
+template<class T> 
+BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
+{
+	const char MIN = 32;
+	BOOL rv = FALSE;
+	for (size_type i = 0; i < string.size(); i++)
+	{
+		if(string[i] < MIN)
+		{
+			rv = TRUE;
+			break;
+		}
+	}
+	return rv;
+}
+
+//static
+template<class T> 
+void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
+{
+	const char MIN = 32;
+	size_type j = 0;
+	if (string.empty())
+	{
+		return;
+	}
+	size_t src_size = string.size();
+	char* c_string = new char[src_size + 1];
+	if(c_string == NULL)
+	{
+		return;
+	}
+	copy(c_string, string.c_str(), src_size+1);
+	char* write_head = &c_string[0];
+	for (size_type i = 0; i < src_size; i++)
+	{
+		char* read_head = &string[i];
+		write_head = &c_string[j];
+		if(!(*read_head < MIN))
+		{
+			*write_head = *read_head;
+			++j;
+		}
+	}
+	c_string[j]= '\0';
+	string = c_string;
+	delete []c_string;
+}
+
+template<class T> 
+void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
+{
+	// Replace non-ASCII chars with LL_UNKNOWN_CHAR
+	for (size_type i = 0; i < string.length(); i++)
+	{
+		if (string[i] > 0x7f)
+		{
+			string[i] = LL_UNKNOWN_CHAR;
+		}
+	}
+}
+
+// static
+template<class T> 
+void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
+{
+	if( dst_size > 0 )
+	{
+		size_type min_len = 0;
+		if( src )
+		{
+			min_len = llmin( dst_size - 1, strlen( src ) );  /* Flawfinder: ignore */
+			memcpy(dst, src, min_len * sizeof(T));		/* Flawfinder: ignore */
+		}
+		dst[min_len] = '\0';
+	}
+}
+
+// static
+template<class T> 
+void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
+{
+	if ( offset == dst.length() )
+	{
+		// special case - append to end of string and avoid expensive
+		// (when strings are large) string manipulations
+		dst += src;
+	}
+	else
+	{
+		std::basic_string<T> tail = dst.substr(offset);
+
+		dst = dst.substr(0, offset);
+		dst += src;
+		dst += tail;
+	};
+}
+
+// True if this is the head of s.
+//static
+template<class T> 
+BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s ) 
+{ 
+	if( string.empty() )
+	{
+		// Early exit
+		return FALSE;
+	}
+	else
+	{
+		return (strncmp( s, string.c_str(), string.size() ) == 0);
+	}
+}
+
+// static
+template<class T> 
+bool LLStringUtilBase<T>::startsWith(
+	const std::basic_string<T>& string,
+	const std::basic_string<T>& substr)
+{
+	if(string.empty() || (substr.empty())) return false;
+	if(0 == string.find(substr)) return true;
+	return false;
+}
+
+// static
+template<class T> 
+bool LLStringUtilBase<T>::endsWith(
+	const std::basic_string<T>& string,
+	const std::basic_string<T>& substr)
+{
+	if(string.empty() || (substr.empty())) return false;
+	std::string::size_type idx = string.rfind(substr);
+	if(std::string::npos == idx) return false;
+	return (idx == (string.size() - substr.size()));
+}
+
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
+{
+	if( string.empty() )
+	{
+		return FALSE;
+	}
+
+	std::basic_string<T> temp( string );
+	trim(temp);
+	if( 
+		(temp == "1") || 
+		(temp == "T") || 
+		(temp == "t") || 
+		(temp == "TRUE") || 
+		(temp == "true") || 
+		(temp == "True") )
+	{
+		value = TRUE;
+		return TRUE;
+	}
+	else
+	if( 
+		(temp == "0") || 
+		(temp == "F") || 
+		(temp == "f") || 
+		(temp == "FALSE") || 
+		(temp == "false") || 
+		(temp == "False") )
+	{
+		value = FALSE;
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value) 
+{
+	S32 value32 = 0;
+	BOOL success = convertToS32(string, value32);
+	if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) )
+	{
+		value = (U8) value32;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value) 
+{
+	S32 value32 = 0;
+	BOOL success = convertToS32(string, value32);
+	if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) )
+	{
+		value = (S8) value32;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value) 
+{
+	S32 value32 = 0;
+	BOOL success = convertToS32(string, value32);
+	if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) )
+	{
+		value = (S16) value32;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value) 
+{
+	S32 value32 = 0;
+	BOOL success = convertToS32(string, value32);
+	if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) )
+	{
+		value = (U16) value32;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) 
+{
+	if( string.empty() )
+	{
+		return FALSE;
+	}
+
+	std::basic_string<T> temp( string );
+	trim(temp);
+	U32 v;
+	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
+	if(i_stream >> v)
+	{
+		value = v;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) 
+{
+	if( string.empty() )
+	{
+		return FALSE;
+	}
+
+	std::basic_string<T> temp( string );
+	trim(temp);
+	S32 v;
+	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
+	if(i_stream >> v)
+	{
+		//TODO: figure out overflow and underflow reporting here
+		//if((LONG_MAX == v) || (LONG_MIN == v))
+		//{
+		//	// Underflow or overflow
+		//	return FALSE;
+		//}
+
+		value = v;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value) 
+{
+	F64 value64 = 0.0;
+	BOOL success = convertToF64(string, value64);
+	if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) )
+	{
+		value = (F32) value64;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
+{
+	if( string.empty() )
+	{
+		return FALSE;
+	}
+
+	std::basic_string<T> temp( string );
+	trim(temp);
+	F64 v;
+	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
+	if(i_stream >> v)
+	{
+		//TODO: figure out overflow and underflow reporting here
+		//if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) )
+		//{
+		//	// Underflow or overflow
+		//	return FALSE;
+		//}
+
+		value = v;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+template<class T> 
+void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
+{
+	size_type cur_size = string.size();
+	string.resize(count < cur_size ? count : cur_size);
+}
+
+#endif  // LL_STRING_H
diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h
index 888361b0b9a1168e77df70a3ac57aba8f5b134f8..d40c9d8dfdab77df16f2f72800756a5e0b74edcf 100644
--- a/indra/llcommon/llstringtable.h
+++ b/indra/llcommon/llstringtable.h
@@ -48,15 +48,17 @@
 //# define STRING_TABLE_HASH_MAP 1
 #endif
 
-#if LL_WINDOWS
-#include <hash_map>
-#else
-#include <ext/hash_map>
+#if STRING_TABLE_HASH_MAP
+# if LL_WINDOWS
+#  include <hash_map>
+# else
+#  include <ext/hash_map>
+# endif
 #endif
 
 const U32 MAX_STRINGS_LENGTH = 256;
 
-class LLStringTableEntry
+class LL_COMMON_API LLStringTableEntry
 {
 public:
 	LLStringTableEntry(const char *str);
@@ -69,7 +71,7 @@ class LLStringTableEntry
 	S32  mCount;
 };
 
-class LLStringTable
+class LL_COMMON_API LLStringTable
 {
 public:
 	LLStringTable(int tablesize);
@@ -103,7 +105,7 @@ class LLStringTable
 #endif	
 };
 
-extern LLStringTable gStringTable;
+extern LL_COMMON_API LLStringTable gStringTable;
 
 //============================================================================
 
@@ -113,7 +115,7 @@ extern LLStringTable gStringTable;
 
 typedef const std::string* LLStdStringHandle;
 
-class LLStdStringTable
+class LL_COMMON_API LLStdStringTable
 {
 public:
 	LLStdStringTable(S32 tablesize = 0)
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 47374212893cbda75bbc9c0f3aa58279fa4b1932..3652eeba729a282be83c6561fc7edbd9a42aae7a 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -161,8 +161,16 @@ LLOSInfo::LLOSInfo() :
 						mOSStringSimple = "Microsoft Windows Vista Server ";
 				}
 			}
+			else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
+			{
+				 if(osvi.wProductType == VER_NT_WORKSTATION)
+					mOSStringSimple = "Microsoft Windows 7 ";
+				 else mOSStringSimple = "Microsoft Windows 7 Server ";
+			}
 			else   // Use the registry on early versions of Windows NT.
 			{
+				mOSStringSimple = "Microsoft Windows (unrecognized) ";
+
 				HKEY hKey;
 				WCHAR szProductType[80];
 				DWORD dwBufLen;
diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h
index 03f48ca0187cbe5a1d21e3230ece3325be510945..c2c45bec9a2a01ea8ce735a70d4d0995176a0a56 100644
--- a/indra/llcommon/llsys.h
+++ b/indra/llcommon/llsys.h
@@ -45,7 +45,7 @@
 #include <iosfwd>
 #include <string>
 
-class LLOSInfo
+class LL_COMMON_API LLOSInfo
 {
 public:
 	LLOSInfo();
@@ -70,7 +70,7 @@ class LLOSInfo
 };
 
 
-class LLCPUInfo
+class LL_COMMON_API LLCPUInfo
 {
 public:
 	LLCPUInfo();	
@@ -99,7 +99,7 @@ class LLCPUInfo
 //
 //	CLASS		LLMemoryInfo
 
-class LLMemoryInfo
+class LL_COMMON_API LLMemoryInfo
 
 /*!	@brief		Class to query the memory subsystem
 
@@ -123,15 +123,15 @@ class LLMemoryInfo
 };
 
 
-std::ostream& operator<<(std::ostream& s, const LLOSInfo& info);
-std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info);
-std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLOSInfo& info);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info);
 
 // gunzip srcfile into dstfile.  Returns FALSE on error.
-BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile);
+BOOL LL_COMMON_API gunzip_file(const std::string& srcfile, const std::string& dstfile);
 // gzip srcfile into dstfile.  Returns FALSE on error.
-BOOL gzip_file(const std::string& srcfile, const std::string& dstfile);
+BOOL LL_COMMON_API gzip_file(const std::string& srcfile, const std::string& dstfile);
 
-extern LLCPUInfo gSysCPU;
+extern LL_COMMON_API LLCPUInfo gSysCPU;
 
 #endif // LL_LLSYS_H
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index f25339f48d124ce2d8baf9d77984bcaa0afcb69e..c3d7650bd9b2d101ddb117c5b1fa679665f17f75 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -42,7 +42,7 @@ class LLThread;
 class LLMutex;
 class LLCondition;
 
-class LLThread
+class LL_COMMON_API LLThread
 {
 public:
 	typedef enum e_thread_status
@@ -130,7 +130,7 @@ class LLThread
 
 //============================================================================
 
-class LLMutex
+class LL_COMMON_API LLMutex
 {
 public:
 	LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
@@ -147,7 +147,7 @@ class LLMutex
 };
 
 // Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
-class LLCondition : public LLMutex
+class LL_COMMON_API LLCondition : public LLMutex
 {
 public:
 	LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
@@ -194,7 +194,7 @@ void LLThread::unlockData()
 
 // see llmemory.h for LLPointer<> definition
 
-class LLThreadSafeRefCount
+class LL_COMMON_API LLThreadSafeRefCount
 {
 public:
 	static void initThreadSafeRefCount(); // creates sMutex
@@ -246,7 +246,7 @@ class LLThreadSafeRefCount
 
 // Simple responder for self destructing callbacks
 // Pure virtual class
-class LLResponder : public LLThreadSafeRefCount
+class LL_COMMON_API LLResponder : public LLThreadSafeRefCount
 {
 protected:
 	virtual ~LLResponder();
diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h
index 0319bec45b62f7da8d1c72c80b5502e74d718657..d009c0f5f7dfc7b05dadac715b195c33eddd99ee 100644
--- a/indra/llcommon/lltimer.h
+++ b/indra/llcommon/lltimer.h
@@ -55,7 +55,7 @@ const U32	USEC_PER_HOUR	= USEC_PER_MIN * MIN_PER_HOUR;
 const U32	SEC_PER_HOUR	= SEC_PER_MIN * MIN_PER_HOUR;
 const F64 	SEC_PER_USEC 	= 1.0 / (F64) USEC_PER_SEC;
 
-class LLTimer 
+class LL_COMMON_API LLTimer 
 {
 public:
 	static LLTimer *sTimer;				// global timer
@@ -114,17 +114,17 @@ class LLTimer
 //
 // Various functions for initializing/accessing clock and timing stuff.  Don't use these without REALLY knowing how they work.
 //
-U64 get_clock_count();
-F64 calc_clock_frequency(U32 msecs);
-void update_clock_frequencies();
+LL_COMMON_API U64 get_clock_count();
+LL_COMMON_API F64 calc_clock_frequency(U32 msecs);
+LL_COMMON_API void update_clock_frequencies();
 
 // Sleep for milliseconds
-void ms_sleep(U32 ms);
-U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF);
+LL_COMMON_API void ms_sleep(U32 ms);
+LL_COMMON_API U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF);
 
 // Returns the correct UTC time in seconds, like time(NULL).
 // Useful on the viewer, which may have its local clock set wrong.
-time_t time_corrected();
+LL_COMMON_API time_t time_corrected();
 
 static inline time_t time_min()
 {
@@ -155,24 +155,24 @@ static inline time_t time_max()
 }
 
 // Correction factor used by time_corrected() above.
-extern S32 gUTCOffset;
+extern LL_COMMON_API S32 gUTCOffset;
 
 // Is the current computer (in its current time zone)
 // observing daylight savings time?
-BOOL is_daylight_savings();
+LL_COMMON_API BOOL is_daylight_savings();
 
 // Converts internal "struct tm" time buffer to Pacific Standard/Daylight Time
 // Usage:
 // S32 utc_time;
 // utc_time = time_corrected();
 // struct tm* internal_time = utc_to_pacific_time(utc_time, gDaylight);
-struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time);
+LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time);
 
-void microsecondsToTimecodeString(U64 current_time, std::string& tcstring);
-void secondsToTimecodeString(F32 current_time, std::string& tcstring);
+LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring);
+LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring);
 
 // class for scheduling a function to be called at a given frequency (approximate, inprecise)
-class LLEventTimer : protected LLInstanceTracker<LLEventTimer>
+class LL_COMMON_API LLEventTimer : protected LLInstanceTracker<LLEventTimer>
 {
 public:
 	LLEventTimer(F32 period);	// period is the amount of time between each call to tick() in seconds
@@ -190,4 +190,6 @@ class LLEventTimer : protected LLInstanceTracker<LLEventTimer>
 	F32 mPeriod;
 };
 
+U64 LL_COMMON_API totalTime();					// Returns current system time in microseconds
+
 #endif
diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h
index 8e46e2e89ef3049bea7445d0b6b2b7d23ae8f99f..8e69e8558ac178d3eaecb035eff26db3947a6f47 100644
--- a/indra/llcommon/lluri.h
+++ b/indra/llcommon/lluri.h
@@ -47,7 +47,7 @@ class LLApp;
  * See: http://www.ietf.org/rfc/rfc3986.txt
  *
  */
-class LLURI
+class LL_COMMON_API LLURI
 {
 public:
   LLURI();
@@ -178,6 +178,6 @@ class LLURI
 };
 
 // this operator required for tut
-bool operator!=(const LLURI& first, const LLURI& second);
+LL_COMMON_API bool operator!=(const LLURI& first, const LLURI& second);
 
 #endif // LL_LLURI_H
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index 4b32138a065a0a7878948d0f1cc4908068fc42d2..c78fb1201804686242792e28950e4a340f4a1cc8 100644
--- a/indra/llcommon/lluuid.h
+++ b/indra/llcommon/lluuid.h
@@ -35,6 +35,7 @@
 #include <iostream>
 #include <set>
 #include "stdtypes.h"
+#include "llpreprocessor.h"
 
 const S32 UUID_BYTES = 16;
 const S32 UUID_WORDS = 4;
@@ -47,7 +48,7 @@ struct uuid_time_t {
 	U32 low;
 		};
 
-class LLUUID
+class LL_COMMON_API LLUUID
 {
 public:
 	//
@@ -106,8 +107,8 @@ class LLUUID
 	LLUUID combine(const LLUUID& other) const;
 	void combine(const LLUUID& other, LLUUID& result) const;  
 
-	friend std::ostream&	 operator<<(std::ostream& s, const LLUUID &uuid);
-	friend std::istream&	 operator>>(std::istream& s, LLUUID &uuid);
+	friend LL_COMMON_API std::ostream&	 operator<<(std::ostream& s, const LLUUID &uuid);
+	friend LL_COMMON_API std::istream&	 operator>>(std::istream& s, LLUUID &uuid);
 
 	void toString(char *out) const;		// Does not allocate memory, needs 36 characters (including \0)
 	void toString(std::string& out) const;
@@ -323,7 +324,7 @@ typedef std::set<LLUUID, lluuid_less> uuid_list_t;
  */
 typedef LLUUID LLAssetID;
 
-class LLTransactionID : public LLUUID
+class LL_COMMON_API LLTransactionID : public LLUUID
 {
 public:
 	LLTransactionID() : LLUUID() { }
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h
index 23e39ceb08f0f02d5848c45f2cf7d0e56d485b2d..71c6fc059192e85fe03ca70fded4c6a8d90ceaba 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -34,9 +34,9 @@
 #define LL_LLVERSIONSERVER_H
 
 const S32 LL_VERSION_MAJOR = 1;
-const S32 LL_VERSION_MINOR = 29;
+const S32 LL_VERSION_MINOR = 31;
 const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 0;
+const S32 LL_VERSION_BUILD = 3256;
 
 const char * const LL_CHANNEL = "Second Life Server";
 
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 2c3e9c73337275b6a6932433415aca4c54f80e28..082d054ba2efa5a6d53bf6bed1c8e86d561c4bb4 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -36,7 +36,7 @@
 const S32 LL_VERSION_MAJOR = 2;
 const S32 LL_VERSION_MINOR = 0;
 const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 0;
+const S32 LL_VERSION_BUILD = 3256;
 
 const char * const LL_CHANNEL = "Second Life Developer";
 
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 19407f4463886b922163d9857a2bed49457db130..a12bd52a648775f4532606848442873e6e89148d 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -50,7 +50,7 @@ class LLWorkerClass;
 // Note: ~LLWorkerThread is O(N) N=# of worker threads, assumed to be small
 //   It is assumed that LLWorkerThreads are rarely created/destroyed.
 
-class LLWorkerThread : public LLQueuedThread
+class LL_COMMON_API LLWorkerThread : public LLQueuedThread
 {
 public:
 	class WorkRequest : public LLQueuedThread::QueuedRequest
@@ -113,7 +113,7 @@ class LLWorkerThread : public LLQueuedThread
 // Only one background task can be active at a time (per instance).
 //  i.e. don't call addWork() if haveWork() returns true
 
-class LLWorkerClass
+class LL_COMMON_API LLWorkerClass
 {
 	friend class LLWorkerThread;
 	friend class LLWorkerThread::WorkRequest;
diff --git a/indra/llcommon/metaclass.h b/indra/llcommon/metaclass.h
index cc10f1675f25c55903710996235883e589ba4138..f38bcd2d57c8058c49668552113b29162c97f889 100644
--- a/indra/llcommon/metaclass.h
+++ b/indra/llcommon/metaclass.h
@@ -43,7 +43,7 @@
 class LLReflective;
 class LLMetaProperty;
 class LLMetaMethod;
-class LLMetaClass
+class LL_COMMON_API LLMetaClass
 {
 public:
 
diff --git a/indra/llcommon/metaproperty.h b/indra/llcommon/metaproperty.h
index e5ac35907c0e96b6887e029834714366350bcd3c..6c016c56ddce9ebb8dc803aa63067d7c969893e6 100644
--- a/indra/llcommon/metaproperty.h
+++ b/indra/llcommon/metaproperty.h
@@ -41,7 +41,7 @@
 
 class LLMetaClass;
 class LLReflective;
-class LLMetaProperty
+class LL_COMMON_API LLMetaProperty
 {
 public:
 	LLMetaProperty(const std::string& name, const LLMetaClass& object_class);
diff --git a/indra/llcommon/metapropertyt.h b/indra/llcommon/metapropertyt.h
index 79a536a224ffaf1ae668747fb5ab3bfd95451b93..5ad230d1d5e8fb8556b84fa28a5a873c673e2621 100644
--- a/indra/llcommon/metapropertyt.h
+++ b/indra/llcommon/metapropertyt.h
@@ -93,6 +93,13 @@ inline const LLReflective* LLMetaPropertyT<LLUUID>::get(const LLReflective* obje
 	return NULL;
 }
 
+template <>
+inline const LLReflective* LLMetaPropertyT<bool>::get(const LLReflective* object) const
+{
+	checkObjectClass(object);
+	return NULL;
+}
+
 template <>
 inline LLSD LLMetaPropertyT<S32>::getLLSD(const LLReflective* object) const
 {
@@ -111,6 +118,12 @@ inline LLSD LLMetaPropertyT<LLUUID>::getLLSD(const LLReflective* object) const
 	return *(getProperty(object));
 }
 
+template <>
+inline LLSD LLMetaPropertyT<bool>::getLLSD(const LLReflective* object) const
+{
+	return *(getProperty(object));
+}
+
 template<class TObject, class TProperty>
 class LLMetaPropertyTT : public LLMetaPropertyT<TProperty>
 {
diff --git a/indra/llcommon/reflective.h b/indra/llcommon/reflective.h
index e2c18ebc6da96ce0f5888d030000d2d73543e5f1..a13537681d7259adbf27e6bc497569f5fcaea7a6 100644
--- a/indra/llcommon/reflective.h
+++ b/indra/llcommon/reflective.h
@@ -36,7 +36,7 @@
 #define LL_REFLECTIVE_H
 
 class LLMetaClass;
-class LLReflective
+class LL_COMMON_API LLReflective
 {
 public:
 	LLReflective();
diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
index 1b2958020fa91f9f28a4cc6b97717a570d3c8a8f..6399547f5e628830727041e8af7e73560a50e533 100644
--- a/indra/llcommon/stringize.h
+++ b/indra/llcommon/stringize.h
@@ -13,6 +13,7 @@
 #define LL_STRINGIZE_H
 
 #include <sstream>
+#include <boost/lambda/lambda.hpp>
 
 /**
  * stringize(item) encapsulates an idiom we use constantly, using
@@ -27,6 +28,17 @@ std::string stringize(const T& item)
     return out.str();
 }
 
+/**
+ * stringize_f(functor)
+ */
+template <typename Functor>
+std::string stringize_f(Functor const & f)
+{
+    std::ostringstream out;
+    f(out);
+    return out.str();
+}
+
 /**
  * STRINGIZE(item1 << item2 << item3 ...) effectively expands to the
  * following:
@@ -36,40 +48,43 @@ std::string stringize(const T& item)
  * return out.str();
  * @endcode
  */
-#define STRINGIZE(EXPRESSION) (static_cast<std::ostringstream&>(Stringize() << EXPRESSION).str())
+#define STRINGIZE(EXPRESSION) (stringize_f(boost::lambda::_1 << EXPRESSION))
+
 
 /**
- * Helper class for STRINGIZE() macro. Ideally the body of
- * STRINGIZE(EXPRESSION) would look something like this:
+ * destringize(str)
+ * defined for symmetry with stringize
+ * *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
+ * leading/trailing whitespace and handling of bad_lexical_cast exceptions
+ */
+template <typename T>
+T destringize(std::string const & str)
+{
+	T val;
+    std::istringstream in(str);
+	in >> val;
+    return val;
+}
+
+/**
+ * destringize_f(str, functor)
+ */
+template <typename Functor>
+void destringize_f(std::string const & str, Functor const & f)
+{
+    std::istringstream in(str);
+    f(in);
+}
+
+/**
+ * DESTRINGIZE(str, item1 >> item2 >> item3 ...) effectively expands to the
+ * following:
  * @code
- * (std::ostringstream() << EXPRESSION).str()
+ * std::istringstream in(str);
+ * in >> item1 >> item2 >> item3 ... ;
  * @endcode
- * That doesn't work because each of the relevant operator<<() functions
- * accepts a non-const std::ostream&, to which you can't pass a temp instance
- * of std::ostringstream. Stringize plays the necessary const tricks to make
- * the whole thing work.
  */
-class Stringize
-{
-public:
-    /**
-     * This is the essence of Stringize. The leftmost << operator (the one
-     * coded in the STRINGIZE() macro) engages this operator<<() const method
-     * on the temp Stringize instance. Every other << operator (ones embedded
-     * in EXPRESSION) simply sees the std::ostream& returned by the first one.
-     *
-     * Finally, the STRINGIZE() macro downcasts that std::ostream& to
-     * std::ostringstream&.
-     */
-    template <typename T>
-    std::ostream& operator<<(const T& item) const
-    {
-        mOut << item;
-        return mOut;
-    }
+#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::lambda::_1 >> EXPRESSION)))
 
-private:
-    mutable std::ostringstream mOut;
-};
 
 #endif /* ! defined(LL_STRINGIZE_H) */
diff --git a/indra/llcommon/tests/listener.h b/indra/llcommon/tests/listener.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa12f944ef58def17b8c194b9a0e997b24540932
--- /dev/null
+++ b/indra/llcommon/tests/listener.h
@@ -0,0 +1,139 @@
+/**
+ * @file   listener.h
+ * @author Nat Goodspeed
+ * @date   2009-03-06
+ * @brief  Useful for tests of the LLEventPump family of classes
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LISTENER_H)
+#define LL_LISTENER_H
+
+#include "llsd.h"
+#include <iostream>
+
+/*****************************************************************************
+*   test listener class
+*****************************************************************************/
+class Listener;
+std::ostream& operator<<(std::ostream&, const Listener&);
+
+/// Bear in mind that this is strictly for testing
+class Listener
+{
+public:
+    /// Every Listener is instantiated with a name
+    Listener(const std::string& name):
+        mName(name)
+    {
+//      std::cout << *this << ": ctor\n";
+    }
+/*==========================================================================*|
+    // These methods are only useful when trying to track Listener instance
+    // lifespan
+    Listener(const Listener& that):
+        mName(that.mName),
+        mLastEvent(that.mLastEvent)
+    {
+        std::cout << *this << ": copy\n";
+    }
+    virtual ~Listener()
+    {
+        std::cout << *this << ": dtor\n";
+    }
+|*==========================================================================*/
+    /// You can request the name
+    std::string getName() const { return mName; }
+    /// This is a typical listener method that returns 'false' when done,
+    /// allowing subsequent listeners on the LLEventPump to process the
+    /// incoming event.
+    bool call(const LLSD& event)
+    {
+//      std::cout << *this << "::call(" << event << ")\n";
+        mLastEvent = event;
+        return false;
+    }
+    /// This is an alternate listener that returns 'true' when done, which
+    /// stops processing of the incoming event.
+    bool callstop(const LLSD& event)
+    {
+//      std::cout << *this << "::callstop(" << event << ")\n";
+        mLastEvent = event;
+        return true;
+    }
+    /// ListenMethod can represent either call() or callstop().
+    typedef bool (Listener::*ListenMethod)(const LLSD&);
+    /**
+     * This helper method is only because our test code makes so many
+     * repetitive listen() calls to ListenerMethods. In real code, you should
+     * call LLEventPump::listen() directly so it can examine the specific
+     * object you pass to boost::bind().
+     */
+    LLBoundListener listenTo(LLEventPump& pump,
+                             ListenMethod method=&Listener::call,
+                             const LLEventPump::NameList& after=LLEventPump::empty,
+                             const LLEventPump::NameList& before=LLEventPump::empty)
+    {
+        return pump.listen(getName(), boost::bind(method, this, _1), after, before);
+    }
+    /// Both call() and callstop() set mLastEvent. Retrieve it.
+    LLSD getLastEvent() const
+    {
+//      std::cout << *this << "::getLastEvent() -> " << mLastEvent << "\n";
+        return mLastEvent;
+    }
+    /// Reset mLastEvent to a known state.
+    void reset(const LLSD& to = LLSD())
+    {
+//      std::cout << *this << "::reset(" << to << ")\n";
+        mLastEvent = to;
+    }
+
+private:
+    std::string mName;
+    LLSD mLastEvent;
+};
+
+std::ostream& operator<<(std::ostream& out, const Listener& listener)
+{
+    out << "Listener(" << listener.getName() /* << "@" << &listener */ << ')';
+    return out;
+}
+
+/**
+ * This class tests the relative order in which various listeners on a given
+ * LLEventPump are called. Each listen() call binds a particular string, which
+ * we collect for later examination. The actual event is ignored.
+ */
+struct Collect
+{
+    bool add(const std::string& bound, const LLSD& event)
+    {
+        result.push_back(bound);
+        return false;
+    }
+    void clear() { result.clear(); }
+    typedef std::vector<std::string> StringList;
+    StringList result;
+};
+
+std::ostream& operator<<(std::ostream& out, const Collect::StringList& strings)
+{
+    out << '(';
+    Collect::StringList::const_iterator begin(strings.begin()), end(strings.end());
+    if (begin != end)
+    {
+        out << '"' << *begin << '"';
+        while (++begin != end)
+        {
+            out << ", \"" << *begin << '"';
+        }
+    }
+    out << ')';
+    return out;
+}
+
+#endif /* ! defined(LL_LISTENER_H) */
diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a2cda773509b13e69b12678be3d6cceb94eeb60
--- /dev/null
+++ b/indra/llcommon/tests/lleventcoro_test.cpp
@@ -0,0 +1,782 @@
+/**
+ * @file   coroutine_test.cpp
+ * @author Nat Goodspeed
+ * @date   2009-04-22
+ * @brief  Test for coroutine.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+/*****************************************************************************/
+//  test<1>() is cloned from a Boost.Coroutine example program whose copyright
+//  info is reproduced here:
+/*---------------------------------------------------------------------------*/
+//  Copyright (c) 2006, Giovanni P. Deretta
+//
+//  This code may be used under either of the following two licences:
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy 
+//  of this software and associated documentation files (the "Software"), to deal 
+//  in the Software without restriction, including without limitation the rights 
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+//  copies of the Software, and to permit persons to whom the Software is 
+//  furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included in 
+//  all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+//  THE SOFTWARE. OF SUCH DAMAGE.
+//
+//  Or:
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  (See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt)
+/*****************************************************************************/
+
+// On some platforms, Boost.Coroutine must #define magic symbols before
+// #including platform-API headers. Naturally, that's ineffective unless the
+// Boost.Coroutine #include is the *first* #include of the platform header.
+// That means that client code must generally #include Boost.Coroutine headers
+// before anything else.
+#include <boost/coroutine/coroutine.hpp>
+// Normally, lleventcoro.h obviates future.hpp. We only include this because
+// we implement a "by hand" test of future functionality.
+#include <boost/coroutine/future.hpp>
+#include <boost/bind.hpp>
+#include <boost/range.hpp>
+
+#include "linden_common.h"
+
+#include <iostream>
+#include <string>
+
+#include "../test/lltut.h"
+#include "llsd.h"
+#include "llevents.h"
+#include "tests/wrapllerrs.h"
+#include "stringize.h"
+#include "lleventcoro.h"
+#include "../test/debug.h"
+
+/*****************************************************************************
+*   from the banana.cpp example program borrowed for test<1>()
+*****************************************************************************/
+namespace coroutines = boost::coroutines;
+using coroutines::coroutine;
+
+template<typename Iter>
+bool match(Iter first, Iter last, std::string match) {
+  std::string::iterator i = match.begin();
+  i != match.end();
+  for(; (first != last) && (i != match.end()); ++i) {
+    if (*first != *i)
+      return false;
+    ++first;
+  }
+  return i == match.end();
+}
+
+template<typename BidirectionalIterator> 
+BidirectionalIterator 
+match_substring(BidirectionalIterator begin, 
+		BidirectionalIterator end, 
+		std::string xmatch,
+		BOOST_DEDUCED_TYPENAME coroutine<BidirectionalIterator(void)>::self& self) { 
+  BidirectionalIterator begin_ = begin;
+  for(; begin != end; ++begin) 
+    if(match(begin, end, xmatch)) {
+      self.yield(begin);
+    }
+  return end;
+} 
+
+typedef coroutine<std::string::iterator(void)> match_coroutine_type;
+
+/*****************************************************************************
+*   Test helpers
+*****************************************************************************/
+// I suspect this will be typical of coroutines used in Linden software
+typedef boost::coroutines::coroutine<void()> coroutine_type;
+
+/// Simulate an event API whose response is immediate: sent on receipt of the
+/// initial request, rather than after some delay. This is the case that
+/// distinguishes postAndWait() from calling post(), then calling
+/// waitForEventOn().
+class ImmediateAPI
+{
+public:
+    ImmediateAPI():
+        mPump("immediate", true)
+    {
+        mPump.listen("API", boost::bind(&ImmediateAPI::operator(), this, _1));
+    }
+
+    LLEventPump& getPump() { return mPump; }
+
+    // Invoke this with an LLSD map containing:
+    // ["value"]: Integer value. We will reply with ["value"] + 1.
+    // ["reply"]: Name of LLEventPump on which to send success response.
+    // ["error"]: Name of LLEventPump on which to send error response.
+    // ["fail"]: Presence of this key selects ["error"], else ["success"] as
+    // the name of the pump on which to send the response.
+    bool operator()(const LLSD& event) const
+    {
+        LLSD::Integer value(event["value"]);
+        LLSD::String replyPumpName(event.has("fail")? "error" : "reply");
+        LLEventPumps::instance().obtain(event[replyPumpName]).post(value + 1);
+        return false;
+    }
+
+private:
+    LLEventStream mPump;
+};
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct coroutine_data
+    {
+        // Define coroutine bodies as methods here so they can use ensure*()
+
+        void explicit_wait(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                // ... do whatever preliminary stuff must happen ...
+
+                // declare the future
+                boost::coroutines::future<LLSD> future(self);
+                // tell the future what to wait for
+                LLTempBoundListener connection(
+                    LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::coroutines::make_callback(future))));
+                ensure("Not yet", ! future);
+                // attempting to dereference ("resolve") the future causes the calling
+                // coroutine to wait for it
+                debug("about to wait");
+                result = *future;
+                ensure("Got it", future);
+            }
+            END
+        }
+
+        void waitForEventOn1(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                result = waitForEventOn(self, "source");
+            }
+            END
+        }
+
+        void waitForEventOn2(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLEventWithID pair = waitForEventOn(self, "reply", "error");
+                result = pair.first;
+                which  = pair.second;
+                debug(STRINGIZE("result = " << result << ", which = " << which));
+            }
+            END
+        }
+
+        void postAndWait1(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                result = postAndWait(self,
+                                     LLSD().insert("value", 17), // request event
+                                     immediateAPI.getPump(),     // requestPump
+                                     "reply1",                   // replyPump
+                                     "reply");                   // request["reply"] = name
+            }
+            END
+        }
+
+        void postAndWait2(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLEventWithID pair = ::postAndWait2(self,
+                                                    LLSD().insert("value", 18),
+                                                    immediateAPI.getPump(),
+                                                    "reply2",
+                                                    "error2",
+                                                    "reply",
+                                                    "error");
+                result = pair.first;
+                which  = pair.second;
+                debug(STRINGIZE("result = " << result << ", which = " << which));
+            }
+            END
+        }
+
+        void postAndWait2_1(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLEventWithID pair = ::postAndWait2(self,
+                                                    LLSD().insert("value", 18).insert("fail", LLSD()),
+                                                    immediateAPI.getPump(),
+                                                    "reply2",
+                                                    "error2",
+                                                    "reply",
+                                                    "error");
+                result = pair.first;
+                which  = pair.second;
+                debug(STRINGIZE("result = " << result << ", which = " << which));
+            }
+            END
+        }
+
+        void coroPump(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPump waiter;
+                replyName = waiter.getName();
+                result = waiter.wait(self);
+            }
+            END
+        }
+
+        void coroPumpPost(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPump waiter;
+                result = waiter.postAndWait(self, LLSD().insert("value", 17),
+                                            immediateAPI.getPump(), "reply");
+            }
+            END
+        }
+
+        void coroPumps(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                replyName = waiter.getName0();
+                errorName = waiter.getName1();
+                LLEventWithID pair(waiter.wait(self));
+                result = pair.first;
+                which  = pair.second;
+            }
+            END
+        }
+
+        void coroPumpsNoEx(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                replyName = waiter.getName0();
+                errorName = waiter.getName1();
+                result = waiter.waitWithException(self);
+            }
+            END
+        }
+
+        void coroPumpsEx(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                replyName = waiter.getName0();
+                errorName = waiter.getName1();
+                try
+                {
+                    result = waiter.waitWithException(self);
+                    debug("no exception");
+                }
+                catch (const LLErrorEvent& e)
+                {
+                    debug(STRINGIZE("exception " << e.what()));
+                    errordata = e.getData();
+                }
+            }
+            END
+        }
+
+        void coroPumpsNoLog(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                replyName = waiter.getName0();
+                errorName = waiter.getName1();
+                result = waiter.waitWithLog(self);
+            }
+            END
+        }
+
+        void coroPumpsLog(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                replyName = waiter.getName0();
+                errorName = waiter.getName1();
+                WrapLL_ERRS capture;
+                try
+                {
+                    result = waiter.waitWithLog(self);
+                    debug("no exception");
+                }
+                catch (const WrapLL_ERRS::FatalException& e)
+                {
+                    debug(STRINGIZE("exception " << e.what()));
+                    threw = e.what();
+                }
+            }
+            END
+        }
+
+        void coroPumpsPost(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                LLEventWithID pair(waiter.postAndWait(self, LLSD().insert("value", 23),
+                                                      immediateAPI.getPump(), "reply", "error"));
+                result = pair.first;
+                which  = pair.second;
+            }
+            END
+        }
+
+        void coroPumpsPost_1(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                LLEventWithID pair(
+                    waiter.postAndWait(self, LLSD().insert("value", 23).insert("fail", LLSD()),
+                                       immediateAPI.getPump(), "reply", "error"));
+                result = pair.first;
+                which  = pair.second;
+            }
+            END
+        }
+
+        void coroPumpsPostNoEx(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                result = waiter.postAndWaitWithException(self, LLSD().insert("value", 8),
+                                                         immediateAPI.getPump(), "reply", "error");
+            }
+            END
+        }
+
+        void coroPumpsPostEx(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                try
+                {
+                    result = waiter.postAndWaitWithException(self,
+                        LLSD().insert("value", 9).insert("fail", LLSD()),
+                        immediateAPI.getPump(), "reply", "error");
+                    debug("no exception");
+                }
+                catch (const LLErrorEvent& e)
+                {
+                    debug(STRINGIZE("exception " << e.what()));
+                    errordata = e.getData();
+                }
+            }
+            END
+        }
+
+        void coroPumpsPostNoLog(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                result = waiter.postAndWaitWithLog(self, LLSD().insert("value", 30),
+                                                   immediateAPI.getPump(), "reply", "error");
+            }
+            END
+        }
+
+        void coroPumpsPostLog(coroutine_type::self& self)
+        {
+            BEGIN
+            {
+                LLCoroEventPumps waiter;
+                WrapLL_ERRS capture;
+                try
+                {
+                    result = waiter.postAndWaitWithLog(self,
+                        LLSD().insert("value", 31).insert("fail", LLSD()),
+                        immediateAPI.getPump(), "reply", "error");
+                    debug("no exception");
+                }
+                catch (const WrapLL_ERRS::FatalException& e)
+                {
+                    debug(STRINGIZE("exception " << e.what()));
+                    threw = e.what();
+                }
+            }
+            END
+        }
+
+        void ensure_done(coroutine_type& coro)
+        {
+            ensure("coroutine complete", ! coro);
+        }
+
+        ImmediateAPI immediateAPI;
+        std::string replyName, errorName, threw;
+        LLSD result, errordata;
+        int which;
+    };
+    typedef test_group<coroutine_data> coroutine_group;
+    typedef coroutine_group::object object;
+    coroutine_group coroutinegrp("coroutine");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("From banana.cpp example program in Boost.Coroutine distro");
+        std::string buffer = "banananana"; 
+        std::string match = "nana"; 
+        std::string::iterator begin = buffer.begin();
+        std::string::iterator end = buffer.end();
+
+#if defined(BOOST_CORO_POSIX_IMPL)
+//      std::cout << "Using Boost.Coroutine " << BOOST_CORO_POSIX_IMPL << '\n';
+#else
+//      std::cout << "Using non-Posix Boost.Coroutine implementation" << std::endl;
+#endif
+
+        typedef std::string::iterator signature(std::string::iterator, 
+                                                std::string::iterator, 
+                                                std::string,
+                                                match_coroutine_type::self&);
+
+        coroutine<std::string::iterator(void)> matcher
+            (boost::bind(static_cast<signature*>(match_substring), 
+                         begin, 
+                         end, 
+                         match, 
+                         _1)); 
+
+        std::string::iterator i = matcher();
+/*==========================================================================*|
+        while(matcher && i != buffer.end()) {
+            std::cout <<"Match at: "<< std::distance(buffer.begin(), i)<<'\n'; 
+            i = matcher();
+        }
+|*==========================================================================*/
+        size_t matches[] = { 2, 4, 6 };
+        for (size_t *mi(boost::begin(matches)), *mend(boost::end(matches));
+             mi != mend; ++mi, i = matcher())
+        {
+            ensure("more", matcher);
+            ensure("found", i != buffer.end());
+            ensure_equals("value", std::distance(buffer.begin(), i), *mi);
+        }
+        ensure("done", ! matcher);
+    }
+
+    template<> template<>
+    void object::test<2>()
+    {
+        set_test_name("explicit_wait");
+        DEBUG;
+
+        // Construct the coroutine instance that will run explicit_wait.
+        // Pass the ctor a callable that accepts the coroutine_type::self
+        // param passed by the library.
+        coroutine_type coro(boost::bind(&coroutine_data::explicit_wait, this, _1));
+        // Start the coroutine
+        coro(std::nothrow);
+        // When the coroutine waits for the event pump, it returns here.
+        debug("about to send");
+        // Satisfy the wait.
+        LLEventPumps::instance().obtain("source").post("received");
+        // Now wait for the coroutine to complete.
+        ensure_done(coro);
+        // ensure the coroutine ran and woke up again with the intended result
+        ensure_equals(result.asString(), "received");
+    }
+
+    template<> template<>
+    void object::test<3>()
+    {
+        set_test_name("waitForEventOn1");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn1, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain("source").post("received");
+        debug("back from send");
+        ensure_done(coro);
+        ensure_equals(result.asString(), "received");
+    }
+
+    template<> template<>
+    void object::test<4>()
+    {
+        set_test_name("waitForEventOn2 reply");
+        {
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain("reply").post("received");
+        debug("back from send");
+        ensure_done(coro);
+        }
+        ensure_equals(result.asString(), "received");
+        ensure_equals("which pump", which, 0);
+    }
+
+    template<> template<>
+    void object::test<5>()
+    {
+        set_test_name("waitForEventOn2 error");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain("error").post("badness");
+        debug("back from send");
+        ensure_done(coro);
+        ensure_equals(result.asString(), "badness");
+        ensure_equals("which pump", which, 1);
+    }
+
+    template<> template<>
+    void object::test<6>()
+    {
+        set_test_name("coroPump");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPump, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain(replyName).post("received");
+        debug("back from send");
+        ensure_done(coro);
+        ensure_equals(result.asString(), "received");
+    }
+
+    template<> template<>
+    void object::test<7>()
+    {
+        set_test_name("coroPumps reply");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain(replyName).post("received");
+        debug("back from send");
+        ensure_done(coro);
+        ensure_equals(result.asString(), "received");
+        ensure_equals("which pump", which, 0);
+    }
+
+    template<> template<>
+    void object::test<8>()
+    {
+        set_test_name("coroPumps error");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain(errorName).post("badness");
+        debug("back from send");
+        ensure_done(coro);
+        ensure_equals(result.asString(), "badness");
+        ensure_equals("which pump", which, 1);
+    }
+
+    template<> template<>
+    void object::test<9>()
+    {
+        set_test_name("coroPumpsNoEx");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoEx, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain(replyName).post("received");
+        debug("back from send");
+        ensure_done(coro);
+        ensure_equals(result.asString(), "received");
+    }
+
+    template<> template<>
+    void object::test<10>()
+    {
+        set_test_name("coroPumpsEx");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsEx, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain(errorName).post("badness");
+        debug("back from send");
+        ensure_done(coro);
+        ensure("no result", result.isUndefined());
+        ensure_equals("got error", errordata.asString(), "badness");
+    }
+
+    template<> template<>
+    void object::test<11>()
+    {
+        set_test_name("coroPumpsNoLog");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoLog, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain(replyName).post("received");
+        debug("back from send");
+        ensure_done(coro);
+        ensure_equals(result.asString(), "received");
+    }
+
+    template<> template<>
+    void object::test<12>()
+    {
+        set_test_name("coroPumpsLog");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsLog, this, _1));
+        coro(std::nothrow);
+        debug("about to send");
+        LLEventPumps::instance().obtain(errorName).post("badness");
+        debug("back from send");
+        ensure_done(coro);
+        ensure("no result", result.isUndefined());
+        ensure_contains("got error", threw, "badness");
+    }
+
+    template<> template<>
+    void object::test<13>()
+    {
+        set_test_name("postAndWait1");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::postAndWait1, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 18);
+    }
+
+    template<> template<>
+    void object::test<14>()
+    {
+        set_test_name("postAndWait2");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::postAndWait2, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 19);
+        ensure_equals(which, 0);
+    }
+
+    template<> template<>
+    void object::test<15>()
+    {
+        set_test_name("postAndWait2_1");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::postAndWait2_1, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 19);
+        ensure_equals(which, 1);
+    }
+
+    template<> template<>
+    void object::test<16>()
+    {
+        set_test_name("coroPumpPost");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpPost, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 18);
+    }
+
+    template<> template<>
+    void object::test<17>()
+    {
+        set_test_name("coroPumpsPost reply");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 24);
+        ensure_equals("which pump", which, 0);
+    }
+
+    template<> template<>
+    void object::test<18>()
+    {
+        set_test_name("coroPumpsPost error");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost_1, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 24);
+        ensure_equals("which pump", which, 1);
+    }
+
+    template<> template<>
+    void object::test<19>()
+    {
+        set_test_name("coroPumpsPostNoEx");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoEx, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 9);
+    }
+
+    template<> template<>
+    void object::test<20>()
+    {
+        set_test_name("coroPumpsPostEx");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostEx, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure("no result", result.isUndefined());
+        ensure_equals("got error", errordata.asInteger(), 10);
+    }
+
+    template<> template<>
+    void object::test<21>()
+    {
+        set_test_name("coroPumpsPostNoLog");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoLog, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure_equals(result.asInteger(), 31);
+    }
+
+    template<> template<>
+    void object::test<22>()
+    {
+        set_test_name("coroPumpsPostLog");
+        DEBUG;
+        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostLog, this, _1));
+        coro(std::nothrow);
+        ensure_done(coro);
+        ensure("no result", result.isUndefined());
+        ensure_contains("got error", threw, "32");
+    }
+} // namespace tut
diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..28b909298e1979ccd9c554c5ba31592aebae4cdc
--- /dev/null
+++ b/indra/llcommon/tests/lleventfilter_test.cpp
@@ -0,0 +1,276 @@
+/**
+ * @file   lleventfilter_test.cpp
+ * @author Nat Goodspeed
+ * @date   2009-03-06
+ * @brief  Test for lleventfilter.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventfilter.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "stringize.h"
+#include "listener.h"
+#include "tests/wrapllerrs.h"
+
+/*****************************************************************************
+*   Test classes
+*****************************************************************************/
+// Strictly speaking, we're testing LLEventTimeoutBase rather than the
+// production LLEventTimeout (using LLTimer) because we don't want every test
+// run to pause for some number of seconds until we reach a real timeout. But
+// as we've carefully put all functionality except actual LLTimer calls into
+// LLEventTimeoutBase, that should suffice. We're not not not trying to test
+// LLTimer here.
+class TestEventTimeout: public LLEventTimeoutBase
+{
+public:
+    TestEventTimeout():
+        mElapsed(true)
+    {}
+    TestEventTimeout(LLEventPump& source):
+        LLEventTimeoutBase(source),
+        mElapsed(true)
+    {}
+
+    // test hook
+    void forceTimeout(bool timeout=true) { mElapsed = timeout; }
+
+protected:
+    virtual void setCountdown(F32 seconds) { mElapsed = false; }
+    virtual bool countdownElapsed() const { return mElapsed; }
+
+private:
+    bool mElapsed;
+};
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct filter_data
+    {
+        // The resemblance between this test data and that in llevents_tut.cpp
+        // is not coincidental.
+        filter_data():
+            pumps(LLEventPumps::instance()),
+            mainloop(pumps.obtain("mainloop")),
+            listener0("first"),
+            listener1("second")
+        {}
+        LLEventPumps& pumps;
+        LLEventPump& mainloop;
+        Listener listener0;
+        Listener listener1;
+
+        void check_listener(const std::string& desc, const Listener& listener, const LLSD& got)
+        {
+            ensure_equals(STRINGIZE(listener << ' ' << desc),
+                          listener.getLastEvent(), got);
+        }
+    };
+    typedef test_group<filter_data> filter_group;
+    typedef filter_group::object filter_object;
+    filter_group filtergrp("lleventfilter");
+
+    template<> template<>
+    void filter_object::test<1>()
+    {
+        set_test_name("LLEventMatching");
+        LLEventPump& driver(pumps.obtain("driver"));
+        listener0.reset(0);
+        // Listener isn't derived from LLEventTrackable specifically to test
+        // various connection-management mechanisms. But that means we have a
+        // couple of transient Listener objects, one of which is listening to
+        // a persistent LLEventPump. Capture those connections in local
+        // LLTempBoundListener instances so they'll disconnect
+        // on destruction.
+        LLTempBoundListener temp1(
+            listener0.listenTo(driver));
+        // Construct a pattern LLSD: desired Event must have a key "foo"
+        // containing string "bar"
+        LLEventMatching filter(driver, LLSD().insert("foo", "bar"));
+        listener1.reset(0);
+        LLTempBoundListener temp2(
+            listener1.listenTo(filter));
+        driver.post(1);
+        check_listener("direct", listener0, LLSD(1));
+        check_listener("filtered", listener1, LLSD(0));
+        // Okay, construct an LLSD map matching the pattern
+        LLSD data;
+        data["foo"] = "bar";
+        data["random"] = 17;
+        driver.post(data);
+        check_listener("direct", listener0, data);
+        check_listener("filtered", listener1, data);
+    }
+
+    template<> template<>
+    void filter_object::test<2>()
+    {
+        set_test_name("LLEventTimeout::actionAfter()");
+        LLEventPump& driver(pumps.obtain("driver"));
+        TestEventTimeout filter(driver);
+        listener0.reset(0);
+        LLTempBoundListener temp1(
+            listener0.listenTo(filter));
+        // Use listener1.call() as the Action for actionAfter(), since it
+        // already provides a way to sense the call
+        listener1.reset(0);
+        // driver --> filter --> listener0
+        filter.actionAfter(20,
+                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+        // Okay, (fake) timer is ticking. 'filter' can only sense the timer
+        // when we pump mainloop. Do that right now to take the logic path
+        // before either the anticipated event arrives or the timer expires.
+        mainloop.post(17);
+        check_listener("no timeout 1", listener1, LLSD(0));
+        // Expected event arrives...
+        driver.post(1);
+        check_listener("event passed thru", listener0, LLSD(1));
+        // Should have canceled the timer. Verify that by asserting that the
+        // time has expired, then pumping mainloop again.
+        filter.forceTimeout();
+        mainloop.post(17);
+        check_listener("no timeout 2", listener1, LLSD(0));
+        // Verify chained actionAfter() calls, that is, that a second
+        // actionAfter() resets the timer established by the first
+        // actionAfter().
+        filter.actionAfter(20,
+                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+        // Since our TestEventTimeout class isn't actually manipulating time
+        // (quantities of seconds), only a bool "elapsed" flag, sense that by
+        // forcing the flag between actionAfter() calls.
+        filter.forceTimeout();
+        // Pumping mainloop here would result in a timeout (as we'll verify
+        // below). This state simulates a ticking timer that has not yet timed
+        // out. But now, before a mainloop event lets 'filter' recognize
+        // timeout on the previous actionAfter() call, pretend we're pushing
+        // that timeout farther into the future.
+        filter.actionAfter(20,
+                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+        // Look ma, no timeout!
+        mainloop.post(17);
+        check_listener("no timeout 3", listener1, LLSD(0));
+        // Now let the updated actionAfter() timer expire.
+        filter.forceTimeout();
+        // Notice the timeout.
+        mainloop.post(17);
+        check_listener("timeout", listener1, LLSD("timeout"));
+        // Timing out cancels the timer. Verify that.
+        listener1.reset(0);
+        filter.forceTimeout();
+        mainloop.post(17);
+        check_listener("no timeout 4", listener1, LLSD(0));
+        // Reset the timer and then cancel() it.
+        filter.actionAfter(20,
+                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+        // neither expired nor satisified
+        mainloop.post(17);
+        check_listener("no timeout 5", listener1, LLSD(0));
+        // cancel
+        filter.cancel();
+        // timeout!
+        filter.forceTimeout();
+        mainloop.post(17);
+        check_listener("no timeout 6", listener1, LLSD(0));
+    }
+
+    template<> template<>
+    void filter_object::test<3>()
+    {
+        set_test_name("LLEventTimeout::eventAfter()");
+        LLEventPump& driver(pumps.obtain("driver"));
+        TestEventTimeout filter(driver);
+        listener0.reset(0);
+        LLTempBoundListener temp1(
+            listener0.listenTo(filter));
+        filter.eventAfter(20, LLSD("timeout"));
+        // Okay, (fake) timer is ticking. 'filter' can only sense the timer
+        // when we pump mainloop. Do that right now to take the logic path
+        // before either the anticipated event arrives or the timer expires.
+        mainloop.post(17);
+        check_listener("no timeout 1", listener0, LLSD(0));
+        // Expected event arrives...
+        driver.post(1);
+        check_listener("event passed thru", listener0, LLSD(1));
+        // Should have canceled the timer. Verify that by asserting that the
+        // time has expired, then pumping mainloop again.
+        filter.forceTimeout();
+        mainloop.post(17);
+        check_listener("no timeout 2", listener0, LLSD(1));
+        // Set timer again.
+        filter.eventAfter(20, LLSD("timeout"));
+        // Now let the timer expire.
+        filter.forceTimeout();
+        // Notice the timeout.
+        mainloop.post(17);
+        check_listener("timeout", listener0, LLSD("timeout"));
+        // Timing out cancels the timer. Verify that.
+        listener0.reset(0);
+        filter.forceTimeout();
+        mainloop.post(17);
+        check_listener("no timeout 3", listener0, LLSD(0));
+    }
+
+    template<> template<>
+    void filter_object::test<4>()
+    {
+        set_test_name("LLEventTimeout::errorAfter()");
+        WrapLL_ERRS capture;
+        LLEventPump& driver(pumps.obtain("driver"));
+        TestEventTimeout filter(driver);
+        listener0.reset(0);
+        LLTempBoundListener temp1(
+            listener0.listenTo(filter));
+        filter.errorAfter(20, "timeout");
+        // Okay, (fake) timer is ticking. 'filter' can only sense the timer
+        // when we pump mainloop. Do that right now to take the logic path
+        // before either the anticipated event arrives or the timer expires.
+        mainloop.post(17);
+        check_listener("no timeout 1", listener0, LLSD(0));
+        // Expected event arrives...
+        driver.post(1);
+        check_listener("event passed thru", listener0, LLSD(1));
+        // Should have canceled the timer. Verify that by asserting that the
+        // time has expired, then pumping mainloop again.
+        filter.forceTimeout();
+        mainloop.post(17);
+        check_listener("no timeout 2", listener0, LLSD(1));
+        // Set timer again.
+        filter.errorAfter(20, "timeout");
+        // Now let the timer expire.
+        filter.forceTimeout();
+        // Notice the timeout.
+        std::string threw;
+        try
+        {
+            mainloop.post(17);
+        }
+        catch (const WrapLL_ERRS::FatalException& e)
+        {
+            threw = e.what();
+        }
+        ensure_contains("errorAfter() timeout exception", threw, "timeout");
+        // Timing out cancels the timer. Verify that.
+        listener0.reset(0);
+        filter.forceTimeout();
+        mainloop.post(17);
+        check_listener("no timeout 3", listener0, LLSD(0));
+    }
+} // namespace tut
+
+/*****************************************************************************
+*   Link dependencies
+*****************************************************************************/
+#include "llsdutil.cpp"
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index f13c69f1e3d67618c9ef8b55fd27084ad056cb9c..6ab48ec34ae2251d7769920e89d78bec53850a5a 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -48,6 +48,18 @@
 typedef U32 uint32_t;
 #endif
 
+std::vector<U8> string_to_vector(std::string str)
+{
+	// bc LLSD can't...
+	size_t len = (size_t)str.length();
+	std::vector<U8> v(len);
+	for (size_t i = 0; i < len ; i++)
+	{
+		v[i] = str[i];
+	}
+	return v;
+}
+
 namespace tut
 {
 	struct sd_xml_data
@@ -107,7 +119,16 @@ namespace tut
 		expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n";
 		xml_test("date", expected);
 
-		// *FIX: test binary
+		// Generated by: echo -n 'hello' | openssl enc -e -base64
+		std::vector<U8> hello;
+		hello.push_back('h');
+		hello.push_back('e');
+		hello.push_back('l');
+		hello.push_back('l');
+		hello.push_back('o');
+		mSD = hello;
+		expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
+		xml_test("binary", expected);
 	}
 	
 	template<> template<>
@@ -199,6 +220,21 @@ namespace tut
 		xml_test("2 element map", expected);
 	}
 	
+	template<> template<>
+	void sd_xml_object::test<6>()
+	{
+		// tests with binary
+		std::string expected;
+
+		// Generated by: echo -n 'hello' | openssl enc -e -base64
+		mSD = string_to_vector("hello");
+		expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
+		xml_test("binary", expected);
+
+		mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
+		expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
+		xml_test("binary", expected);
+	}
 	
 	class TestLLSDSerializeData
 	{
@@ -637,6 +673,42 @@ namespace tut
 			v.size() + 1);
 	}
 
+	template<> template<> 
+	void TestLLSDXMLParsingObject::test<4>()
+	{
+		// test handling of binary object in XML
+		std::string xml;
+		LLSD expected;
+
+		// Generated by: echo -n 'hello' | openssl enc -e -base64
+		expected = string_to_vector("hello");
+		xml = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
+		ensureParse(
+			"the word 'hello' packed in binary encoded base64",
+			xml,
+			expected,
+			1);
+
+		expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
+		xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
+		ensureParse(
+			"a common binary blob for object -> agent offline inv transfer",
+			xml,
+			expected,
+			1);
+
+		expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
+		xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n";
+		xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n";
+		xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n";
+		xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n";
+		xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
+		ensureParse(
+			"a common binary blob for object -> agent offline inv transfer",
+			xml,
+			expected,
+			1);
+	}
 	/*
 	TODO:
 		test XML parsing
diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp
index 6a2ebc61f5d5fff88bcb7860c91b73f9e3aeaeae..beba55416ad50fc3b4c28a44e45f4d09f8b44b39 100644
--- a/indra/llcommon/tests/llstring_test.cpp
+++ b/indra/llcommon/tests/llstring_test.cpp
@@ -32,6 +32,7 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
 #include "../test/lltut.h"
 
 #include "../llstring.h"
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
new file mode 100644
index 0000000000000000000000000000000000000000..1001ebc466c8495db35b5f9b072d3f2f5b3af14a
--- /dev/null
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -0,0 +1,56 @@
+/**
+ * @file   wrapllerrs.h
+ * @author Nat Goodspeed
+ * @date   2009-03-11
+ * @brief  Define a class useful for unit tests that engage llerrs (LL_ERRS) functionality
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_WRAPLLERRS_H)
+#define LL_WRAPLLERRS_H
+
+#include "llerrorcontrol.h"
+
+struct WrapLL_ERRS
+{
+    WrapLL_ERRS():
+        // Resetting Settings discards the default Recorder that writes to
+        // stderr. Otherwise, expected llerrs (LL_ERRS) messages clutter the
+        // console output of successful tests, potentially confusing things.
+        mPriorErrorSettings(LLError::saveAndResetSettings()),
+        // Save shutdown function called by LL_ERRS
+        mPriorFatal(LLError::getFatalFunction())
+    {
+        // Make LL_ERRS call our own operator() method
+        LLError::setFatalFunction(boost::bind(&WrapLL_ERRS::operator(), this, _1));
+    }
+
+    ~WrapLL_ERRS()
+    {
+        LLError::setFatalFunction(mPriorFatal);
+        LLError::restoreSettings(mPriorErrorSettings);
+    }
+
+    struct FatalException: public std::runtime_error
+    {
+        FatalException(const std::string& what): std::runtime_error(what) {}
+    };
+
+    void operator()(const std::string& message)
+    {
+        // Save message for later in case consumer wants to sense the result directly
+        error = message;
+        // Also throw an appropriate exception since calling code is likely to
+        // assume that control won't continue beyond LL_ERRS.
+        throw FatalException(message);
+    }
+
+    std::string error;
+    LLError::Settings* mPriorErrorSettings;
+    LLError::FatalFunction mPriorFatal;
+};
+
+#endif /* ! defined(LL_WRAPLLERRS_H) */
diff --git a/indra/llcommon/timing.h b/indra/llcommon/timing.h
index 2b9f60adad70bc3213060fb29279447469a231a9..140ce1fcaa11de68935460eb6f74706f21f0688c 100644
--- a/indra/llcommon/timing.h
+++ b/indra/llcommon/timing.h
@@ -43,7 +43,6 @@ const F32 SEC_TO_MICROSEC = 1000000.f;
 const U64 SEC_TO_MICROSEC_U64 = 1000000;
 const U32 SEC_PER_DAY = 86400;
 
-// This is just a stub, implementation in lltimer.cpp.  This file will be deprecated in the future.
-U64 totalTime();					// Returns current system time in microseconds
+// functionality has been moved lltimer.{cpp,h}.  This file will be deprecated in the future.
 
 #endif
diff --git a/indra/llcommon/u64.h b/indra/llcommon/u64.h
index 09a6b3e18d8eedef0b18480a349073b5b43c944a..eb51131e94655d5d8b0b4fbc40d68bb8884514cd 100644
--- a/indra/llcommon/u64.h
+++ b/indra/llcommon/u64.h
@@ -39,14 +39,14 @@
  * @param str The string to parse.
  * @return Returns the first U64 value found in the string or 0 on failure.
  */
-U64 str_to_U64(const std::string& str);
+LL_COMMON_API U64 str_to_U64(const std::string& str);
 
 /**
  * @brief Given a U64 value, return a printable representation.
  * @param value The U64 to turn into a printable character array.
  * @return Returns the result string.
  */
-std::string U64_to_str(U64 value);
+LL_COMMON_API std::string U64_to_str(U64 value);
 
 /**
  * @brief Given a U64 value, return a printable representation.
@@ -65,16 +65,16 @@ std::string U64_to_str(U64 value);
  * @param result_size The size of the buffer allocated. Use U64_BUF.
  * @return Returns the result pointer.
  */
-char* U64_to_str(U64 value, char* result, S32 result_size);
+LL_COMMON_API char* U64_to_str(U64 value, char* result, S32 result_size);
 
 /**
  * @brief Convert a U64 to the closest F64 value.
  */
-F64 U64_to_F64(const U64 value);
+LL_COMMON_API F64 U64_to_F64(const U64 value);
 
 /**
  * @brief Helper function to wrap strtoull() which is not available on windows.
  */
-U64 llstrtou64(const char* str, char** end, S32 base);
+LL_COMMON_API U64 llstrtou64(const char* str, char** end, S32 base);
 
 #endif
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 363486fb9c013caa8e9ec4141c412638171e9188..2352c8edd725112b80c12cd7937d9ed538ef4dd6 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -178,8 +178,8 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),
 							mMaxBytes(0),
 							mRawDiscardLevel(-1),
 							mRate(0.0f),
-							mReversible(FALSE)
-	
+							mReversible(FALSE),
+							mAreaUsedForDataSizeCalcs(0)
 {
 	//We assume here that if we wanted to create via
 	//a dynamic library that the approriate open calls were made
@@ -195,6 +195,12 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),
 	}
 
 	mImpl = j2cimpl_create_func();
+
+	// Clear data size table
+	for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++)
+	{	// Array size is MAX_DISCARD_LEVEL+1
+		mDataSizes[i] = 0;
+	}
 }
 
 // virtual
@@ -367,9 +373,45 @@ S32 LLImageJ2C::calcHeaderSize()
 	return calcHeaderSizeJ2C();
 }
 
+
+// calcDataSize() returns how many bytes to read 
+// to load discard_level (including header and higher discard levels)
 S32 LLImageJ2C::calcDataSize(S32 discard_level)
 {
-	return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate);
+	discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL);
+
+	if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth()) 
+		|| mDataSizes[0] == 0)
+	{
+		mAreaUsedForDataSizeCalcs = getHeight() * getWidth();
+		
+		S32 level = MAX_DISCARD_LEVEL;	// Start at the highest discard
+		while ( level >= 0 )
+		{
+			mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate);
+			level--;
+		}
+
+		/* This is technically a more correct way to calculate the size required
+		   for each discard level, since they should include the size needed for
+		   lower levels.   Unfortunately, this doesn't work well and will lead to 
+		   download stalls.  The true correct way is to parse the header.  This will
+		   all go away with http textures at some point.
+
+		// Calculate the size for each discard level.   Lower levels (higher quality)
+		// contain the cumulative size of higher levels		
+		S32 total_size = calcHeaderSizeJ2C();
+
+		S32 level = MAX_DISCARD_LEVEL;	// Start at the highest discard
+		while ( level >= 0 )
+		{	// Add in this discard level and all before it
+			total_size += calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate);
+			mDataSizes[level] = total_size;
+			level--;
+		}
+		*/
+	}
+	return mDataSizes[discard_level];
 }
 
 S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes)
diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h
index 23f6ef5fd10b8a7a82cc4283143acd990eaf51e8..55df7f44296e537ec9cf50c796a7831ed3b48a21 100644
--- a/indra/llimage/llimagej2c.h
+++ b/indra/llimage/llimagej2c.h
@@ -87,6 +87,10 @@ class LLImageJ2C : public LLImageFormatted
 	void updateRawDiscardLevel();
 
 	S32 mMaxBytes; // Maximum number of bytes of data to use...
+	
+	S32 mDataSizes[MAX_DISCARD_LEVEL+1];		// Size of data required to reach a given level
+	U32 mAreaUsedForDataSizeCalcs;				// Height * width used to calculate mDataSizes
+
 	S8  mRawDiscardLevel;
 	F32 mRate;
 	BOOL mReversible;
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index e2a77f1d1e5f4f7f14b6daf16a9a401d15546d34..5d3fbe51289192d1c33db39247376434fa9df1be 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -458,6 +458,39 @@ void LLInventoryItem::setCreationDate(time_t creation_date_utc)
 	mCreationDate = creation_date_utc;
 }
 
+void LLInventoryItem::accumulatePermissionSlamBits(const LLInventoryItem& old_item)
+{
+	// Remove any pre-existing II_FLAGS_PERM_OVERWRITE_MASK flags 
+	// because we now detect when they should be set.
+	setFlags( old_item.getFlags() | (getFlags() & ~(LLInventoryItem::II_FLAGS_PERM_OVERWRITE_MASK)) );
+
+	// Enforce the PERM_OVERWRITE flags for any masks that are different
+	// but only for AT_OBJECT's since that is the only asset type that can 
+	// exist in-world (instead of only in-inventory or in-object-contents).
+	if (LLAssetType::AT_OBJECT == getType())
+	{
+		LLPermissions old_permissions = old_item.getPermissions();
+		U32 flags_to_be_set = 0;
+		if(old_permissions.getMaskNextOwner() != getPermissions().getMaskNextOwner())
+		{
+			flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_PERM;
+		}
+		if(old_permissions.getMaskEveryone() != getPermissions().getMaskEveryone())
+		{
+			flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
+		}
+		if(old_permissions.getMaskGroup() != getPermissions().getMaskGroup())
+		{
+			flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
+		}
+		LLSaleInfo old_sale_info = old_item.getSaleInfo();
+		if(old_sale_info != getSaleInfo())
+		{
+			flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_SALE;
+		}
+		setFlags(getFlags() | flags_to_be_set);
+	}
+}
 
 const LLSaleInfo& LLInventoryItem::getSaleInfo() const
 {
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 64af6c94f5dd996cbd368b4313e0bd293fd2785d..bd581e860f3a230dd919f9836e3d402c3c8aaf0b 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -93,7 +93,6 @@ class LLInventoryObject : public LLRefCount
 	virtual const LLUUID& getUUID() const;
 	const LLUUID& getParentUUID() const;
 	virtual const LLUUID& getLinkedUUID() const; // get the inventoryID that this item points to, else this item's inventoryID
-
 	virtual const std::string& getName() const;
 	virtual LLAssetType::EType getType() const;
 	LLAssetType::EType getActualType() const; // bypasses indirection for linked items
@@ -263,6 +262,10 @@ class LLInventoryItem : public LLInventoryObject
 	void setInventoryType(LLInventoryType::EType inv_type);
 	void setFlags(U32 flags);
 	void setCreationDate(time_t creation_date_utc);
+
+	// Check for changes in permissions masks and sale info
+	// and set the corresponding bits in mFlags
+	void accumulatePermissionSlamBits(const LLInventoryItem& old_item);
 	
 	// This is currently only used in the Viewer to handle calling cards
 	// where the creator is actually used to store the target.
diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp
index f208d82084c632ca55f03ba3d291556b865618cf..ec21ae40e732d7499bab1ffa82982e9446ba4afa 100644
--- a/indra/llinventory/llparcel.cpp
+++ b/indra/llinventory/llparcel.cpp
@@ -43,7 +43,7 @@
 #include "llsdutil.h"
 #include "lltransactiontypes.h"
 #include "lltransactionflags.h"
-#include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "message.h"
 #include "u64.h"
 
diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h
index aa8391230c30b72cc3bd5b85360e6224355de8c1..2a9a596912fce7403ab1da61cc7590f8128ccaa2 100644
--- a/indra/llinventory/llparcel.h
+++ b/indra/llinventory/llparcel.h
@@ -136,9 +136,9 @@ class LLSD;
 class LLAccessEntry
 {
 public:
-	LLUUID		mID;
-	S32			mTime;
-	U32			mFlags;
+	LLUUID		mID;		// Agent ID
+	S32			mTime;		// Time (unix seconds) when entry expires
+	U32			mFlags;		// Not used - currently should always be zero
 };
 
 typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator;
diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp
index 0babf26457e91ee463ae662697d5c4aea7b3380f..d2e503473401a6063679c4ea0dfff1ecac5040ed 100644
--- a/indra/llinventory/llpermissions.cpp
+++ b/indra/llinventory/llpermissions.cpp
@@ -288,6 +288,17 @@ BOOL LLPermissions::setOwnerAndGroup(
 	return allowed;
 }
 
+//Fix for DEV-33917, last owner isn't used much and has little impact on
+//permissions so it's reasonably safe to do this, however, for now, 
+//limiting the functionality of this routine to objects which are 
+//group owned.
+void LLPermissions::setLastOwner(const LLUUID& last_owner)
+{
+	if (isGroupOwned())
+		mLastOwner = last_owner;
+}
+
+ 
 // only call this if you know what you're doing
 // there are usually perm-bit consequences when the 
 // ownerhsip changes
@@ -895,6 +906,8 @@ void LLMetaClassT<LLPermissions>::reflectProperties(LLMetaClass& meta_class)
 {
 	reflectProperty(meta_class, "mCreator", &LLPermissions::mCreator);
 	reflectProperty(meta_class, "mOwner", &LLPermissions::mOwner);
+	reflectProperty(meta_class, "mGroup", &LLPermissions::mGroup);
+	reflectProperty(meta_class, "mIsGroupOwned", &LLPermissions::mIsGroupOwned);
 }
 
 // virtual
diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h
index 864088148f58ccb64f3582dacc75c262324bb53e..d5a0881c8f2ab684ed52f526c3e29dc26c3154de 100644
--- a/indra/llinventory/llpermissions.h
+++ b/indra/llinventory/llpermissions.h
@@ -232,6 +232,10 @@ class LLPermissions : public LLReflective
 	// ownerhsip changes
 	void yesReallySetOwner(const LLUUID& owner, bool group_owned);
 
+	// Last owner doesn't have much in the way of permissions so it's 
+	//not too dangerous to do this. 
+	void setLastOwner(const LLUUID& last_owner);
+
 	// saves last owner, sets owner to uuid null, sets group
 	// owned. group_id must be the group of the object (that's who it
 	// is being deeded to) and the object must be group
diff --git a/indra/llinventory/lltransactiontypes.h b/indra/llinventory/lltransactiontypes.h
index 1cb7308bd417fbcfd473e5b65385359df6753719..2c699bcb87cb7761882b5435b2c1b78c8ee7b93a 100644
--- a/indra/llinventory/lltransactiontypes.h
+++ b/indra/llinventory/lltransactiontypes.h
@@ -69,6 +69,12 @@ const S32 TRANS_PARCEL_DIR_FEE		= 2003;
 const S32 TRANS_GROUP_TAX		    = 2004; // Taxes incurred as part of group membership
 const S32 TRANS_CLASSIFIED_RENEW	= 2005;
 
+// Codes 2100-2999 reserved for recurring billing services
+// New codes can be created through an admin interface so may not
+// automatically end up in the list below :-(
+// So make sure you check the transaction_description table
+const S32 TRANS_RECURRING_GENERIC  = 2100;
+
 // Codes 3000-3999 reserved for inventory transactions
 const S32 TRANS_GIVE_INVENTORY		= 3000;
 
@@ -84,6 +90,12 @@ const S32 TRANS_DWELL_BONUS			= 5007;
 const S32 TRANS_PAY_OBJECT			= 5008;
 const S32 TRANS_OBJECT_PAYS			= 5009;
 
+// Codes 5100-5999 reserved for recurring billing transfers between users
+// New codes can be created through an admin interface so may not
+// automatically end up in the list below :-(
+// So make sure you check the transaction_description table
+const S32 TRANS_RECURRING_GENERIC_USER  = 5100;
+
 // Codes 6000-6999 reserved for group transactions
 //const S32 TRANS_GROUP_JOIN		    = 6000;  //reserved for future use
 const S32 TRANS_GROUP_LAND_DEED		= 6001;
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index 9006a8a284ee5986dec86eac281815a7491cc76f..7957c32be2c05288ca725b95689c1deec5aa9f6a 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -64,6 +64,7 @@ set(llmath_HEADER_FILES
     llv4vector3.h
     llvolume.h
     llvolumemgr.h
+    llsdutil_math.h
     m3math.h
     m4math.h
     raytrace.h
diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp
index acf93a2a38fc2e0efbc2cb144af5bece154362ab..914cbfdc124fe2b0b74c6f96388481d3795c0978 100644
--- a/indra/llmath/llbbox.cpp
+++ b/indra/llmath/llbbox.cpp
@@ -30,6 +30,8 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
+
 // self include
 #include "llbbox.h"
 
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index f85c4f39f412d625fa5358635a4b6cf259192d30..7a5d51ff768609bf384029c81ea69a94424f8aeb 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -35,6 +35,7 @@
 
 #include <cmath>
 #include <cstdlib>
+#include <complex>
 #include "lldefs.h"
 //#include "llstl.h" // *TODO: Remove when LLString is gone
 //#include "llstring.h" // *TODO: Remove when LLString is gone
diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp
index cfd6183ec44cc3f118b16647b028fded6b811b9e..fdcc19d657b6ee0144121cdbd411fc82b22b6513 100644
--- a/indra/llmath/llquaternion.cpp
+++ b/indra/llmath/llquaternion.cpp
@@ -121,7 +121,7 @@ void	LLQuaternion::quantize16(F32 lower, F32 upper)
 	mQ[VZ] = z;
 	mQ[VS] = s;
 
-	normQuat();
+	normalize();
 }
 
 void	LLQuaternion::quantize8(F32 lower, F32 upper)
@@ -131,7 +131,7 @@ void	LLQuaternion::quantize8(F32 lower, F32 upper)
 	mQ[VZ] = U8_to_F32(F32_to_U8_ROUND(mQ[VZ], lower, upper), lower, upper);
 	mQ[VS] = U8_to_F32(F32_to_U8_ROUND(mQ[VS], lower, upper), lower, upper);
 
-	normQuat();
+	normalize();
 }
 
 // LLVector3 Magnitude and Normalization Functions
@@ -346,7 +346,7 @@ const LLQuaternion&	LLQuaternion::setQuat(const LLMatrix4 &mat)
 //    mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ);
 //#endif
 //
-//	normQuat();
+//	normalize();
 //	return (*this);
 }
 
diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h
index 5db9c5be2ed5167b82d85db3d1847d3fb6f5d31e..0769f29f235d747a3a36ef74d34027fcb6a659e9 100644
--- a/indra/llmath/llquaternion.h
+++ b/indra/llmath/llquaternion.h
@@ -469,20 +469,30 @@ inline const LLQuaternion&	operator*=(LLQuaternion &a, const LLQuaternion &b)
 	return a;
 }
 
+const F32 ONE_PART_IN_A_MILLION = 0.000001f;
+
 inline F32	LLQuaternion::normalize()
 {
 	F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
 
 	if (mag > FP_MAG_THRESHOLD)
 	{
-		F32 oomag = 1.f/mag;
-		mQ[VX] *= oomag;
-		mQ[VY] *= oomag;
-		mQ[VZ] *= oomag;
-		mQ[VS] *= oomag;
+		// Floating point error can prevent some quaternions from achieving
+		// exact unity length.  When trying to renormalize such quaternions we
+		// can oscillate between multiple quantized states.  To prevent such
+		// drifts we only renomalize if the length is far enough from unity.
+		if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION)
+		{
+			F32 oomag = 1.f/mag;
+			mQ[VX] *= oomag;
+			mQ[VY] *= oomag;
+			mQ[VZ] *= oomag;
+			mQ[VS] *= oomag;
+		}
 	}
 	else
 	{
+		// we were given a very bad quaternion so we set it to identity
 		mQ[VX] = 0.f;
 		mQ[VY] = 0.f;
 		mQ[VZ] = 0.f;
@@ -499,11 +509,15 @@ inline F32	LLQuaternion::normQuat()
 
 	if (mag > FP_MAG_THRESHOLD)
 	{
-		F32 oomag = 1.f/mag;
-		mQ[VX] *= oomag;
-		mQ[VY] *= oomag;
-		mQ[VZ] *= oomag;
-		mQ[VS] *= oomag;
+		if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION)
+		{
+			// only renormalize if length not close enough to 1.0 already
+			F32 oomag = 1.f/mag;
+			mQ[VX] *= oomag;
+			mQ[VY] *= oomag;
+			mQ[VZ] *= oomag;
+			mQ[VS] *= oomag;
+		}
 	}
 	else
 	{
diff --git a/indra/llmath/llsdutil_math.cpp b/indra/llmath/llsdutil_math.cpp
index c5176681cef05230597fabf5c50e338b6c18b0dd..1bd12ae5137d0ea2beeed6223f9a79576c42ee22 100644
--- a/indra/llmath/llsdutil_math.cpp
+++ b/indra/llmath/llsdutil_math.cpp
@@ -34,7 +34,7 @@
 
 #include "linden_common.h"
 
-#include "llsdutil.h"
+#include "llsdutil_math.h"
 
 #include "v3math.h"
 #include "v4math.h"
diff --git a/indra/llmath/llsdutil_math.h b/indra/llmath/llsdutil_math.h
new file mode 100644
index 0000000000000000000000000000000000000000..121f4b746a820c22efe3bf524c2849ab4358f46f
--- /dev/null
+++ b/indra/llmath/llsdutil_math.h
@@ -0,0 +1,70 @@
+/** 
+ * @file llsdutil_math.h
+ * @author Brad
+ * @date 2009-05-19
+ * @brief Utility classes, functions, etc, for using structured data with math classes.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSDUTIL_MATH_H
+#define LL_LLSDUTIL_MATH_H
+
+class LL_COMMON_API LLSD;
+
+// vector3
+class LLVector3;
+LLSD ll_sd_from_vector3(const LLVector3& vec);
+LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0);
+
+// vector4
+class LLVector4;
+LLSD ll_sd_from_vector4(const LLVector4& vec);
+LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0);
+
+// vector3d (double)
+class LLVector3d;
+LLSD ll_sd_from_vector3d(const LLVector3d& vec);
+LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0);
+
+// vector2
+class LLVector2;
+LLSD ll_sd_from_vector2(const LLVector2& vec);
+LLVector2 ll_vector2_from_sd(const LLSD& sd);
+
+// Quaternion
+class LLQuaternion;
+LLSD ll_sd_from_quaternion(const LLQuaternion& quat);
+LLQuaternion ll_quaternion_from_sd(const LLSD& sd);
+
+// color4
+class LLColor4;
+LLSD ll_sd_from_color4(const LLColor4& c);
+LLColor4 ll_color4_from_sd(const LLSD& sd);
+
+#endif // LL_LLSDUTIL_MATH_H
diff --git a/indra/llmath/tests/llbbox_test.cpp b/indra/llmath/tests/llbbox_test.cpp
index b310baf07f1b40505ea0eb4241f8b5d6ec7b0edb..3031310a5dfa7d0c4211285f4f3076f20765c79e 100644
--- a/indra/llmath/tests/llbbox_test.cpp
+++ b/indra/llmath/tests/llbbox_test.cpp
@@ -32,6 +32,8 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
+
 #include "../test/lltut.h"
 
 #include "../llbbox.h"
diff --git a/indra/llmath/tests/llbboxlocal_test.cpp b/indra/llmath/tests/llbboxlocal_test.cpp
index ae75e056d1574444d84b0cb339108bbf6f11d1c0..fb51deab4a21ca875efd698d9f2e6f4d9795d8b6 100644
--- a/indra/llmath/tests/llbboxlocal_test.cpp
+++ b/indra/llmath/tests/llbboxlocal_test.cpp
@@ -32,11 +32,10 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
 #include "../test/lltut.h"
-
 #include "../llbboxlocal.h"
 
-
 namespace tut
 {
 	struct LLBBoxLocalData
diff --git a/indra/llmath/tests/llrect_test.cpp b/indra/llmath/tests/llrect_test.cpp
index 4b39f777726226f3d47eb4c8fa0fc5cdf7bdbbec..c5e9e425bb6f3997520308d19f94268ec7a56efb 100644
--- a/indra/llmath/tests/llrect_test.cpp
+++ b/indra/llmath/tests/llrect_test.cpp
@@ -32,8 +32,8 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
 #include "../test/lltut.h"
-
 #include "../llrect.h"
 
 namespace tut
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 47fbc3ab69d28d02437072b89b847d4c5177f7ff..a611de0cda901aeee5483baf9a275091548563bc 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -3,6 +3,7 @@
 project(llmessage)
 
 include(00-Common)
+include(GoogleMock)
 include(LLAddBuildTest)
 include(LLCommon)
 include(LLMath)
@@ -22,6 +23,7 @@ include_directories(
 
 set(llmessage_SOURCE_FILES
     llares.cpp
+    llareslistener.cpp
     llassetstorage.cpp
     llblowfishcipher.cpp
     llbuffer.cpp
@@ -104,6 +106,7 @@ set(llmessage_HEADER_FILES
     CMakeLists.txt
 
     llares.h
+    llareslistener.h
     llassetstorage.h
     llblowfishcipher.h
     llbuffer.h
@@ -221,6 +224,7 @@ SET(llmessage_TEST_SOURCE_FILES
   llnamevalue.cpp
   lltrustedmessageservice.cpp
   lltemplatemessagedispatcher.cpp
+      llregionpresenceverifier.cpp
   )
 LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}")
 
@@ -231,6 +235,7 @@ set(test_libs
   ${LLVFS_LIBRARIES}
   ${LLMATH_LIBRARIES}
   ${LLCOMMON_LIBRARIES}
+      ${GOOGLEMOCK_LIBRARIES}
   )
 
 LL_ADD_INTEGRATION_TEST(
diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
index fe37fe8142c1fd6102cda912f9787ee4dae642fc..acbf51d75ca26be890928c262ffd5e39f4f5918d 100644
--- a/indra/llmessage/llares.cpp
+++ b/indra/llmessage/llares.cpp
@@ -33,6 +33,7 @@
  */
 
 #include "linden_common.h"
+#include "llares.h"
 
 #include <ares_dns.h>
 #include <ares_version.h>
@@ -42,9 +43,10 @@
 #include "apr_poll.h"
 
 #include "llapr.h"
-#include "llares.h"
+#include "llareslistener.h"
 
 #if defined(LL_WINDOWS)
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
 # define ns_c_in 1
 # define NS_HFIXEDSZ     12      /* #/bytes of fixed data in header */
 # define NS_QFIXEDSZ     4       /* #/bytes of fixed data in query */
@@ -102,7 +104,9 @@ void LLAres::QueryResponder::queryError(int code)
 }
 
 LLAres::LLAres() :
-chan_(NULL), mInitSuccess(false)
+    chan_(NULL),
+    mInitSuccess(false),
+    mListener(new LLAresListener("LLAres", this))
 {
 	if (ares_init(&chan_) != ARES_SUCCESS)
 	{
diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h
index c709a08499473b7808909934236654c7df314357..78febcd560fdb2af07c4d053b1245fb1b0d810f8 100644
--- a/indra/llmessage/llares.h
+++ b/indra/llmessage/llares.h
@@ -36,7 +36,13 @@
 #define LL_LLARES_H
 
 #ifdef LL_WINDOWS
+// ares.h is broken on windows in that it depends on types defined in ws2tcpip.h
+// we need to include them first to work around it, but the headers issue warnings
+# pragma warning(push)
+# pragma warning(disable:4996)
+# include <winsock2.h>
 # include <ws2tcpip.h>
+# pragma warning(pop)
 #endif
 
 #ifdef LL_STANDALONE
@@ -49,7 +55,10 @@
 #include "llrefcount.h"
 #include "lluri.h"
 
+#include <boost/shared_ptr.hpp>
+
 class LLQueryResponder;
+class LLAresListener;
 
 /**
  * @brief Supported DNS RR types.
@@ -444,6 +453,9 @@ class LLAres
 protected:
 	ares_channel chan_;
 	bool mInitSuccess;
+    // boost::scoped_ptr would actually fit the requirement better, but it
+    // can't handle incomplete types as boost::shared_ptr can.
+    boost::shared_ptr<LLAresListener> mListener;
 };
 	
 /**
diff --git a/indra/llmessage/llareslistener.cpp b/indra/llmessage/llareslistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a8beb8cbde350d7a414eccd7d8855903b69387bc
--- /dev/null
+++ b/indra/llmessage/llareslistener.cpp
@@ -0,0 +1,75 @@
+/**
+ * @file   llareslistener.cpp
+ * @author Nat Goodspeed
+ * @date   2009-03-18
+ * @brief  Implementation for llareslistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llareslistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llares.h"
+#include "llerror.h"
+#include "llevents.h"
+#include "llsdutil.h"
+
+LLAresListener::LLAresListener(const std::string& pumpname, LLAres* llares):
+    LLDispatchListener(pumpname, "op"),
+    mAres(llares)
+{
+    // add() every method we want to be able to invoke via this event API.
+    // Optional third parameter validates expected LLSD request structure.
+    add("rewriteURI", &LLAresListener::rewriteURI,
+        LLSD().insert("uri", LLSD()).insert("reply", LLSD()));
+}
+
+/// This UriRewriteResponder subclass packages returned URIs as an LLSD
+/// array to send back to the requester.
+class UriRewriteResponder: public LLAres::UriRewriteResponder
+{
+public:
+    /**
+     * Specify the request, containing the event pump name on which to send
+     * the reply.
+     */
+    UriRewriteResponder(const LLSD& request):
+        mReqID(request),
+        mPumpName(request["reply"])
+    {}
+
+    /// Called by base class with results. This is called in both the
+    /// success and error cases. On error, the calling logic passes the
+    /// original URI.
+    virtual void rewriteResult(const std::vector<std::string>& uris)
+    {
+        LLSD result;
+        for (std::vector<std::string>::const_iterator ui(uris.begin()), uend(uris.end());
+             ui != uend; ++ui)
+        {
+            result.append(*ui);
+        }
+        // This call knows enough to avoid trying to insert a map key into an
+        // LLSD array. It's there so that if, for any reason, we ever decide
+        // to change the response from array to map, it will Just Start Working.
+        mReqID.stamp(result);
+        LLEventPumps::instance().obtain(mPumpName).post(result);
+    }
+
+private:
+    LLReqID mReqID;
+    const std::string mPumpName;
+};
+
+void LLAresListener::rewriteURI(const LLSD& data)
+{
+    mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
+}
diff --git a/indra/llmessage/llareslistener.h b/indra/llmessage/llareslistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf093b3d3d79bfb17dadf5e98cf2ff62c695bb51
--- /dev/null
+++ b/indra/llmessage/llareslistener.h
@@ -0,0 +1,37 @@
+/**
+ * @file   llareslistener.h
+ * @author Nat Goodspeed
+ * @date   2009-03-18
+ * @brief  LLEventPump API for LLAres. This header doesn't actually define the
+ *         API; the API is defined by the pump name on which this class
+ *         listens, and by the expected content of LLSD it receives.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLARESLISTENER_H)
+#define LL_LLARESLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLAres;
+class LLSD;
+
+/// Listen on an LLEventPump with specified name for LLAres request events.
+class LLAresListener: public LLDispatchListener
+{
+public:
+    /// Specify the pump name on which to listen, and bind the LLAres instance
+    /// to use (e.g. gAres)
+    LLAresListener(const std::string& pumpname, LLAres* llares);
+
+private:
+    /// command["op"] == "rewriteURI" 
+    void rewriteURI(const LLSD& data);
+
+    LLAres* mAres;
+};
+
+#endif /* ! defined(LL_LLARESLISTENER_H) */
diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h
index 47d49076f4a28ed1b38407a5c82ffd957472a2fc..8641437d86216317cdb7ff1fd04924c9a48f0d45 100644
--- a/indra/llmessage/llcachename.h
+++ b/indra/llmessage/llcachename.h
@@ -42,9 +42,9 @@ class LLUUID;
 
 
 typedef boost::signals2::signal<void (const LLUUID& id,
-							const std::string& first_name,
-							const std::string& last_name,
-							BOOL is_group)> LLCacheNameSignal;
+                                      const std::string& first_name,
+                                      const std::string& last_name,
+                                      BOOL is_group)> LLCacheNameSignal;
 typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
 
 // Old callback with user data for compatability
@@ -100,7 +100,6 @@ class LLCacheName
 	
 	// LEGACY
 	boost::signals2::connection get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data);
-
 	// This method needs to be called from time to time to send out
 	// requests.
 	void processPending();
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index a4af8e989ba7436c067ae67105c197feb19af458..5ff41322b7b65ca2168245ca8ab7c5f12737ce62 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -131,7 +131,7 @@ void LLCurl::Responder::errorWithContent(
 // virtual
 void LLCurl::Responder::error(U32 status, const std::string& reason)
 {
-	llinfos << status << ": " << reason << llendl;
+	llinfos << mURL << " [" << status << "]: " << reason << llendl;
 }
 
 // virtual
@@ -139,6 +139,11 @@ void LLCurl::Responder::result(const LLSD& content)
 {
 }
 
+void LLCurl::Responder::setURL(const std::string& url)
+{
+	mURL = url;
+}
+
 // virtual
 void LLCurl::Responder::completedRaw(
 	U32 status,
@@ -148,7 +153,11 @@ void LLCurl::Responder::completedRaw(
 {
 	LLSD content;
 	LLBufferStream istr(channels, buffer.get());
-	LLSDSerialize::fromXML(content, istr);
+	if (!LLSDSerialize::fromXML(content, istr))
+	{
+		llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl;
+	}
+
 	completed(status, reason, content);
 }
 
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index fbd3077cbf75eddadebadb6ecb535fb7757ee8cd..0b58e7c4a59fa82538b2fa31b4fc93dbcf3a81d2 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -120,8 +120,14 @@ class LLCurl
 			// of the header can be parsed.  In the ::completed call above only the body is contained in the LLSD.
 			virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content);
 
+			// Used internally to set the url for debugging later.
+			void setURL(const std::string& url);
+
 	public: /* but not really -- don't touch this */
 		U32 mReferenceCount;
+
+	private:
+		std::string mURL;
 	};
 	typedef boost::intrusive_ptr<Responder>	ResponderPtr;
 
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 8b90a4c5cacd2ed5df432d2ca9c3e7f49847deae..12ecbb36eb8ea85862fe1e723daaa1c27ffc9bf0 100644
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -265,6 +265,11 @@ static void request(
 		}
 	}
 
+	if (responder)
+	{
+		responder->setURL(url);
+	}
+
 	req->setCallback(new LLHTTPClientURLAdaptor(responder));
 
 	if (method == LLURLRequest::HTTP_POST  &&  gMessageSystem)
diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp
index b6988224ce7356524caa73e4d37681a84a84f3bf..9d3c83f82870c2f13f2b8115dd520400b83e3aea 100644
--- a/indra/llmessage/llhttpclientadapter.cpp
+++ b/indra/llmessage/llhttpclientadapter.cpp
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llhttpclientadapter.cpp
  * @brief 
  *
  * $LicenseInfo:firstyear=2009&license=viewergpl$
diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h
index 7f76390d0c59d9a2ff2cb43966867f407ff3a86d..a205a2f260e122faa8a636e90f88c7d5ccb86233 100644
--- a/indra/llmessage/llhttpclientadapter.h
+++ b/indra/llmessage/llhttpclientadapter.h
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llhttpclientadepter.h
  * @brief 
  *
  * $LicenseInfo:firstyear=2008&license=viewergpl$
diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h
index 42a8e5cd0a9bac2068c71a12ca73569c33f949f7..085a59cf2776816ff67ed8dfe766b188eba71ecd 100644
--- a/indra/llmessage/llhttpclientinterface.h
+++ b/indra/llmessage/llhttpclientinterface.h
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llhttpclientinterface.h
  * @brief 
  *
  * $LicenseInfo:firstyear=2008&license=viewergpl$
diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp
index 7c636250040c2ef54fef28556591a8c81d8fcf7e..3da41939fae047184f0ae872779690b207e4e2fa 100644
--- a/indra/llmessage/llinstantmessage.cpp
+++ b/indra/llmessage/llinstantmessage.cpp
@@ -40,7 +40,7 @@
 #include "lluuid.h"
 #include "llsd.h"
 #include "llsdserialize.h"
-#include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "llpointer.h"
 #include "message.h"
 
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index a00dbd180906235cf13f3fd688b2b9ed54c99815..97134bd336c45938f464646dacf36b4025728e78 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -521,7 +521,7 @@ class LLHTTPResponder : public LLIOPipe
 	 * seek orfor string assignment.
 	 * @returns Returns true if a line was found.
 	 */
-	bool readLine(
+	bool readHeaderLine(
 		const LLChannelDescriptors& channels,
 		buffer_ptr_t buffer,
 		U8* dest,
@@ -592,7 +592,7 @@ LLHTTPResponder::~LLHTTPResponder()
 	//lldebugs << "destroying LLHTTPResponder" << llendl;
 }
 
-bool LLHTTPResponder::readLine(
+bool LLHTTPResponder::readHeaderLine(
 	const LLChannelDescriptors& channels,
 	buffer_ptr_t buffer,
 	U8* dest,
@@ -670,7 +670,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
 #endif
 		
 		PUMP_DEBUG;
-		if(readLine(channels, buffer, (U8*)buf, len))
+		if(readHeaderLine(channels, buffer, (U8*)buf, len))
 		{
 			bool read_next_line = false;
 			bool parse_all = true;
@@ -734,7 +734,13 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
 					if(read_next_line)
 					{
 						len = HEADER_BUFFER_SIZE;	
-						readLine(channels, buffer, (U8*)buf, len);
+						if (!readHeaderLine(channels, buffer, (U8*)buf, len))
+						{
+							// Failed to read the header line, probably too long.
+							// readHeaderLine already marked the channel/buffer as bad.
+							keep_parsing = false;
+							break;
+						}
 					}
 					if(0 == len)
 					{
diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp
index d52ff6c7e8bbc0eb063a38131c24f6b04d88ac99..ce206d8d7d17bb7ffdefb4d861db5ea433f1d831 100644
--- a/indra/llmessage/llmail.cpp
+++ b/indra/llmessage/llmail.cpp
@@ -265,7 +265,7 @@ std::string LLMail::buildSMTPTransaction(
 // static
 bool LLMail::send(
 	const std::string& header,
-	const std::string& message,
+	const std::string& raw_message,
 	const char* from_address,
 	const char* to_address)
 {
@@ -276,8 +276,20 @@ bool LLMail::send(
 		return false;
 	}
 
-	// *FIX: this translation doesn't deal with a single period on a
-	// line by itself.
+	// remove any "." SMTP commands to prevent injection (DEV-35777)
+	// we don't need to worry about "\r\n.\r\n" because of the 
+	// "\n" --> "\n\n" conversion going into rfc2822_msg below
+	std::string message = raw_message;
+	std::string bad_string = "\n.\n";
+	std::string good_string = "\n..\n";
+	while (1)
+	{
+		int index = message.find(bad_string);
+		if (index == std::string::npos) break;
+		message.replace(index, bad_string.size(), good_string);
+	}
+
+	// convert all "\n" into "\r\n"
 	std::ostringstream rfc2822_msg;
 	for(U32 i = 0; i < message.size(); ++i)
 	{
diff --git a/indra/llmessage/llmessagesenderinterface.h b/indra/llmessage/llmessagesenderinterface.h
index 119eb1d7f73f2013e01af8ea9b711b6a7a9bbb7c..af6733fa05acecb377a6ac5787c4c318a5ea521e 100644
--- a/indra/llmessage/llmessagesenderinterface.h
+++ b/indra/llmessage/llmessagesenderinterface.h
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llmessagesenderinterface.h
  * @brief 
  *
  * $LicenseInfo:firstyear=2008&license=viewergpl$
diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp
index 485bc6aa4468a921eda5a003911fbab17efc1227..9376cde7b50f6212e75d579779782f32771ac841 100644
--- a/indra/llmessage/llpartdata.cpp
+++ b/indra/llmessage/llpartdata.cpp
@@ -39,6 +39,8 @@
 #include "v4coloru.h"
 
 #include "llsdutil.h"
+#include "llsdutil_math.h"
+
 
 
 const S32 PS_PART_DATA_BLOCK_SIZE = 4 + 2 + 4 + 4 + 2 + 2; // 18
diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp
index 0527d5cb8debff456cbf674598a5a22a0fe944b0..b1868e6a00f3d355028f3b65291c8bc2912046de 100644
--- a/indra/llmessage/llregionpresenceverifier.cpp
+++ b/indra/llmessage/llregionpresenceverifier.cpp
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llregionpresenceverifier.cpp
  * @brief 
  *
  * $LicenseInfo:firstyear=2008&license=viewergpl$
@@ -30,17 +30,48 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
+
 #include "llregionpresenceverifier.h"
 #include "llhttpclientinterface.h"
 #include <sstream>
 #include "net.h"
 #include "message.h"
 
+namespace boost
+{
+	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p)
+	{
+		++p->mReferenceCount;
+	}
+	
+	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p)
+	{
+		if(p && 0 == --p->mReferenceCount)
+		{
+			delete p;
+		}
+	}
+};
 
-LLRegionPresenceVerifier::RegionResponder::RegionResponder(ResponsePtr data) : mSharedData(data)
+LLRegionPresenceVerifier::Response::~Response()
 {
 }
 
+LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string&
+														   uri,
+														   ResponsePtr data,
+														   S32 retry_count) :
+	mUri(uri),
+	mSharedData(data),
+	mRetryCount(retry_count)
+{
+}
+
+//virtual
+LLRegionPresenceVerifier::RegionResponder::~RegionResponder()
+{
+}
 
 void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content)
 {
@@ -49,30 +80,36 @@ void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content)
 	LLHost destination(host, port);
 	LLUUID id = content["region_id"];
 
-	llinfos << "Verifying " << destination.getString() << " is region " << id << llendl;
+	lldebugs << "Verifying " << destination.getString() << " is region " << id << llendl;
 
 	std::stringstream uri;
 	uri << "http://" << destination.getString() << "/state/basic/";
-	mSharedData->getHttpClient().get(uri.str(), new VerifiedDestinationResponder(mSharedData, content));
+	mSharedData->getHttpClient().get(
+		uri.str(),
+		new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount));
 }
 
-void LLRegionPresenceVerifier::RegionResponder::completed(
-	U32 status,
-	const std::string& reason,
-	const LLSD& content)
+void LLRegionPresenceVerifier::RegionResponder::error(U32 status,
+													 const std::string& reason)
 {
-	LLHTTPClient::Responder::completed(status, reason, content);
-	
-	mSharedData->onCompletedRegionRequest();
+	// TODO: babbage: distinguish between region presence service and
+	// region verification errors?
+	mSharedData->onRegionVerificationFailed();
 }
 
-
-LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(ResponsePtr data, const LLSD& content) : mSharedData(data), mContent(content)
+LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content,
+	S32 retry_count):
+	mUri(uri),
+	mSharedData(data),
+	mContent(content),
+	mRetryCount(retry_count) 
 {
 }
 
-
-
+//virtual
+LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder()
+{
+}
 
 void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content)
 {
@@ -87,13 +124,14 @@ void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD&
 	{
 		mSharedData->onRegionVerified(mContent);
 	}
-	else if (mSharedData->shouldRetry())
+	else if (mRetryCount > 0)
 	{
 		retry();
 	}
 	else
 	{
-		llwarns << "Could not correctly look up region from region presence service. Region: " << mSharedData->getRegionUri() << llendl;
+		llwarns << "Simulator verification failed. Region: " << mUri << llendl;
+		mSharedData->onRegionVerificationFailed();
 	}
 }
 
@@ -101,13 +139,21 @@ void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry()
 {
 	LLSD headers;
 	headers["Cache-Control"] = "no-cache, max-age=0";
-	llinfos << "Requesting region information, get uncached for region " << mSharedData->getRegionUri() << llendl;
-	mSharedData->decrementRetries();
-	mSharedData->getHttpClient().get(mSharedData->getRegionUri(), new RegionResponder(mSharedData), headers);
+	llinfos << "Requesting region information, get uncached for region "
+			<< mUri << llendl;
+	--mRetryCount;
+	mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers);
 }
 
 void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason)
 {
-	retry();
+	if(mRetryCount > 0)
+	{
+		retry();
+	}
+	else
+	{
+		llwarns << "Failed to contact simulator for verification. Region: " << mUri << llendl;
+		mSharedData->onRegionVerificationFailed();
+	}
 }
-
diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h
index 54ad6226d645cbe7c4aed403aec028367b504504..f57a62a731317f509b84a7f7208174a5eab4d250 100644
--- a/indra/llmessage/llregionpresenceverifier.h
+++ b/indra/llmessage/llregionpresenceverifier.h
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llregionpresenceverifier.cpp
  * @brief 
  *
  * $LicenseInfo:firstyear=2008&license=viewergpl$
@@ -37,7 +37,7 @@
 #include "llhttpclient.h"
 #include <string>
 #include "llsd.h"
-#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
 
 class LLHTTPClientInterface;
 
@@ -47,49 +47,58 @@ class LLRegionPresenceVerifier
 	class Response
 	{
 	public:
-		virtual ~Response() {}
+		virtual ~Response() = 0;
 
 		virtual bool checkValidity(const LLSD& content) const = 0;
 		virtual void onRegionVerified(const LLSD& region_details) = 0;
-
-		virtual void decrementRetries() = 0;
+		virtual void onRegionVerificationFailed() = 0;
 
 		virtual LLHTTPClientInterface& getHttpClient() = 0;
-		virtual std::string getRegionUri() const = 0;
-		virtual bool shouldRetry() const = 0;
 
-		virtual void onCompletedRegionRequest() {}
+	public: /* but not really -- don't touch this */
+		U32 mReferenceCount;		
 	};
 
-	typedef boost::shared_ptr<Response> ResponsePtr;
+	typedef boost::intrusive_ptr<Response> ResponsePtr;
 
 	class RegionResponder : public LLHTTPClient::Responder
 	{
 	public:
-		RegionResponder(ResponsePtr data);
+		RegionResponder(const std::string& uri, ResponsePtr data,
+						S32 retry_count);
+		virtual ~RegionResponder(); 
 		virtual void result(const LLSD& content);
-		virtual void completed(
-			U32 status,
-			const std::string& reason,
-			const LLSD& content);
+		virtual void error(U32 status, const std::string& reason);
 
 	private:
 		ResponsePtr mSharedData;
+		std::string mUri;
+		S32 mRetryCount;
 	};
 
 	class VerifiedDestinationResponder : public LLHTTPClient::Responder
 	{
 	public:
-		VerifiedDestinationResponder(ResponsePtr data, const LLSD& content);
+		VerifiedDestinationResponder(const std::string& uri, ResponsePtr data,
+									 const LLSD& content, S32 retry_count);
+		virtual ~VerifiedDestinationResponder();
 		virtual void result(const LLSD& content);
 		
 		virtual void error(U32 status, const std::string& reason);
+		
 	private:
 		void retry();
 		ResponsePtr mSharedData;
 		LLSD mContent;
+		std::string mUri;
+		S32 mRetryCount;
 	};
 };
 
+namespace boost
+{
+	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p);
+	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p);
+};
 
 #endif //LL_LLREGIONPRESENCEVERIFIER_H
diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp
index 9967a6197fe4e7a2abbd52cd23fb660aedc0d753..2cb742e2619a6796c1bab7c51b0cd2396a126822 100644
--- a/indra/llmessage/llsdmessage.cpp
+++ b/indra/llmessage/llsdmessage.cpp
@@ -68,6 +68,7 @@ bool LLSDMessage::httpListener(const LLSD& request)
     }
     LLHTTPClient::post(url, payload,
                        new LLSDMessage::EventResponder(LLEventPumps::instance(),
+                                                       request,
                                                        url, "POST", reply, error),
                        LLSD(),      // headers
                        timeout);
@@ -81,7 +82,9 @@ void LLSDMessage::EventResponder::result(const LLSD& data)
     // to the pump whose name is "".
     if (! mReplyPump.empty())
     {
-        mPumps.obtain(mReplyPump).post(data);
+        LLSD response(data);
+        mReqID.stamp(response);
+        mPumps.obtain(mReplyPump).post(response);
     }
     else                            // default success handling
     {
@@ -98,7 +101,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string
     // explicit pump name.
     if (! mErrorPump.empty())
     {
-        LLSD info;
+        LLSD info(mReqID.makeResponse());
         info["target"]  = mTarget;
         info["message"] = mMessage;
         info["status"]  = LLSD::Integer(status);
diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h
index 65503756a83585881eb43bbb4f463e0b07c1a3f9..6ee00fd41d25b5a6175405542190b354c7a065b4 100644
--- a/indra/llmessage/llsdmessage.h
+++ b/indra/llmessage/llsdmessage.h
@@ -121,9 +121,11 @@ class LLSDMessage
          * (e.g. "POST") as @a message.
          */
         EventResponder(LLEventPumps& pumps,
+                       const LLSD& request,
                        const std::string& target, const std::string& message,
                        const std::string& replyPump, const std::string& errorPump):
             mPumps(pumps),
+            mReqID(request),
             mTarget(target),
             mMessage(message),
             mReplyPump(replyPump),
@@ -135,6 +137,7 @@ class LLSDMessage
     
     private:
         LLEventPumps& mPumps;
+        LLReqID mReqID;
         const std::string mTarget, mMessage, mReplyPump, mErrorPump;
     };
 
diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp
index 21937f022f4edf042a6b3829e14919d782ba0d9c..6e41b03895c04a44670b828f0c57c85eb3f001a5 100755
--- a/indra/llmessage/llsdmessagebuilder.cpp
+++ b/indra/llmessage/llsdmessagebuilder.cpp
@@ -37,6 +37,7 @@
 #include "llmessagetemplate.h"
 #include "llquaternion.h"
 #include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "llsdserialize.h"
 #include "u64.h"
 #include "v3dmath.h"
diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp
index e699ec9e28b467c7ed93e719684b78f96a3ccc89..845a12d23b9c7383e1366d7738dd64e5efd4e424 100755
--- a/indra/llmessage/llsdmessagereader.cpp
+++ b/indra/llmessage/llsdmessagereader.cpp
@@ -38,6 +38,7 @@
 #include "llsdmessagebuilder.h"
 #include "llsdutil.h"
 
+#include "llsdutil_math.h"
 #include "v3math.h"
 #include "v4math.h"
 #include "v3dmath.h"
diff --git a/indra/llmessage/llstoredmessage.cpp b/indra/llmessage/llstoredmessage.cpp
index 32cbb15cb385fcf072e5e7375634fe353db704bf..d6b2f45d04e58d08f6fa411e64431f74d2bc5e72 100644
--- a/indra/llmessage/llstoredmessage.cpp
+++ b/indra/llmessage/llstoredmessage.cpp
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llstoredmessage.cpp
  * @brief 
  *
  * $LicenseInfo:firstyear=2009&license=viewergpl$
diff --git a/indra/llmessage/llstoredmessage.h b/indra/llmessage/llstoredmessage.h
index 5069c2cb2e19226d283d19fe6dfefa8c02321e9e..359e4c5aeac96ba32f23aee834792a9d95d02a92 100644
--- a/indra/llmessage/llstoredmessage.h
+++ b/indra/llmessage/llstoredmessage.h
@@ -1,5 +1,5 @@
 /** 
- * @file 
+ * @file llstoredmessage.h
  * @brief 
  *
  * $LicenseInfo:firstyear=2009&license=viewergpl$
diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp
index 70279a3c62d033ab8eab74103eac4d93bf548bdf..0872efba508ff8d427f557881356de7bf4320fc6 100644
--- a/indra/llmessage/llthrottle.cpp
+++ b/indra/llmessage/llthrottle.cpp
@@ -265,6 +265,31 @@ BOOL LLThrottleGroup::setNominalBPS(F32* throttle_vec)
 	return changed;
 }
 
+// Return bits available in the channel
+S32		LLThrottleGroup::getAvailable(S32 throttle_cat)
+{
+	S32 retval = 0;
+
+	F32 category_bps = mCurrentBPS[throttle_cat];
+	F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
+
+	// use a temporary bits_available
+	// since we don't want to change mBitsAvailable every time
+	F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]);
+	F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time);
+
+	if (bits_available >= lookahead_bits)
+	{
+		retval = (S32) gThrottleMaximumBPS[throttle_cat];
+	}
+	else 
+	{
+		retval = (S32) bits_available;
+	}
+	
+	return retval;
+}
+
 
 BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits)
 {
diff --git a/indra/llmessage/llthrottle.h b/indra/llmessage/llthrottle.h
index 7d1679beb232ead9c23259f0bab6799fdca3d9f8..47a7c653b23b1679a73d845c9da4a4ec73172468 100644
--- a/indra/llmessage/llthrottle.h
+++ b/indra/llmessage/llthrottle.h
@@ -84,6 +84,8 @@ class LLThrottleGroup
 	BOOL	dynamicAdjust();		// Shift bandwidth from idle channels to busy channels, TRUE if adjustment occurred
 	BOOL	setNominalBPS(F32* throttle_vec);				// TRUE if any value was different, resets adjustment system if was different
 
+	S32		getAvailable(S32 throttle_cat);					// Return bits available in the channel
+
 	void packThrottle(LLDataPacker &dp) const;
 	void unpackThrottle(LLDataPacker &dp);
 public:
diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp
index 5a1cd95ffcd54183a95618dbd321b145d6e96952..41f3f3f607d9fcae5fa610b871c7126f6efeccbd 100644
--- a/indra/llmessage/lltransfersourceasset.cpp
+++ b/indra/llmessage/lltransfersourceasset.cpp
@@ -270,7 +270,6 @@ bool is_asset_fetch_by_id_allowed(LLAssetType::EType type)
 		case LLAssetType::AT_BODYPART:
 		case LLAssetType::AT_ANIMATION:
 		case LLAssetType::AT_GESTURE:
-		case LLAssetType::AT_FAVORITE:
 			rv = true;
 			break;
 		default:
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 3ab8057abb0951576a5f4d1dea241e404c65e4c3..81b7761ed5fdec3b2263ab3c6c6da23d2f471f31 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -51,6 +51,7 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;
  * String constants
  */
 const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
+const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
 
 
 static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
@@ -247,7 +248,29 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
 	PUMP_DEBUG;
 	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
 	//llinfos << "LLURLRequest::process_impl()" << llendl;
-	if(!buffer) return STATUS_ERROR;
+	if (!buffer) return STATUS_ERROR;
+	
+	// we're still waiting or prcessing, check how many
+	// bytes we have accumulated.
+	const S32 MIN_ACCUMULATION = 100000;
+	if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
+	{
+		 // This is a pretty sloppy calculation, but this
+		 // tries to make the gross assumption that if data
+		 // is coming in at 56kb/s, then this transfer will
+		 // probably succeed. So, if we're accumlated
+		 // 100,000 bytes (MIN_ACCUMULATION) then let's
+		 // give this client another 2s to complete.
+		 const F32 TIMEOUT_ADJUSTMENT = 2.0f;
+		 mDetail->mByteAccumulator = 0;
+		 pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
+		 lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl;
+		 if (mState == STATE_INITIALIZED)
+		 {
+			  llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl;
+		 }
+	}
+
 	switch(mState)
 	{
 	case STATE_INITIALIZED:
@@ -286,27 +309,14 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
 			bool newmsg = mDetail->mCurlRequest->getResult(&result);
 			if(!newmsg)
 			{
-				// we're still waiting or prcessing, check how many
-				// bytes we have accumulated.
-				const S32 MIN_ACCUMULATION = 100000;
-				if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
-				{
-					// This is a pretty sloppy calculation, but this
-					// tries to make the gross assumption that if data
-					// is coming in at 56kb/s, then this transfer will
-					// probably succeed. So, if we're accumlated
-					// 100,000 bytes (MIN_ACCUMULATION) then let's
-					// give this client another 2s to complete.
-					const F32 TIMEOUT_ADJUSTMENT = 2.0f;
-					mDetail->mByteAccumulator = 0;
-					pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
-				}
-
 				// keep processing
 				break;
 			}
 
 			mState = STATE_HAVE_RESPONSE;
+			context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
+			context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
+			lldebugs << this << "Setting context to " << context << llendl;
 			switch(result)
 			{
 				case CURLE_OK:
@@ -353,10 +363,16 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
 		// we already stuffed everything into channel in in the curl
 		// callback, so we are done.
 		eos = true;
+		context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
+		context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
+		lldebugs << this << "Setting context to " << context << llendl;
 		return STATUS_DONE;
 
 	default:
 		PUMP_DEBUG;
+		context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
+		context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
+		lldebugs << this << "Setting context to " << context << llendl;
 		return STATUS_ERROR;
 	}
 }
@@ -369,6 +385,8 @@ void LLURLRequest::initialize()
 	mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
 	mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
 	mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
+	mRequestTransferedBytes = 0;
+	mResponseTransferedBytes = 0;
 }
 
 bool LLURLRequest::configure()
@@ -471,6 +489,7 @@ size_t LLURLRequest::downCallback(
 		req->mDetail->mChannels.out(),
 		(U8*)data,
 		bytes);
+	req->mResponseTransferedBytes += bytes;
 	req->mDetail->mByteAccumulator += bytes;
 	return bytes;
 }
@@ -494,6 +513,7 @@ size_t LLURLRequest::upCallback(
 		req->mDetail->mLastRead,
 		(U8*)data,
 		bytes);
+	req->mRequestTransferedBytes += bytes;
 	return bytes;
 }
 
diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h
index 86ef71f085b7048386f68a9c086681987d9d5b21..cb3c46644062cbb26530cc4fbc4e13c90a99309e 100644
--- a/indra/llmessage/llurlrequest.h
+++ b/indra/llmessage/llurlrequest.h
@@ -45,6 +45,12 @@
 #include "llchainio.h"
 #include "llerror.h"
 
+
+extern const std::string CONTEXT_REQUEST;
+extern const std::string CONTEXT_DEST_URI_SD_LABEL;
+extern const std::string CONTEXT_RESPONSE;
+extern const std::string CONTEXT_TRANSFERED_BYTES;
+
 class LLURLRequestDetail;
 
 class LLURLRequestComplete;
@@ -208,6 +214,8 @@ class LLURLRequest : public LLIOPipe
 	ERequestAction mAction;
 	LLURLRequestDetail* mDetail;
 	LLIOPipe::ptr_t mCompletionCallback;
+	 S32 mRequestTransferedBytes;
+	 S32 mResponseTransferedBytes;
 
 private:
 	/** 
diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp
index 08c9192c9ff5c4ddc117de55811223ad464903dd..209bdb2249459fe446fb336e4b287db0ebf08ed6 100644
--- a/indra/llmessage/llxfermanager.cpp
+++ b/indra/llmessage/llxfermanager.cpp
@@ -760,30 +760,36 @@ static bool remove_prefix(std::string& filename, const std::string& prefix)
 static bool verify_cache_filename(const std::string& filename)
 {
 	//NOTE: This routine is only used to check file names that our own
-	// code places in the cache directory.  As such, it can be limited
-	// to this very restrictive file name pattern.  It does not need to
-	// handle other characters.
-
+	// code places in the cache directory.	As such, it can be limited
+	// to this very restrictive file name pattern.	It does not need to
+	// handle other characters. The only known uses of this are (with examples):
+	//	sim to sim object pass:			fc0b72d8-9456-63d9-a802-a557ef847313.tmp
+	//	sim to viewer mute list:		mute_b78eacd0-1244-448e-93ca-28ede242f647.tmp
+	//	sim to viewer task inventory:	inventory_d8ab59d2-baf0-0e79-c4c2-a3f99b9fcf45.tmp
+	
+	//IMPORTANT: Do not broaden the filenames accepted by this routine
+	// without careful analysis. Anything allowed by this function can
+	// be downloaded by the viewer.
+	
 	size_t len = filename.size();
-	//const boost::regex expr("[a-zA-Z0-9][-_.a-zA-Z0-9]<0,49>");
-	if (len < 1 || len > 50)
-	{
+	//const boost::regex expr("[0-9a-zA-Z_-]<1,46>\.tmp");
+	if (len < 5 || len > 50)
+	{	
 		return false;
 	}
-	for(unsigned i=0; i<len; ++i)
-	{
+	for(size_t i=0; i<(len-4); ++i)
+	{	
 		char c = filename[i];
-		bool ok = isalnum(c);
-		if (!ok && i > 0)
-		{
-			ok = '_'==c || '-'==c || '.'==c;
-		}
+		bool ok = isalnum(c) || '_'==c || '-'==c;
 		if (!ok)
 		{
 			return false;
 		}
 	}
-	return true;
+	return filename[len-4] == '.'
+		&& filename[len-3] == 't'
+		&& filename[len-2] == 'm'
+		&& filename[len-1] == 'p';
 }
 
 void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/)
diff --git a/indra/llmessage/tests/llareslistener_test.cpp b/indra/llmessage/tests/llareslistener_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac4886ccf4f023bd343b753b5497ea619aed1555
--- /dev/null
+++ b/indra/llmessage/tests/llareslistener_test.cpp
@@ -0,0 +1,200 @@
+/**
+ * @file   llareslistener_test.cpp
+ * @author Mark Palange
+ * @date   2009-02-26
+ * @brief  Tests of llareslistener.h.
+ * 
+ * $LicenseInfo:firstyear=2009&license=internal$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "../llareslistener.h"
+// STL headers
+#include <iostream>
+// std headers
+// external library headers
+#include <boost/bind.hpp>
+
+// other Linden headers
+#include "llsd.h"
+#include "llares.h"
+#include "../test/lltut.h"
+#include "llevents.h"
+#include "tests/wrapllerrs.h"
+
+/*****************************************************************************
+*   Dummy stuff
+*****************************************************************************/
+LLAres::LLAres():
+    // Simulate this much of the real LLAres constructor: we need an
+    // LLAresListener instance.
+    mListener(new LLAresListener("LLAres", this))
+{}
+LLAres::~LLAres() {}
+void LLAres::rewriteURI(const std::string &uri,
+					LLAres::UriRewriteResponder *resp)
+{
+	// This is the only LLAres method I chose to implement.
+	// The effect is that LLAres returns immediately with
+	// a result that is equal to the input uri.
+	std::vector<std::string> result;
+	result.push_back(uri);
+	resp->rewriteResult(result);
+}
+
+LLAres::QueryResponder::~QueryResponder() {}
+void LLAres::QueryResponder::queryError(int) {}
+void LLAres::QueryResponder::queryResult(char const*, size_t) {}
+LLQueryResponder::LLQueryResponder() {}
+void LLQueryResponder::queryResult(char const*, size_t) {}
+void LLQueryResponder::querySuccess() {}
+void LLAres::UriRewriteResponder::queryError(int) {}
+void LLAres::UriRewriteResponder::querySuccess() {}
+void LLAres::UriRewriteResponder::rewriteResult(const std::vector<std::string>& uris) {}
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct data
+    {
+        LLAres dummyAres;
+    };
+    typedef test_group<data> llareslistener_group;
+    typedef llareslistener_group::object object;
+    llareslistener_group llareslistenergrp("llareslistener");
+
+	struct ResponseCallback
+	{
+		std::vector<std::string> mURIs;
+		bool operator()(const LLSD& response)
+		{
+            mURIs.clear();
+            for (LLSD::array_const_iterator ri(response.beginArray()), rend(response.endArray());
+                 ri != rend; ++ri)
+            {
+                mURIs.push_back(*ri);
+            }
+            return false;
+		}
+	};
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("test event");
+		// Tests the success and failure cases, since they both use 
+		// the same code paths in the LLAres responder.
+		ResponseCallback response;
+        std::string pumpname("trigger");
+        // Since we're asking LLEventPumps to obtain() the pump by the desired
+        // name, it will persist beyond the current scope, so ensure we
+        // disconnect from it when 'response' goes away.
+        LLTempBoundListener temp(
+            LLEventPumps::instance().obtain(pumpname).listen("rewriteURIresponse",
+                                                             boost::bind(&ResponseCallback::operator(), &response, _1)));
+        // Now build an LLSD request that will direct its response events to
+        // that pump.
+		const std::string testURI("login.bar.com");
+        LLSD request;
+        request["op"] = "rewriteURI";
+        request["uri"] = testURI;
+        request["reply"] = pumpname;
+        LLEventPumps::instance().obtain("LLAres").post(request);
+		ensure_equals(response.mURIs.size(), 1);
+		ensure_equals(response.mURIs.front(), testURI); 
+	}
+
+    template<> template<>
+    void object::test<2>()
+    {
+        set_test_name("bad op");
+        WrapLL_ERRS capture;
+        LLSD request;
+        request["op"] = "foo";
+        std::string threw;
+        try
+        {
+            LLEventPumps::instance().obtain("LLAres").post(request);
+        }
+        catch (const WrapLL_ERRS::FatalException& e)
+        {
+            threw = e.what();
+        }
+        ensure_contains("LLAresListener bad op", threw, "bad");
+    }
+
+    template<> template<>
+    void object::test<3>()
+    {
+        set_test_name("bad rewriteURI request");
+        WrapLL_ERRS capture;
+        LLSD request;
+        request["op"] = "rewriteURI";
+        std::string threw;
+        try
+        {
+            LLEventPumps::instance().obtain("LLAres").post(request);
+        }
+        catch (const WrapLL_ERRS::FatalException& e)
+        {
+            threw = e.what();
+        }
+        ensure_contains("LLAresListener bad req", threw, "missing");
+        ensure_contains("LLAresListener bad req", threw, "reply");
+        ensure_contains("LLAresListener bad req", threw, "uri");
+    }
+
+    template<> template<>
+    void object::test<4>()
+    {
+        set_test_name("bad rewriteURI request");
+        WrapLL_ERRS capture;
+        LLSD request;
+        request["op"] = "rewriteURI";
+        request["reply"] = "nonexistent";
+        std::string threw;
+        try
+        {
+            LLEventPumps::instance().obtain("LLAres").post(request);
+        }
+        catch (const WrapLL_ERRS::FatalException& e)
+        {
+            threw = e.what();
+        }
+        ensure_contains("LLAresListener bad req", threw, "missing");
+        ensure_contains("LLAresListener bad req", threw, "uri");
+        ensure_does_not_contain("LLAresListener bad req", threw, "reply");
+    }
+
+    template<> template<>
+    void object::test<5>()
+    {
+        set_test_name("bad rewriteURI request");
+        WrapLL_ERRS capture;
+        LLSD request;
+        request["op"] = "rewriteURI";
+        request["uri"] = "foo.bar.com";
+        std::string threw;
+        try
+        {
+            LLEventPumps::instance().obtain("LLAres").post(request);
+        }
+        catch (const WrapLL_ERRS::FatalException& e)
+        {
+            threw = e.what();
+        }
+        ensure_contains("LLAresListener bad req", threw, "missing");
+        ensure_contains("LLAresListener bad req", threw, "reply");
+        ensure_does_not_contain("LLAresListener bad req", threw, "uri");
+    }
+}
diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp
index 5dc5932fde9db420c408ac4a0747a92e34cc01c7..e6a5ad9946d8347ded67f231bc0e0e88c5121ddb 100644
--- a/indra/llmessage/tests/llcurl_stub.cpp
+++ b/indra/llmessage/tests/llcurl_stub.cpp
@@ -22,6 +22,7 @@
 #include "linden_common.h"
 
 LLCurl::Responder::Responder()
+	: mReferenceCount(0)
 {
 }
 
diff --git a/indra/llmessage/tests/llhost_test.cpp b/indra/llmessage/tests/llhost_test.cpp
index 2424dbcb6b43d05d3574932d2d8e4eded9144cdf..7e5c3a117b326e51b0ea9db67ed28ae50b3e7609 100644
--- a/indra/llmessage/tests/llhost_test.cpp
+++ b/indra/llmessage/tests/llhost_test.cpp
@@ -157,7 +157,8 @@ namespace tut
 	template<> template<>
 	void host_object::test<9>()
 	{
-		std::string hostStr = "linux.org";
+//		skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\"");
+		std::string hostStr = "linux.org";		
 		LLHost host;
 		host.setHostByName(hostStr);	
 
@@ -166,7 +167,15 @@ namespace tut
 		// the main domain name and not do the exact compare
 		
 		std::string hostname = host.getHostName();
-		ensure("getHostName failed", hostname.find(hostStr) != std::string::npos);
+		try
+		{
+			ensure("getHostName failed", hostname.find(hostStr) != std::string::npos);
+		}
+		catch (const std::exception&)
+		{
+			std::cerr << "set '" << hostStr << "'; reported '" << hostname << "'" << std::endl;
+			throw;
+		}
 	}
 
 //	setHostByName for dotted IP
diff --git a/indra/llmessage/tests/llmockhttpclient.h b/indra/llmessage/tests/llmockhttpclient.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f55e97fcc95f89a9eaf390e3c5e95314df4eb90
--- /dev/null
+++ b/indra/llmessage/tests/llmockhttpclient.h
@@ -0,0 +1,61 @@
+/** 
+ * @file 
+ * @brief 
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
+ * this source code is governed by the Linden Lab Source Code Disclosure
+ * Agreement ("Agreement") previously entered between you and Linden
+ * Lab. By accessing, using, copying, modifying or distributing this
+ * software, you acknowledge that you have been informed of your
+ * obligations under the Agreement and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/* Macro Definitions */
+#ifndef LL_LLMOCKHTTPCLIENT_H
+#define LL_LLMOCKHTTPCLIENT_H
+
+#include "linden_common.h"
+#include "llhttpclientinterface.h"
+
+#include <gmock/gmock.h>
+
+class LLMockHTTPClient : public LLHTTPClientInterface
+{
+public:
+  MOCK_METHOD2(get, void(const std::string& url, LLCurl::ResponderPtr responder));
+  MOCK_METHOD3(get, void(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers));
+  MOCK_METHOD3(put, void(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder));
+};
+
+// A helper to match responder types
+template<typename T>
+struct ResponderType
+{
+	bool operator()(LLCurl::ResponderPtr ptr) const
+	{
+		T* p = dynamic_cast<T*>(ptr.get());
+		return p != NULL;
+	}
+};
+
+inline bool operator==(const LLSD& l, const LLSD& r)
+{
+	std::ostringstream ls, rs;
+	ls << l;
+	rs << r;
+	return ls.str() == rs.str();
+
+}
+
+
+#endif //LL_LLMOCKHTTPCLIENT_H
+
diff --git a/indra/llmessage/tests/llregionpresenceverifier_test.cpp b/indra/llmessage/tests/llregionpresenceverifier_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c86126406ec0afe2e7510999cf8d4b3065119770
--- /dev/null
+++ b/indra/llmessage/tests/llregionpresenceverifier_test.cpp
@@ -0,0 +1,113 @@
+/** 
+ * @file 
+ * @brief 
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "../test/lltut.h"
+#include "llregionpresenceverifier.h"
+#include "llcurl_stub.cpp"
+#include "llhost.cpp"
+#include "net.cpp"
+#include "lltesthttpclientadapter.cpp"
+
+class LLTestResponse : public LLRegionPresenceVerifier::Response
+{
+public:
+
+	virtual bool checkValidity(const LLSD& content) const
+	{
+		return true;
+	}
+
+	virtual void onRegionVerified(const LLSD& region_details)
+	{
+	}
+
+	virtual void onRegionVerificationFailed()
+	{
+	}
+	
+	virtual LLHTTPClientInterface& getHttpClient()
+	{
+		return mHttpInterface;
+	}
+
+	LLTestHTTPClientAdapter mHttpInterface;
+};
+
+namespace tut
+{
+	struct LLRegionPresenceVerifierData
+	{
+		LLRegionPresenceVerifierData() :
+			mResponse(new LLTestResponse()),
+			mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse),
+					   LLSD(), 3)
+		{
+		}
+		
+		LLTestResponse* mResponse;
+		LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder;
+	};
+
+	typedef test_group<LLRegionPresenceVerifierData> factory;
+	typedef factory::object object;
+}
+
+namespace
+{
+	tut::factory tf("LLRegionPresenceVerifier test");
+}
+
+namespace tut
+{
+	// Test that VerifiedDestinationResponder does retry
+    // on error when shouldRetry returns true.
+	template<> template<>
+	void object::test<1>()
+	{
+		mResponder.error(500, "Internal server error");
+		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1);
+	}
+
+	// Test that VerifiedDestinationResponder only retries
+	// on error until shouldRetry returns false.
+	template<> template<>
+	void object::test<2>()
+	{
+		mResponder.error(500, "Internal server error");
+		mResponder.error(500, "Internal server error");
+		mResponder.error(500, "Internal server error");
+		mResponder.error(500, "Internal server error");
+		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3);
+	}
+}
+
diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py
index e62f20912be58a8d7235ebb815a4141913624479..86d5761b1b4bf69c7ebcfccfb41814bdc97d89c9 100644
--- a/indra/llmessage/tests/test_llsdmessage_peer.py
+++ b/indra/llmessage/tests/test_llsdmessage_peer.py
@@ -16,16 +16,12 @@
 import sys
 from threading import Thread
 from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+
 mydir = os.path.dirname(__file__)       # expected to be .../indra/llmessage/tests/
 sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
 from indra.util.fastest_elementtree import parse as xml_parse
 from indra.base import llsd
-
-def debug(*args):
-    sys.stdout.writelines(args)
-    sys.stdout.flush()
-# comment out the line below to enable debug output
-debug = lambda *args: None
+from testrunner import run, debug
 
 class TestHTTPRequestHandler(BaseHTTPRequestHandler):
     """This subclass of BaseHTTPRequestHandler is to receive and echo
@@ -106,25 +102,5 @@ def run(self):
         debug("Starting HTTP server...\n")
         httpd.serve_forever()
 
-def main(*args):
-    # Start HTTP server thread. Note that this and all other comm server
-    # threads should be daemon threads: we'll let them run "forever,"
-    # confident that the whole process will terminate when the main thread
-    # terminates, which will be when the test executable child process
-    # terminates.
-    httpThread = TestHTTPServer(name="httpd")
-    httpThread.setDaemon(True)
-    httpThread.start()
-    # choice of os.spawnv():
-    # - [v vs. l] pass a list of args vs. individual arguments,
-    # - [no p] don't use the PATH because we specifically want to invoke the
-    #   executable passed as our first arg,
-    # - [no e] child should inherit this process's environment.
-    debug("Running %s...\n" % (" ".join(args)))
-    sys.stdout.flush()
-    rc = os.spawnv(os.P_WAIT, args[0], args)
-    debug("%s returned %s\n" % (args[0], rc))
-    return rc
-
 if __name__ == "__main__":
-    sys.exit(main(*sys.argv[1:]))
+    sys.exit(run(server=TestHTTPServer(name="httpd"), *sys.argv[1:]))
diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b9c3a7a1976dd8cba3a7e4daf8a1f21c6bfc558
--- /dev/null
+++ b/indra/llmessage/tests/testrunner.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+"""\
+@file   testrunner.py
+@author Nat Goodspeed
+@date   2009-03-20
+@brief  Utilities for writing wrapper scripts for ADD_COMM_BUILD_TEST unit tests
+
+$LicenseInfo:firstyear=2009&license=viewergpl$
+Copyright (c) 2009, Linden Research, Inc.
+$/LicenseInfo$
+"""
+
+import os
+import sys
+
+def debug(*args):
+    sys.stdout.writelines(args)
+    sys.stdout.flush()
+# comment out the line below to enable debug output
+debug = lambda *args: None
+
+def run(*args, **kwds):
+    """All positional arguments collectively form a command line, executed as
+    a synchronous child process.
+    In addition, pass server=new_thread_instance as an explicit keyword (to
+    differentiate it from an additional command-line argument).
+    new_thread_instance should be an instantiated but not yet started Thread
+    subclass instance, e.g.:
+    run("python", "-c", 'print "Hello, world!"', server=TestHTTPServer(name="httpd"))
+    """
+    # If there's no server= keyword arg, don't start a server thread: simply
+    # run a child process.
+    try:
+        thread = kwds.pop("server")
+    except KeyError:
+        pass
+    else:
+        # Start server thread. Note that this and all other comm server
+        # threads should be daemon threads: we'll let them run "forever,"
+        # confident that the whole process will terminate when the main thread
+        # terminates, which will be when the child process terminates.
+        thread.setDaemon(True)
+        thread.start()
+    # choice of os.spawnv():
+    # - [v vs. l] pass a list of args vs. individual arguments,
+    # - [no p] don't use the PATH because we specifically want to invoke the
+    #   executable passed as our first arg,
+    # - [no e] child should inherit this process's environment.
+    debug("Running %s...\n" % (" ".join(args)))
+    sys.stdout.flush()
+    rc = os.spawnv(os.P_WAIT, args[0], args)
+    debug("%s returned %s\n" % (args[0], rc))
+    return rc
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 7299ede22d7d455373fb7a520ce0297d5c17e6e9..fc58b48a7b9357c74dc2522286a4ee2b9818b30c 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -133,6 +133,7 @@ void LLPluginClassMedia::reset()
 	mCurrentTime = 0.0f;
 	mDuration = 0.0f;
 	mCurrentRate = 0.0f;
+	mLoadedDuration = 0.0f;
 }
 
 void LLPluginClassMedia::idle(void)
@@ -705,6 +706,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			
 
 			bool time_duration_updated = false;
+			int previous_percent = mProgressPercent;
 
 			if(message.hasValue("current_time"))
 			{
@@ -722,11 +724,32 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 				mCurrentRate = message.getValueReal("current_rate");
 			}
 			
+			if(message.hasValue("loaded_duration"))
+			{
+				mLoadedDuration = message.getValueReal("loaded_duration");
+				time_duration_updated = true;
+			}
+			else
+			{
+				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
+				mLoadedDuration = mDuration;
+			}
+			
+			// Calculate a percentage based on the loaded duration and total duration.
+			if(mDuration != 0.0f)	// Don't divide by zero.
+			{
+				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
+			}
+
 			if(time_duration_updated)
 			{
 				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
 			}
 			
+			if(previous_percent != mProgressPercent)
+			{
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
+			}
 		}
 		else if(message_name == "media_status")
 		{
@@ -812,6 +835,11 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 				mCanPaste = message.getValueBoolean("paste");
 			}
 		}
+		else if(message_name == "name_text")
+		{
+			mMediaName = message.getValue("name");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
+		}
 		else
 		{
 			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
@@ -883,6 +911,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 
 }
 
+/* virtual */ 
+void LLPluginClassMedia::pluginLaunchFailed()
+{
+	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
+}
+
 /* virtual */ 
 void LLPluginClassMedia::pluginDied()
 {
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 331ca5f6dcd58ee492fc46bafc7d68eb9ce33d64..697deec353052ad6113dfc4d2244649bc336f02f 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -135,6 +135,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	
 	// Inherited from LLPluginProcessParentOwner
 	/* virtual */ void receivePluginMessage(const LLPluginMessage &message);
+	/* virtual */ void pluginLaunchFailed();
 	/* virtual */ void pluginDied();
 	
 	
@@ -230,6 +231,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	F64 getCurrentTime(void) const { return mCurrentTime; };
 	F64 getDuration(void) const { return mDuration; };
 	F64 getCurrentPlayRate(void) { return mCurrentRate; };
+	F64 getLoadedDuration(void) const { return mLoadedDuration; };
 	
 	// Initialize the URL history of the plugin by sending
 	// "init_history" message 
@@ -338,6 +340,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	F64				mCurrentTime;
 	F64				mDuration;
 	F64				mCurrentRate;
+	F64				mLoadedDuration;
 	
 };
 
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index df6de0925e8c27f3d8a91fdef4d0cfb646a5cd30..4690f09172489523b357d9aea55db60294e393c1 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -52,11 +52,13 @@ class LLPluginClassMediaOwner
 		MEDIA_EVENT_NAVIGATE_COMPLETE,		// browser has finished navigation
 		MEDIA_EVENT_PROGRESS_UPDATED,		// browser has updated loading progress
 		MEDIA_EVENT_STATUS_TEXT_CHANGED,	// browser has updated the status text
+		MEDIA_EVENT_NAME_CHANGED,			// browser has updated the name of the media (typically <title> tag)
 		MEDIA_EVENT_LOCATION_CHANGED,		// browser location (URL) has changed (maybe due to internal navagation/frames/etc)
 		MEDIA_EVENT_CLICK_LINK_HREF,		// I'm not entirely sure what the semantics of these two are
 		MEDIA_EVENT_CLICK_LINK_NOFOLLOW,
 		
-		MEDIA_EVENT_PLUGIN_FAILED			// The plugin failed to launch or died unexpectedly
+		MEDIA_EVENT_PLUGIN_FAILED_LAUNCH,	// The plugin failed to launch 
+		MEDIA_EVENT_PLUGIN_FAILED			// The plugin died unexpectedly
 		
 	} EMediaEvent;
 	
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index 41784a713c4b0f367ed82faeab615ccf5c008b7c..f3b4c6bdc63d4ae70ed81b32d492c8e82af0948e 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -83,6 +83,14 @@ void LLPluginProcessParent::killSockets(void)
 	mSocket.reset();
 }
 
+void LLPluginProcessParent::errorState(void)
+{
+	if(mState < STATE_RUNNING)
+		setState(STATE_LAUNCH_FAILURE);
+	else
+		setState(STATE_ERROR);
+}
+
 void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename)
 {	
 	mProcess.setExecutable(launcher_filename);
@@ -132,7 +140,7 @@ bool LLPluginProcessParent::accept()
 		ll_apr_warn_status(status);
 		
 		// Some other error.
-		setState(STATE_ERROR);
+		errorState();
 	}
 	
 	return result;	
@@ -150,15 +158,15 @@ void LLPluginProcessParent::idle(void)
 			if(!mMessagePipe->pump())
 			{
 //				LL_WARNS("Plugin") << "Message pipe hit an error state" << LL_ENDL;
-				setState(STATE_ERROR);
+				errorState();
 			}
 		}
 
-		if((mSocketError != APR_SUCCESS) && (mState < STATE_ERROR))
+		if((mSocketError != APR_SUCCESS) && (mState <= STATE_RUNNING))
 		{
 			// The socket is in an error state -- the plugin is gone.
 			LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
-			setState(STATE_ERROR);
+			errorState();
 		}	
 		
 		// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
@@ -191,7 +199,7 @@ void LLPluginProcessParent::idle(void)
 				if(ll_apr_warn_status(status))
 				{
 					killSockets();
-					setState(STATE_ERROR);
+					errorState();
 					break;
 				}
 
@@ -202,7 +210,7 @@ void LLPluginProcessParent::idle(void)
 				if(ll_apr_warn_status(status))
 				{
 					killSockets();
-					setState(STATE_ERROR);
+					errorState();
 					break;
 				}
 
@@ -212,7 +220,7 @@ void LLPluginProcessParent::idle(void)
 					if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket())))
 					{
 						killSockets();
-						setState(STATE_ERROR);
+						errorState();
 						break;
 					}
 					mBoundPort = bound_addr->port;	
@@ -222,7 +230,7 @@ void LLPluginProcessParent::idle(void)
 						LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL;
 						
 						killSockets();
-						setState(STATE_ERROR);
+						errorState();
 						break;
 					}
 				}
@@ -234,7 +242,7 @@ void LLPluginProcessParent::idle(void)
 				if(ll_apr_warn_status(status))
 				{
 					killSockets();
-					setState(STATE_ERROR);
+					errorState();
 					break;
 				}
 
@@ -242,7 +250,7 @@ void LLPluginProcessParent::idle(void)
 				if(ll_apr_warn_status(status))
 				{
 					killSockets();
-					setState(STATE_ERROR);
+					errorState();
 					break;
 				}
 				
@@ -255,7 +263,7 @@ void LLPluginProcessParent::idle(void)
 				if(ll_apr_warn_status(status))
 				{
 					killSockets();
-					setState(STATE_ERROR);
+					errorState();
 					break;
 				}
 				
@@ -274,7 +282,7 @@ void LLPluginProcessParent::idle(void)
 				mProcess.addArgument(stream.str());
 				if(mProcess.launch() != 0)
 				{
-					setState(STATE_ERROR);
+					errorState();
 				}
 				else
 				{
@@ -290,7 +298,7 @@ void LLPluginProcessParent::idle(void)
 				// waiting for the plugin to connect
 				if(pluginLockedUpOrQuit())
 				{
-					setState(STATE_ERROR);
+					errorState();
 				}
 				else
 				{
@@ -309,7 +317,7 @@ void LLPluginProcessParent::idle(void)
 
 				if(pluginLockedUpOrQuit())
 				{
-					setState(STATE_ERROR);
+					errorState();
 				}
 			break;
 
@@ -330,14 +338,14 @@ void LLPluginProcessParent::idle(void)
 				// The load_plugin_response message will kick us from here into STATE_RUNNING
 				if(pluginLockedUpOrQuit())
 				{
-					setState(STATE_ERROR);
+					errorState();
 				}
 			break;
 			
 			case STATE_RUNNING:
 				if(pluginLockedUpOrQuit())
 				{
-					setState(STATE_ERROR);
+					errorState();
 				}
 			break;
 			
@@ -349,8 +357,16 @@ void LLPluginProcessParent::idle(void)
 				else if(pluginLockedUp())
 				{
 					LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << llendl;
-					setState(STATE_ERROR);
+					errorState();
+				}
+			break;
+
+			case STATE_LAUNCH_FAILURE:
+				if(mOwner != NULL)
+				{
+					mOwner->pluginLaunchFailed();
 				}
+				setState(STATE_CLEANUP);
 			break;
 
 			case STATE_ERROR:
@@ -467,7 +483,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
 			else
 			{
 				LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL;
-				setState(STATE_ERROR);
+				errorState();
 			}
 			
 		}
@@ -477,6 +493,9 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
 			{
 				// Plugin has been loaded. 
 				
+				mPluginVersionString = message.getValue("plugin_version");
+				LL_INFOS("Plugin") << "plugin version string: " << mPluginVersionString << LL_ENDL;
+
 				// Check which message classes/versions the plugin supports.
 				// TODO: check against current versions
 				// TODO: kill plugin on major mismatches?
@@ -487,8 +506,6 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
 					LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL;
 				}
 				
-				mPluginVersionString = message.getValue("plugin_version");
-				
 				// Send initial sleep time
 				setSleepTime(mSleepTime, true);			
 
@@ -497,7 +514,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
 			else
 			{
 				LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL;
-				setState(STATE_ERROR);
+				errorState();
 			}
 		}
 		else if(message_name == "heartbeat")
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 0d0b047c88c22ad81b0a4a22ab32f01bf7a22700..754ebeb94683efc033c077013f0f06bc48dde25b 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -45,6 +45,7 @@ class LLPluginProcessParentOwner
 	virtual ~LLPluginProcessParentOwner();
 	virtual void receivePluginMessage(const LLPluginMessage &message) = 0;
 	// This will only be called when the plugin has died unexpectedly 
+	virtual void pluginLaunchFailed() {};
 	virtual void pluginDied() {};
 };
 
@@ -68,6 +69,9 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 	bool isDone(void);	
 	
 	void killSockets(void);
+	
+	// Go to the proper error state
+	void errorState(void);
 
 	void setSleepTime(F64 sleep_time, bool force_send = false);
 	F64 getSleepTime(void) const { return mSleepTime; };
@@ -110,6 +114,7 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 		STATE_HELLO,			// first message from the plugin process has been received
 		STATE_LOADING,			// process has been asked to load the plugin
 		STATE_RUNNING,			// 
+		STATE_LAUNCH_FAILURE,	// Failure before plugin loaded
 		STATE_ERROR,			// generic bailout state
 		STATE_CLEANUP,			// clean everything up
 		STATE_EXITING,			// Tried to kill process, waiting for it to exit
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index b102254b62fb81d48a3b25080eef6e09e982571e..5ad758072c98bdce3827b5b2c71ba969c0c273e5 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -43,7 +43,7 @@
 #include "llvolumemgr.h"
 #include "llstring.h"
 #include "lldatapacker.h"
-#include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "llprimtexturelist.h"
 
 /**
@@ -746,16 +746,201 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
 
 	U32 old_face_mask = mVolumep->mFaceMask;
 
+	S32 face_bit = 0;
+	S32 cur_mask = 0;
+
+	// Grab copies of the old faces from the original shape, ordered by type.
+	// We will use these to figure out what old texture info gets mapped to new
+	// faces in the new shape.
+	std::vector<LLProfile::Face> old_faces; 
+	for (S32 face = 0; face < mVolumep->getNumFaces(); face++)
+	{
+		old_faces.push_back(mVolumep->getProfile().mFaces[face]);
+	}
+
+	// Copy the old texture info off to the side, but not in the order in which
+	// they live in the mTextureList, rather in order of ther "face id" which
+	// is the corresponding value of LLVolueParams::LLProfile::mFaces::mIndex.
+	//
+	// Hence, some elements of old_tes::mEntryList will be invalid.  It is
+	// initialized to a size of 9 (max number of possible faces on a volume?)
+	// and only the ones with valid types are filled in.
+	LLPrimTextureList old_tes;
+	old_tes.setSize(9);
+	for (face_bit = 0; face_bit < 9; face_bit++)
+	{
+		cur_mask = 0x1 << face_bit;
+		if (old_face_mask & cur_mask)
+		{
+			S32 te_index = face_index_from_id(cur_mask, old_faces);
+			old_tes.copyTexture(face_bit, *(getTE(te_index)));
+			//llinfos << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << llendl;
+		}
+	}
+
+
 	// build the new object
 	sVolumeManager->unrefVolume(mVolumep);
 	mVolumep = volumep;
 	
 	U32 new_face_mask = mVolumep->mFaceMask;
-	if (old_face_mask != new_face_mask) 
+	S32 i;
+
+	if (old_face_mask == new_face_mask) 
 	{
+		// nothing to do
+		return TRUE;
+	}
+
+	if (mVolumep->getNumFaces() == 0 && new_face_mask != 0)
+	{
+		llwarns << "Object with 0 faces found...INCORRECT!" << llendl;
 		setNumTEs(mVolumep->getNumFaces());
+		return TRUE;
+	}
+
+	// initialize face_mapping
+	S32 face_mapping[9];
+	for (face_bit = 0; face_bit < 9; face_bit++)
+	{
+		face_mapping[face_bit] = face_bit;
+	}
+
+	// The new shape may have more faces than the original, but we can't just
+	// add them to the end -- the ordering matters and it may be that we must
+	// insert the new faces in the middle of the list.  When we add a face it
+	// will pick up the texture/color info of one of the old faces an so we
+	// now figure out which old face info gets mapped to each new face, and 
+	// store in the face_mapping lookup table.
+	for (face_bit = 0; face_bit < 9; face_bit++)
+	{
+		cur_mask = 0x1 << face_bit;
+		if (!(new_face_mask & cur_mask))
+		{
+			// Face doesn't exist in new map.
+			face_mapping[face_bit] = -1;
+			continue;
+		}
+		else if (old_face_mask & cur_mask)
+		{
+			// Face exists in new and old map.
+			face_mapping[face_bit] = face_bit;
+			continue;
+		}
+
+		// OK, how we've got a mismatch, where we have to fill a new face with one from
+		// the old face.
+		if (cur_mask & (LL_FACE_PATH_BEGIN | LL_FACE_PATH_END | LL_FACE_INNER_SIDE))
+		{
+			// It's a top/bottom/hollow interior face.
+			if (old_face_mask & LL_FACE_PATH_END)
+			{
+				face_mapping[face_bit] = 1;
+				continue;
+			}
+			else
+			{
+				S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0;
+				for (i = 0; i < 4; i++)
+				{
+					if (old_face_mask & cur_outer_mask)
+					{
+						face_mapping[face_bit] = 5 + i;
+						break;
+					}
+					cur_outer_mask <<= 1;
+				}
+				if (i == 4)
+				{
+					llwarns << "No path end or outer face in volume!" << llendl;
+				}
+				continue;
+			}
+		}
+
+		if (cur_mask & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
+		{
+			// A cut slice.  Use the hollow interior if we have it.
+			if (old_face_mask & LL_FACE_INNER_SIDE)
+			{
+				face_mapping[face_bit] = 2;
+				continue;
+			}
+
+			// No interior, use the bottom face.
+			// Could figure out which of the outer faces was nearest, but that would be harder.
+			if (old_face_mask & LL_FACE_PATH_END)
+			{
+				face_mapping[face_bit] = 1;
+				continue;
+			}
+			else
+			{
+				S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0;
+				for (i = 0; i < 4; i++)
+				{
+					if (old_face_mask & cur_outer_mask)
+					{
+						face_mapping[face_bit] = 5 + i;
+						break;
+					}
+					cur_outer_mask <<= 1;
+				}
+				if (i == 4)
+				{
+					llwarns << "No path end or outer face in volume!" << llendl;
+				}
+				continue;
+			}
+		}
+
+		// OK, the face that's missing is an outer face...
+		// Pull from the nearest adjacent outer face (there's always guaranteed to be one...
+		S32 cur_outer = face_bit - 5;
+		S32 min_dist = 5;
+		S32 min_outer_bit = -1;
+		S32 i;
+		for (i = 0; i < 4; i++)
+		{
+			if (old_face_mask & (LL_FACE_OUTER_SIDE_0 << i))
+			{
+				S32 dist = abs(i - cur_outer);
+				if (dist < min_dist)
+				{
+					min_dist = dist;
+					min_outer_bit = i + 5;
+				}
+			}
+		}
+		if (-1 == min_outer_bit)
+		{
+			llinfos << (LLVolume *)mVolumep << llendl;
+			llwarns << "Bad!  No outer faces, impossible!" << llendl;
+		}
+		face_mapping[face_bit] = min_outer_bit;
 	}
+	
 
+	setNumTEs(mVolumep->getNumFaces());
+	for (face_bit = 0; face_bit < 9; face_bit++)
+	{
+		// For each possible face type on the new shape we check to see if that
+		// face exists and if it does we create a texture entry that is a copy
+		// of one of the originals.  Since the originals might not have a
+		// matching face, we use the face_mapping lookup table to figure out
+		// which face information to copy.
+		cur_mask = 0x1 << face_bit;
+		if (new_face_mask & cur_mask)
+		{
+			if (-1 == face_mapping[face_bit])
+			{
+				llwarns << "No mapping from old face to new face!" << llendl;
+			}
+
+			S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces);
+			setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit])));
+		}
+	}
 	return TRUE;
 }
 
@@ -1715,10 +1900,10 @@ LLSD LLLightImageParams::asLLSD() const
 
 bool LLLightImageParams::fromLLSD(LLSD& sd)
 {
-	if (sd.has("texture") && sd.has("params") && sd["params"].size() == 3)
+	if (sd.has("texture"))
 	{
 		setLightTexture( sd["texture"] );
-		setParams( LLVector3(sd["params"][0].asReal(), sd["params"][1].asReal(), sd["params"][2].asReal()) );
+		setParams( LLVector3( sd["params"] ) );
 		return true;
 	} 
 	
diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp
index d03150fc78b2b0873eedb452186087296679b61e..1c7de9597545627504c1c85cfb5cbeabc5bc7937 100644
--- a/indra/llprimitive/llprimtexturelist.cpp
+++ b/indra/llprimitive/llprimtexturelist.cpp
@@ -135,13 +135,12 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te)
 {
 	if (S32(index) >= mEntryList.size())
 	{
-		// TODO -- assert here
 		S32 current_size = mEntryList.size();
-		llerrs << "index = " << S32(index) << "  current_size = " << current_size << llendl;
+		llwarns << "ignore copy of index = " << S32(index) << " into texture entry list of size = " << current_size << llendl;
 		return TEM_CHANGE_NONE;
 	}
 
-	// we're changing an existing entry
+		// we're changing an existing entry
 	llassert(mEntryList[index]);
 	delete (mEntryList[index]);
 	if  (&te)
@@ -387,8 +386,18 @@ void LLPrimTextureList::setSize(S32 new_size)
 		mEntryList.resize(new_size);
 		for (S32 index = current_size; index < new_size; ++index)
 		{
-			LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry();
-			mEntryList[index] = new_entry;
+			if (current_size > 0
+				&& mEntryList[current_size - 1])
+			{
+				// copy the last valid entry for the new one
+				mEntryList[index] = mEntryList[current_size - 1]->newCopy();
+			}
+			else
+			{
+				// no valid enries to copy, so we new one up
+				LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry();
+				mEntryList[index] = new_entry;
+			}
 		}
 	}
 	else if (new_size < current_size)
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index b534939dfc436d741731d62f4784df083ce0dc93..f75f1d9b8cd4d1e03102aae060039510f0bee670 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -35,7 +35,7 @@
 #include "lluuid.h"
 #include "llmediaentry.h"
 #include "lltextureentry.h"
-#include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "v4color.h"
 
 const U8 DEFAULT_BUMP_CODE = 0;  // no bump or shininess
@@ -646,3 +646,9 @@ LLUUID LLTextureEntry::getAgentIDFromMediaVersionString(const std::string &versi
     }
     return id;
 }
+
+//static
+bool LLTextureEntry::isMediaVersionString(const std::string &version_string)
+{
+	return std::string::npos != version_string.find(MEDIA_VERSION_STRING_PREFIX);
+}
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index 8d2834f78c5a4218718dd55154059da8531e73a8..d6366b9bb253c74ada0048c44d8944c4d4656dd9 100644
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -171,7 +171,9 @@ class LLTextureEntry
     static U32 getVersionFromMediaVersionString(const std::string &version_string);
     // Given a media version string, return the UUID of the agent
     static LLUUID getAgentIDFromMediaVersionString(const std::string &version_string);
-
+	// Return whether or not the given string is actually a media version
+	static bool isMediaVersionString(const std::string &version_string);
+	
 	// Media flags
 	enum { MF_NONE = 0x0, MF_HAS_MEDIA = 0x1 };
 
diff --git a/indra/llprimitive/tests/llmediaentry_test.cpp b/indra/llprimitive/tests/llmediaentry_test.cpp
index 72478d0459112198b7a7f2e6282d456965ce6608..9ce65609237884ed5c888e6b172043b02c61ee51 100644
--- a/indra/llprimitive/tests/llmediaentry_test.cpp
+++ b/indra/llprimitive/tests/llmediaentry_test.cpp
@@ -157,7 +157,7 @@ namespace tut
 
     void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual)
     {
-        if (! llsd_equals(expected, actual))
+        if (!tut::llsd_equals(expected, actual))
         {
             std::string message = msg;
             message += ": actual: ";
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index c9163d28906999b20acf48dafeda15dd941b2e13..793a526c2602f9c710f99d8e153600baa6d8edae 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -893,6 +893,13 @@ LLFontGL* LLFontGL::getFontByName(const std::string& name)
 	}
 }
 
+//static
+LLFontGL* LLFontGL::getFontDefault()
+{
+	return getFontSansSerif(); // Fallback to sans serif as default font
+}
+
+
 // static 
 std::string LLFontGL::getFontPathSystem()
 {
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index a278d88287042d39f8e68de92f90130e6fd1ce88..5f2c86c6c129ffa887aeaf695822f4c75c6cdec7 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -165,6 +165,7 @@ class LLFontGL
 	static LLFontGL* getFont(const LLFontDescriptor& desc);
 	// Use with legacy names like "SANSSERIF_SMALL" or "OCRA"
 	static LLFontGL* getFontByName(const std::string& name);
+	static LLFontGL* getFontDefault(); // default fallback font
 
 	static std::string getFontPathLocal();
 	static std::string getFontPathSystem();
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index 45573cd817a93f1c634a29107be2d3949927fef6..7a3d6ec4f2d09356a92b0566775a1571ebbe4f04 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -380,7 +380,10 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
 	LLFontDescriptor nearest_exact_desc = *match_desc;
 	nearest_exact_desc.setSize(norm_desc.getSize());
 	font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc);
-	if (it != mFontMap.end())
+	// If we fail to find a font in the fonts directory, it->second might be NULL.
+	// We shouldn't construcnt a font with a NULL mFontFreetype.
+	// This may not be the best solution, but it at least prevents a crash.
+	if (it != mFontMap.end() && it->second != NULL)
 	{
 		llinfos << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << llendl;
 		
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 10315bacf1b90bb81124f7800ac92d9e70d737a2..3400a7238572439f961e3b3148c56c7dd8bfe79f 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -593,8 +593,6 @@ void LLGLManager::shutdownGL()
 // these are used to turn software blending on. They appear in the Debug/Avatar menu
 // presence of vertex skinning/blending or vertex programs will set these to FALSE by default.
 
-extern LLCPUInfo gSysCPU;
-
 void LLGLManager::initExtensions()
 {
 #if LL_MESA_HEADLESS
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index f4d1284095fdccc1ea986916b26c8a442506c96e..f0b4436df584d87a8760421caa90d9c729f500cc 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -43,6 +43,7 @@ set(llui_SOURCE_FILES
     llflatlistview.cpp
     llfloater.cpp
     llfloaterreg.cpp
+    llfloaterreglistener.cpp
     llflyoutbutton.cpp 
     llfocusmgr.cpp
     llfunctorregistry.cpp
@@ -58,6 +59,7 @@ set(llui_SOURCE_FILES
     llmultislider.cpp
     llmultisliderctrl.cpp
     llnotifications.cpp
+    llnotificationslistener.cpp
     llpanel.cpp
     llprogressbar.cpp
     llradiogroup.cpp
@@ -127,6 +129,7 @@ set(llui_HEADER_FILES
     llflatlistview.h
     llfloater.h
     llfloaterreg.h
+    llfloaterreglistener.h
     llflyoutbutton.h 
     llfocusmgr.h
     llfunctorregistry.h
@@ -145,6 +148,7 @@ set(llui_HEADER_FILES
     llmultisliderctrl.h
     llmultislider.h
     llnotifications.h
+    llnotificationslistener.h
     llpanel.h
     llprogressbar.h
     llradiogroup.h
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 285ce82d2d61cfccfee88ff0a4fadfbab39b95b4..e0053b4cc70ce0a5a64ec4d4eb057c759e1c5ec3 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -120,6 +120,11 @@ void LLConsole::setFontSize(S32 size_index)
 	{
 		mFont = LLFontGL::getFontSansSerifHuge();
 	}
+	// Make sure the font exists
+	if (mFont == NULL)
+	{
+		mFont = LLFontGL::getFontDefault();
+	}
 	
 	for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
 	{
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 0c0c5921ceb16128b8b0392069049d3ece32bd02..021e2e94ac6cd2450cd04b0957a765ef44010a23 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -61,6 +61,7 @@
 #include "lltrans.h"
 #include "llhelp.h"
 #include "llmultifloater.h"
+#include "llsdutil.h"
 
 // use this to control "jumping" behavior when Ctrl-Tabbing
 const S32 TABBED_FLOATER_OFFSET = 0;
@@ -132,6 +133,16 @@ LLFloater::handle_map_t	LLFloater::sFloaterMap;
 
 LLFloaterView* gFloaterView = NULL;
 
+/*==========================================================================*|
+// DEV-38598: The fundamental problem with this operation is that it can only
+// support a subset of LLSD values. While it's plausible to compare two arrays
+// lexicographically, what strict ordering can you impose on maps?
+// (LLFloaterTOS's current key is an LLSD map.)
+
+// Of course something like this is necessary if you want to build a std::set
+// or std::map with LLSD keys. Fortunately we're getting by with other
+// container types for now.
+
 //static
 bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
 {
@@ -159,32 +170,11 @@ bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
 	else
 		return false; // no valid operation for Binary
 }
+|*==========================================================================*/
 
 bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b)
 {
-	if (a.type() != b.type())
-	{
-		//llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl;
-		return false;
-	}
-	else if (a.isUndefined())
-		return true;
-	else if (a.isInteger())
-		return a.asInteger() == b.asInteger();
-	else if (a.isReal())
-		return a.asReal() == b.asReal();
-	else if (a.isString())
-		return a.asString() == b.asString();
-	else if (a.isUUID())
-		return a.asUUID() == b.asUUID();
-	else if (a.isDate())
-		return a.asDate() == b.asDate();
-	else if (a.isURI())
-		return a.asString() == b.asString(); // compare URIs as strings
-	else if (a.isBoolean())
-		return a.asBoolean() == b.asBoolean();
-	else
-		return false; // no valid operation for Binary
+	return llsd_equals(a, b);
 }
 
 //************************************
@@ -2629,3 +2619,13 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
 	return true; // *TODO: Error checking
 }
 
+bool LLFloater::isShown() const
+{
+    return ! isMinimized() && isInVisibleChain();
+}
+
+/* static */
+bool LLFloater::isShown(const LLFloater* floater)
+{
+    return floater && floater->isShown();
+}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 123de1239824381b338bb8f2c39e76260f082634..2fdaecf59ad001ee329fba790f7587a663384135 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -87,12 +87,14 @@ friend class LLMultiFloater;
 public:
 	struct KeyCompare
 	{
-		static bool compare(const LLSD& a, const LLSD& b);
+//		static bool compare(const LLSD& a, const LLSD& b);
 		static bool equate(const LLSD& a, const LLSD& b);
+/*==========================================================================*|
 		bool operator()(const LLSD& a, const LLSD& b) const
 		{
 			return compare(a, b);
 		}
+|*==========================================================================*/
 	};
 	
 	enum EFloaterButtons
@@ -183,7 +185,13 @@ friend class LLMultiFloater;
 	void			addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE);
 	LLFloater*		getDependee() { return (LLFloater*)mDependeeHandle.get(); }
 	void		removeDependentFloater(LLFloater* dependent);
-	BOOL			isMinimized()					{ return mMinimized; }
+	BOOL			isMinimized() const				{ return mMinimized; }
+	/// isShown() differs from getVisible() in that isShown() also considers
+	/// isMinimized(). isShown() is true only if visible and not minimized.
+	bool			isShown() const;
+	/// The static isShown() can accept a NULL pointer (which of course
+	/// returns false). When non-NULL, it calls the non-static isShown().
+	static bool		isShown(const LLFloater* floater);
 	BOOL			isFrontmost();
 	BOOL			isDependent()					{ return !mDependeeHandle.isDead(); }
 	void			setCanMinimize(BOOL can_minimize);
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 815260dff3e721c8015a662ef1ffd576dd022bb7..3c5a8a69216cb34de310536e3be3b962475a9f31 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -36,6 +36,7 @@
 
 #include "llfloater.h"
 #include "llmultifloater.h"
+#include "llfloaterreglistener.h"
 
 //*******************************************************
 
@@ -45,6 +46,8 @@ LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
 LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
 std::map<std::string,std::string> LLFloaterReg::sGroupMap;
 
+static LLFloaterRegListener sFloaterRegListener("LLFloaterReg");
+
 //*******************************************************
 
 //static
@@ -249,7 +252,7 @@ bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key)
 bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
 {
 	LLFloater* instance = findInstance(name, key); 
-	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
+	if (LLFloater::isShown(instance))
 	{
 		// When toggling *visibility*, close the host instead of the floater when hosted
 		if (instance->getHost())
@@ -269,14 +272,7 @@ bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
 bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key)
 {
 	LLFloater* instance = findInstance(name, key); 
-	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
-	{
-		return true;
-	}
-	else
-	{
-		return false;
-	}
+	return LLFloater::isShown(instance);
 }
 
 //static
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 7edac43c96b45701e89d5a4364da8776397b972a..451bd1dbe3dd00fa0e217d283c56b50ce1918446 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -70,6 +70,7 @@ class LLFloaterReg
 	typedef std::map<std::string, BuildData> build_map_t;
 	
 private:
+	friend class LLFloaterRegListener;
 	static instance_list_t sNullInstanceList;
 	static instance_map_t sInstanceMap;
 	static build_map_t sBuildMap;
diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57d148b5af474025a2fd9bbbc94f816c7850da2a
--- /dev/null
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -0,0 +1,114 @@
+/**
+ * @file   llfloaterreglistener.cpp
+ * @author Nat Goodspeed
+ * @date   2009-08-12
+ * @brief  Implementation for llfloaterreglistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llfloaterreglistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llfloaterreg.h"
+#include "llfloater.h"
+#include "llbutton.h"
+
+LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
+    LLDispatchListener(pumpName, "op")
+{
+    add("getBuildMap",  &LLFloaterRegListener::getBuildMap,  LLSD().insert("reply", LLSD()));
+    LLSD requiredName;
+    requiredName["name"] = LLSD();
+    add("showInstance", &LLFloaterRegListener::showInstance, requiredName);
+    add("hideInstance", &LLFloaterRegListener::hideInstance, requiredName);
+    add("toggleInstance", &LLFloaterRegListener::toggleInstance, requiredName);
+    LLSD requiredNameButton;
+    requiredNameButton["name"] = LLSD();
+    requiredNameButton["button"] = LLSD();
+    add("clickButton", &LLFloaterRegListener::clickButton, requiredNameButton);
+}
+
+void LLFloaterRegListener::getBuildMap(const LLSD& event) const
+{
+    // Honor the "reqid" convention by echoing event["reqid"] in our reply packet.
+    LLReqID reqID(event);
+    LLSD reply(reqID.makeResponse());
+    // Build an LLSD map that mirrors sBuildMap. Since we have no good way to
+    // represent a C++ callable in LLSD, the only part of BuildData we can
+    // store is the filename. For each LLSD map entry, it would be more
+    // extensible to store a nested LLSD map containing a single key "file" --
+    // but we don't bother, simply storing the string filename instead.
+    for (LLFloaterReg::build_map_t::const_iterator mi(LLFloaterReg::sBuildMap.begin()),
+                                                   mend(LLFloaterReg::sBuildMap.end());
+         mi != mend; ++mi)
+    {
+        reply[mi->first] = mi->second.mFile;
+    }
+    // Send the reply to the LLEventPump named in event["reply"].
+    LLEventPumps::instance().obtain(event["reply"]).post(reply);
+}
+
+void LLFloaterRegListener::showInstance(const LLSD& event) const
+{
+    LLFloaterReg::showInstance(event["name"], event["key"], event["focus"]);
+}
+
+void LLFloaterRegListener::hideInstance(const LLSD& event) const
+{
+    LLFloaterReg::hideInstance(event["name"], event["key"]);
+}
+
+void LLFloaterRegListener::toggleInstance(const LLSD& event) const
+{
+    LLFloaterReg::toggleInstance(event["name"], event["key"]);
+}
+
+void LLFloaterRegListener::clickButton(const LLSD& event) const
+{
+    // If the caller requests a reply, build the reply.
+    LLReqID reqID(event);
+    LLSD reply(reqID.makeResponse());
+
+    LLFloater* floater = LLFloaterReg::findInstance(event["name"], event["key"]);
+    if (! LLFloater::isShown(floater))
+    {
+        reply["type"]  = "LLFloater";
+        reply["name"]  = event["name"];
+        reply["key"]   = event["key"];
+        reply["error"] = floater? "!isShown()" : "NULL";
+    }
+    else
+    {
+        // Here 'floater' points to an LLFloater instance with the specified
+        // name and key which isShown().
+        LLButton* button = floater->findChild<LLButton>(event["button"]);
+        if (! LLButton::isAvailable(button))
+        {
+            reply["type"]  = "LLButton";
+            reply["name"]  = event["button"];
+            reply["error"] = button? "!isAvailable()" : "NULL";
+        }
+        else
+        {
+            // Here 'button' points to an isAvailable() LLButton child of
+            // 'floater' with the specified button name. Pretend to click it.
+            button->onCommit();
+            // Leave reply["error"] isUndefined(): no error, i.e. success.
+        }
+    }
+
+    // Send a reply only if caller asked for a reply.
+    LLSD replyPump(event["reply"]);
+    if (replyPump.isString())       // isUndefined() if absent
+    {
+        LLEventPumps::instance().obtain(replyPump).post(reply);
+    }
+}
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..304ecd10904aebd567289db04c69c7da45136318
--- /dev/null
+++ b/indra/llui/llfloaterreglistener.h
@@ -0,0 +1,36 @@
+/**
+ * @file   llfloaterreglistener.h
+ * @author Nat Goodspeed
+ * @date   2009-08-12
+ * @brief  Wrap (subset of) LLFloaterReg API with an event API
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLFLOATERREGLISTENER_H)
+#define LL_LLFLOATERREGLISTENER_H
+
+#include "lleventdispatcher.h"
+#include <string>
+
+class LLSD;
+
+/// Event API wrapper for LLFloaterReg
+class LLFloaterRegListener: public LLDispatchListener
+{
+public:
+    /// As all public LLFloaterReg methods are static, there's no point in
+    /// binding an LLFloaterReg instance.
+    LLFloaterRegListener(const std::string& pumpName);
+
+private:
+    void getBuildMap(const LLSD& event) const;
+    void showInstance(const LLSD& event) const;
+    void hideInstance(const LLSD& event) const;
+    void toggleInstance(const LLSD& event) const;
+    void clickButton(const LLSD& event) const;
+};
+
+#endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
diff --git a/indra/llui/llfunctorregistry.cpp b/indra/llui/llfunctorregistry.cpp
index 0c5b1655b1011a4d49c7a0094a9446d85931cd0d..5f9644f258476bb8b74757705042e88ba035956d 100644
--- a/indra/llui/llfunctorregistry.cpp
+++ b/indra/llui/llfunctorregistry.cpp
@@ -31,6 +31,7 @@
  * $/LicenseInfo$
  **/
 
+#include "linden_common.h"
 #include "llfunctorregistry.h"
 
 // This is a default functor always resident in the system.
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index f77ec5f4c7658f2c334e4ad8056fcee2d874ee1b..387af05935738ea896ce03bd70738679999bc338 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -297,5 +297,16 @@ void LLModalDialog::onAppFocusGained()
 	}
 }
 
-
-
+void LLModalDialog::shutdownModals()
+{
+	// This method is only for use during app shutdown. ~LLModalDialog()
+	// checks sModalStack, and if the dialog instance is still there, it
+	// crumps with "Attempt to delete dialog while still in sModalStack!" But
+	// at app shutdown, all bets are off. If the user asks to shut down the
+	// app, we shouldn't have to care WHAT's open. Put differently, if a modal
+	// dialog is so crucial that we can't let the user terminate until s/he
+	// addresses it, we should reject a termination request. The current state
+	// of affairs is that we accept it, but then produce an llerrs popup that
+	// simply makes our software look unreliable.
+	sModalStack.clear();
+}
diff --git a/indra/llui/llmodaldialog.h b/indra/llui/llmodaldialog.h
index 9d716a1880455d88190412b24aedfe083eab62a7..863572fb5acc110e5b508f7c9394e2a8f7b0d62e 100644
--- a/indra/llui/llmodaldialog.h
+++ b/indra/llui/llmodaldialog.h
@@ -73,7 +73,8 @@ class LLModalDialog : public LLFloater
 	static void		onAppFocusGained();
 
 	static S32		activeCount() { return sModalStack.size(); }
-	
+	static void		shutdownModals();
+
 protected:
 	void			centerOnScreen();
 
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index a0e51151c942774f39d73fe1d9538e942c2f18ee..ef222bad608cad3379b25c5c964964acb4a4312a 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -40,6 +40,7 @@
 #include "lldir.h"
 #include "llsdserialize.h"
 #include "lltrans.h"
+#include "llnotificationslistener.h"
 
 #include <algorithm>
 #include <boost/regex.hpp>
@@ -945,6 +946,8 @@ LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFil
 									mIgnoreAllNotifications(false)
 {
 	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
+
+    mListener.reset(new LLNotificationsListener(*this));
 }
 
 
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index cd05db3c30ea8d9c3ce861165023b9f8e0c9a21e..0d7cb74f7044602874487569445acfff12503b82 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -102,6 +102,7 @@
 #include "llfunctorregistry.h"
 #include "llpointer.h"
 #include "llinitparam.h"
+#include "llnotificationslistener.h"
 
 class LLNotification;
 typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
@@ -812,9 +813,19 @@ class LLNotificationChannel :
 	LLNotificationComparator mComparator;
 };
 
-
+// An interface class to provide a clean linker seam to the LLNotifications class.
+// Extend this interface as needed for your use of LLNotifications.
+class LLNotificationsInterface
+{
+public:
+	virtual LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						LLNotificationFunctorRegistry::ResponseFunctor functor) = 0;
+};
 
 class LLNotifications : 
+	public LLNotificationsInterface,
 	public LLSingleton<LLNotifications>, 
 	public LLNotificationChannelBase
 {
@@ -838,7 +849,7 @@ class LLNotifications :
 						const LLSD& substitutions, 
 						const LLSD& payload, 
 						const std::string& functor_name);
-	LLNotificationPtr add(const std::string& name, 
+	/* virtual */ LLNotificationPtr add(const std::string& name, 
 						const LLSD& substitutions, 
 						const LLSD& payload, 
 						LLNotificationFunctorRegistry::ResponseFunctor functor);
@@ -917,6 +928,8 @@ class LLNotifications :
 	GlobalStringMap mGlobalStrings;
 
 	bool mIgnoreAllNotifications;
+
+    boost::scoped_ptr<LLNotificationsListener> mListener;
 };
 
 
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..75f4d6177dc3958e5b1fc0b9f54dc6133e8a7ccb
--- /dev/null
+++ b/indra/llui/llnotificationslistener.cpp
@@ -0,0 +1,55 @@
+/**
+ * @file   llnotificationslistener.cpp
+ * @author Brad Kittenbrink
+ * @date   2009-07-08
+ * @brief  Implementation for llnotificationslistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llnotificationslistener.h"
+
+#include "llnotifications.h"
+
+LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
+    LLDispatchListener("LLNotifications", "op"),
+    mNotifications(notifications)
+{
+    add("requestAdd", &LLNotificationsListener::requestAdd);
+}
+
+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);
+}
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f71a7c7817dc6490592e9c570c4f386d8977788
--- /dev/null
+++ b/indra/llui/llnotificationslistener.h
@@ -0,0 +1,34 @@
+/**
+ * @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=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLNOTIFICATIONSLISTENER_H
+#define LL_LLNOTIFICATIONSLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLNotifications;
+class LLSD;
+
+class LLNotificationsListener : public LLDispatchListener
+{
+public:
+    LLNotificationsListener(LLNotifications & notifications);
+
+    void requestAdd(LLSD const & event_data) const;
+
+private:
+	void NotificationResponder(const std::string& replypump, 
+							   const LLSD& notification, 
+							   const LLSD& response) const;
+	LLNotifications & mNotifications;
+};
+
+#endif // LL_LLNOTIFICATIONSLISTENER_H
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index 07b68953789ab4f1bb45db8d8ef48685e099ad34..f86776384ada0dae375bdc0b913b226a4e4f20af 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -43,6 +43,8 @@
 #include "lluictrlfactory.h"
 
 static LLDefaultChildRegistry::Register<LLSlider> r1("slider_bar");
+//FIXME: make this into an unregistered template so that code constructed sliders don't
+// have ambigious template lookup problem
 
 LLSlider::Params::Params()
 :	track_color("track_color"),
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 3ecf62908284aa561e6bc804816f85626ec0f403..ed22c0a47f8ac07ea994edf0d85e6fb0102e18af 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -396,4 +396,3 @@ void LLSliderCtrl::reportInvalidData()
 	make_ui_sound("UISndBadKeystroke");
 }
 
-
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index f253857851549eb61309540d0c103e019d511199..da9384f8769389ee747691e8eac35963763665e2 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1952,7 +1952,12 @@ namespace LLInitParam
 				return fontp;
 			}
 		}
-
+		
+		if (mData.mValue == NULL)
+		{
+			mData.mValue = LLFontGL::getFontDefault();
+		}
+		
 		// default to current value
 		return mData.mValue;
 	}
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 31f12fe312cab8c2755a7fd314b02d071b5e000b..fe7fd59de80e3a4c32288bfc022bf5ae84d22484 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -437,6 +437,18 @@ void LLView::setEnabled(BOOL enabled)
 	mEnabled = enabled;
 }
 
+//virtual
+bool LLView::isAvailable() const
+{
+    return isInEnabledChain() && isInVisibleChain();
+}
+
+//static
+bool LLView::isAvailable(const LLView* view)
+{
+    return view && view->isAvailable();
+}
+
 //virtual
 BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text )
 {
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 73146b2c1f5d0b242aedc88a79eb636124f38d9b..c3b442e0224383803325c76ab3658da33d70892e 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -304,6 +304,11 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	BOOL			getVisible() const			{ return mVisible; }
 	virtual void	setEnabled(BOOL enabled);
 	BOOL			getEnabled() const			{ return mEnabled; }
+	/// 'available' in this context means 'visible and enabled': in other
+	/// words, can a user actually interact with this?
+	virtual bool	isAvailable() const;
+	/// The static isAvailable() tests an LLView* that could be NULL.
+	static bool		isAvailable(const LLView* view);
 	U8              getSoundFlags() const       { return mSoundFlags; }
 
 	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp
index 93ac1203023c45ca049a259f1143718f8e183b51..315baa001d2a6a0c01596ac6e7d1a8e1e062af90 100755
--- a/indra/llvfs/llpidlock.cpp
+++ b/indra/llvfs/llpidlock.cpp
@@ -62,7 +62,7 @@ class LLPidLockFile
 			mSaving(FALSE), mWaiting(FALSE), 
 			mClean(TRUE), mPID(getpid())
 		{
-			mLockName = gDirUtilp->getTempDir() + "/savelock";
+			mLockName = gDirUtilp->getTempDir() + gDirUtilp->getDirDelimiter() + "savelock";
 		}
 		bool requestLock(LLNameTable<void *> *name_table, bool autosave,
 						bool force_immediate=FALSE, F32 timeout=300.0);
diff --git a/indra/llwindow/llwindowmesaheadless.cpp b/indra/llwindow/llwindowmesaheadless.cpp
index 7ee09f4a24fcf37a9864bb43fe45bd2ac4b98d11..48736d920706c2d88246b75191ffb5a385318657 100644
--- a/indra/llwindow/llwindowmesaheadless.cpp
+++ b/indra/llwindow/llwindowmesaheadless.cpp
@@ -45,7 +45,7 @@ U16 *gMesaBuffer = NULL;
 // LLWindowMesaHeadless
 //
 LLWindowMesaHeadless::LLWindowMesaHeadless(LLWindowCallbacks* callbacks,
-			 				 const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
+                                           const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
 							 U32 flags,  BOOL fullscreen, BOOL clearBg,
 							 BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
 	: LLWindow(callbacks, fullscreen, flags)
diff --git a/indra/llwindow/llwindowmesaheadless.h b/indra/llwindow/llwindowmesaheadless.h
index 22e0ec126d507957b52dd863e047d4d3c16c0d82..46b62b914c092fc507175e94726e92323cd881a4 100644
--- a/indra/llwindow/llwindowmesaheadless.h
+++ b/indra/llwindow/llwindowmesaheadless.h
@@ -99,7 +99,7 @@ class LLWindowMesaHeadless : public LLWindow
 	/*virtual*/ void bringToFront() {};
 	
 	LLWindowMesaHeadless(LLWindowCallbacks* callbacks,
-			      const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
+                         const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
 				  U32 flags,  BOOL fullscreen, BOOL clearBg,
 				  BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth);
 	~LLWindowMesaHeadless();
diff --git a/indra/llxuixml/lluicolor.cpp b/indra/llxuixml/lluicolor.cpp
index 856c05cf4af5d660b575dad16756db5552371549..424d878a6b23a9c46a7ed360005670145bd0b096 100644
--- a/indra/llxuixml/lluicolor.cpp
+++ b/indra/llxuixml/lluicolor.cpp
@@ -7,6 +7,8 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
+
 #include "lluicolor.h"
 
 LLUIColor::LLUIColor()
diff --git a/indra/lscript/lscript_byteformat.h b/indra/lscript/lscript_byteformat.h
index ba2c46bef253bf3a0fa685b7f49b8e26710159dc..a54ebd5831a122350e28e834443a8737a12ac562 100644
--- a/indra/lscript/lscript_byteformat.h
+++ b/indra/lscript/lscript_byteformat.h
@@ -556,7 +556,7 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] =
 // http_request string constants
 extern const char* URL_REQUEST_GRANTED;
 extern const char* URL_REQUEST_DENIED;
-extern const U64 LSL_HTTP_REQUEST_TIMEOUT;
+extern const U64 LSL_HTTP_REQUEST_TIMEOUT_USEC;
 
 #endif
 
diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp
index 98146d6f2bd9ba299ee838a6f5b55dd3ba8289a0..3b8bbbe805f57d305624ec53c6e119726a37fcb1 100644
--- a/indra/lscript/lscript_compile/lscript_tree.cpp
+++ b/indra/lscript/lscript_compile/lscript_tree.cpp
@@ -631,9 +631,7 @@ static void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetTy
 		switch(targetType)
 		{
 		case LST_INTEGER:
-			//fprintf(fp, "call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32)\n");
-			fprintf(fp, "conv.i4\n"); // TODO replace this line with the above
-			// we the entire grid is > 1.25.1
+			fprintf(fp, "call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32)\n");
 			break;
 		case LST_STRING:
 			fprintf(fp, "call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ToString(float32)\n");
@@ -8375,10 +8373,18 @@ void LLScriptStateChange::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp
 			chunk->addInteger(mIdentifier->mScopeEntry->mCount);
 		}
 		break;
+	case LSCP_TYPE:
+		mReturnType = basetype;
+		break;
 	case LSCP_EMIT_CIL_ASSEMBLY:
 		fprintf(fp, "ldarg.0\n");
 		fprintf(fp, "ldstr \"%s\"\n", mIdentifier->mName);
 		fprintf(fp, "call instance void class [LslUserScript]LindenLab.SecondLife.LslUserScript::ChangeState(string)\n");
+		// We are doing a state change. In the LSL interpreter, this is basically a longjmp. We emulate it
+		// here using a call to the ChangeState followed by a short cut return of the current method. To
+		// maintain type safety we need to push an arbitrary variable of the current method's return type
+		// onto the stack before returning. This will be ignored and discarded.
+		print_cil_init_variable(fp, mReturnType);
 		fprintf(fp, "ret\n");
 		break;
 	default:
diff --git a/indra/lscript/lscript_compile/lscript_tree.h b/indra/lscript/lscript_compile/lscript_tree.h
index 12c16908af2b6aab5313e63014dbd0b9b6979702..a667e1eb5b796fbbea67a1dd34793a7e06df6f54 100644
--- a/indra/lscript/lscript_compile/lscript_tree.h
+++ b/indra/lscript/lscript_compile/lscript_tree.h
@@ -1888,6 +1888,7 @@ class LLScriptStateChange : public LLScriptStatement
 	S32 getSize();
 
 	LLScriptIdentifier *mIdentifier;
+	LSCRIPTType mReturnType;
 };
 
 class LLScriptJump : public LLScriptStatement
diff --git a/indra/lscript/lscript_execute.h b/indra/lscript/lscript_execute.h
index 245fc320d1154ee84b0847bebba58adf2fb69332..96855abea0fdf7f9cd60a99c3df828277b1b5d83 100644
--- a/indra/lscript/lscript_execute.h
+++ b/indra/lscript/lscript_execute.h
@@ -371,8 +371,7 @@ class LLScriptExecute
 {
 public:
 	LLScriptExecute();
-	virtual ~LLScriptExecute() {;}
-
+	virtual ~LLScriptExecute()  = 0;
 	virtual S32 getVersion() const = 0;
 	virtual void deleteAllEvents() = 0;
 	virtual void addEvent(LLScriptDataCollection* event) = 0;
diff --git a/indra/lscript/lscript_execute/llscriptresource.cpp b/indra/lscript/lscript_execute/llscriptresource.cpp
index 6c4776c2e446cb1021d789c7b39221ed24f94ccc..cd3696ab3faddee6970fef502d4dc7c05ecb4c0b 100644
--- a/indra/lscript/lscript_execute/llscriptresource.cpp
+++ b/indra/lscript/lscript_execute/llscriptresource.cpp
@@ -30,6 +30,8 @@
  * $/LicenseInfo$
  */
 
+#include "linden_common.h"
+
 #include "llscriptresource.h"
 #include "llerror.h"
 
diff --git a/indra/lscript/lscript_execute/lscript_execute.cpp b/indra/lscript/lscript_execute/lscript_execute.cpp
index 2fd81210c069ef68545d80e26fd51dbd03db552f..e849fa9a6e8532586fc8d70913b157e62917be7c 100644
--- a/indra/lscript/lscript_execute/lscript_execute.cpp
+++ b/indra/lscript/lscript_execute/lscript_execute.cpp
@@ -41,6 +41,8 @@
 #include "lscript_library.h"
 #include "lscript_heapruntime.h"
 #include "lscript_alloc.h"
+#include "llstat.h"
+
 
 // Static
 const	S32	DEFAULT_SCRIPT_TIMER_CHECK_SKIP = 4;
@@ -72,7 +74,7 @@ const char* URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED";
 const char* URL_REQUEST_DENIED = "URL_REQUEST_DENIED";
 
 // HTTP Requests to LSL scripts will time out after 25 seconds.
-const U64 LSL_HTTP_REQUEST_TIMEOUT = 25 * USEC_PER_SEC; 
+const U64 LSL_HTTP_REQUEST_TIMEOUT_USEC = 25 * USEC_PER_SEC; 
 
 LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp)
 {
@@ -110,6 +112,7 @@ LLScriptExecuteLSL2::LLScriptExecuteLSL2(const U8* bytecode, U32 bytecode_size)
 	init();
 }
 
+LLScriptExecute::~LLScriptExecute() {}
 LLScriptExecuteLSL2::~LLScriptExecuteLSL2()
 {
 	delete[] mBuffer;
@@ -4234,19 +4237,16 @@ S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer)
 	return 4;
 }
 
-BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
+
+// Shared code for run_calllib() and run_calllib_two_byte()
+BOOL run_calllib_common(U8 *buffer, S32 &offset, const LLUUID &id, U16 arg)
 {
-	if (b_print)
-		printf("[0x%X]\tCALLLIB ", offset);
-	offset++;
-	U8 arg = safe_instruction_bytestream2byte(buffer, offset);
-	if (arg >= (U8)gScriptLibrary.mFunctions.size())
+	if (arg >= gScriptLibrary.mFunctions.size())
 	{
 		set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
 		return FALSE;
 	}
-	if (b_print)
-		printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg].mName);
+	LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg];
 
 	// pull out the arguments and the return values
 	LLScriptLibData	*arguments = NULL;
@@ -4254,14 +4254,14 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
 
 	S32 i, number;
 
-	if (gScriptLibrary.mFunctions[arg].mReturnType)
+	if (function.mReturnType)
 	{
 		returnvalue = new LLScriptLibData;
 	}
 
-	if (gScriptLibrary.mFunctions[arg].mArgs)
+	if (function.mArgs)
 	{
-		number = (S32)strlen(gScriptLibrary.mFunctions[arg].mArgs);		/*Flawfinder: ignore*/
+		number = (S32)strlen(function.mArgs);		//Flawfinder: ignore
 		arguments = new LLScriptLibData[number];
 	}
 	else
@@ -4271,23 +4271,18 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
 
 	for (i = number - 1; i >= 0; i--)
 	{
-		lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg].mArgs[i]);
+		lscript_pop_variable(&arguments[i], buffer, function.mArgs[i]);
 	}
 
-	if (b_print)
-	{
-		printf("See LSLTipText_%s in strings.xml for usage\n", gScriptLibrary.mFunctions[arg].mName);
-	}
+	// Actually execute the function call
+	function.mExecFunc(returnvalue, arguments, id);
 
-	{
-		gScriptLibrary.mFunctions[arg].mExecFunc(returnvalue, arguments, id);
-	}
-	add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg].mEnergyUse);
-	add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg].mSleepTime);
+	add_register_fp(buffer, LREG_ESR, -(function.mEnergyUse));
+	add_register_fp(buffer, LREG_SLR, function.mSleepTime);
 
 	if (returnvalue)
 	{
-		returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg].mReturnType);
+		returnvalue->mType = char2type(*function.mReturnType);
 		lscript_push_return_variable(returnvalue, buffer);
 	}
 
@@ -4304,71 +4299,32 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
 }
 
 
-BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
+BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
 {
-	if (b_print)
-		printf("[0x%X]\tCALLLIB ", offset);
 	offset++;
-	U16 arg = safe_instruction_bytestream2u16(buffer, offset);
-	if (arg >= (U16)gScriptLibrary.mFunctions.size())
+	U16 arg = (U16) safe_instruction_bytestream2byte(buffer, offset);
+	if (b_print &&
+		arg < gScriptLibrary.mFunctions.size())
 	{
-		set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
-		return FALSE;
-	}
-	if (b_print)
-		printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg].mName);
-
-	// pull out the arguments and the return values
-	LLScriptLibData	*arguments = NULL;
-	LLScriptLibData	*returnvalue = NULL;
-
-	S32 i, number;
-
-	if (gScriptLibrary.mFunctions[arg].mReturnType)
-	{
-		returnvalue = new LLScriptLibData;
-	}
-
-	if (gScriptLibrary.mFunctions[arg].mArgs)
-	{
-		number = (S32)strlen(gScriptLibrary.mFunctions[arg].mArgs);		/*Flawfinder: ignore*/
-		arguments = new LLScriptLibData[number];
-	}
-	else
-	{
-		number = 0;
-	}
-
-	for (i = number - 1; i >= 0; i--)
-	{
-		lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg].mArgs[i]);
-	}
-
-	if (b_print)
-	{
-		printf("See LSLTipText_%s in strings.xml for usage\n", gScriptLibrary.mFunctions[arg].mName);
-	}
-
-	{
-		gScriptLibrary.mFunctions[arg].mExecFunc(returnvalue, arguments, id);
+		printf("[0x%X]\tCALLLIB ", offset);
+		LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg];
+		printf("%d (%s)\n", (U32)arg, function.mName);
+		//printf("%s\n", function.mDesc);
 	}
-	add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg].mEnergyUse);
-	add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg].mSleepTime);
+	return run_calllib_common(buffer, offset, id, arg);
+}
 
-	if (returnvalue)
+BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
+{
+	offset++;
+	U16 arg = safe_instruction_bytestream2u16(buffer, offset);
+	if (b_print &&
+		arg < gScriptLibrary.mFunctions.size())
 	{
-		returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg].mReturnType);
-		lscript_push_return_variable(returnvalue, buffer);
+		printf("[0x%X]\tCALLLIB ", (offset-1));
+		LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg];
+		printf("%d (%s)\n", (U32)arg, function.mName);
+		//printf("%s\n", function.mDesc);
 	}
-
-	delete [] arguments;
-	delete returnvalue;
-
-	// reset the BP after calling the library files
-	S32 bp = lscript_pop_int(buffer);
-	set_bp(buffer, bp);
-
-	// pop off the spot for the instruction pointer
-	lscript_poparg(buffer, 4);
-	return FALSE;
+	return run_calllib_common(buffer, offset, id, arg);
 }
diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/media_plugins/quicktime/CMakeLists.txt
index db11c9ae218b7667bd7e71d72cb3a86315c355d3..f0b8f0d16706f5b491d783b45559b0cd9d8d8a31 100644
--- a/indra/media_plugins/quicktime/CMakeLists.txt
+++ b/indra/media_plugins/quicktime/CMakeLists.txt
@@ -56,6 +56,14 @@ add_dependencies(media_plugin_quicktime
   ${LLCOMMON_LIBRARIES}
 )
 
+if (WINDOWS)
+  set_target_properties(
+    media_plugin_quicktime
+    PROPERTIES
+    LINK_FLAGS "/MANIFEST:NO"
+    )
+endif (WINDOWS)
+
 if (QUICKTIME)
 
     add_definitions(-DLL_QUICKTIME_ENABLED=1)
diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
index fbda65120d729708844453c2cc7bb967b349b424..7100d03f051f5c5507b7e23e1c7957b46c06644b 100644
--- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
+++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
@@ -1,981 +1,1077 @@
-/** 
- * @file media_plugin_quicktime.cpp
- * @brief QuickTime plugin for LLMedia API plugin system
- *
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- *
- * Copyright (c) 2008, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llgl.h"
-
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "media_plugin_base.h"
-
-#if LL_QUICKTIME_ENABLED
-
-#if defined(LL_DARWIN)
-	#include <QuickTime/QuickTime.h>
-#elif defined(LL_WINDOWS)
-	#include "MacTypes.h"
-	#include "QTML.h"
-	#include "Movies.h"
-	#include "QDoffscreen.h"
-	#include "FixMath.h"
-#endif
-
-// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
-////////////////////////////////////////////////////////////////////////////////
-//
-class MediaPluginQuickTime : public MediaPluginBase
-{
-public:
-	MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
-	~MediaPluginQuickTime();
-
-	/* virtual */ void receiveMessage(const char *message_string);
-
-private:
-
-	int mNaturalWidth;
-	int mNaturalHeight;
-	Movie mMovieHandle;
-	GWorldPtr mGWorldHandle;
-	ComponentInstance mMovieController;
-	int mCurVolume;
-	bool mMediaSizeChanging;
-	bool mIsLooping;
-	const int mMinWidth;
-	const int mMaxWidth;
-	const int mMinHeight;
-	const int mMaxHeight;
-	F64 mPlayRate;
-
-	enum ECommand {
-		COMMAND_NONE,
-		COMMAND_STOP,
-		COMMAND_PLAY,
-		COMMAND_FAST_FORWARD,
-		COMMAND_FAST_REWIND,
-		COMMAND_PAUSE,
-		COMMAND_SEEK,
-	};
-	ECommand mCommand;
-
-	// Override this to add current time and duration to the message
-	/*virtual*/ void setDirty(int left, int top, int right, int bottom)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
-
-		message.setValueS32("left", left);
-		message.setValueS32("top", top);
-		message.setValueS32("right", right);
-		message.setValueS32("bottom", bottom);
-		
-		if(mMovieHandle)
-		{
-			message.setValueReal("current_time", getCurrentTime());
-			message.setValueReal("duration", getDuration());
-			message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle)));
-		}
-			
-		sendMessage(message);
-	}
-
-
-	static Rect rectFromSize(int width, int height)
-	{
-		Rect result;
-		
-
-		result.left = 0;
-		result.top = 0;
-		result.right = width;
-		result.bottom = height;
-		
-		return result;
-	}
-	
-	Fixed getPlayRate(void)
-	{
-		Fixed result;
-		if(mPlayRate == 0.0f)
-		{
-			// Default to the movie's preferred rate
-			result = GetMoviePreferredRate(mMovieHandle);
-			if(result == 0)
-			{
-				// Don't return a 0 play rate, ever.
-				std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl;
-				result = X2Fix(1.0f);
-			}
-		}
-		else
-		{
-			result = X2Fix(mPlayRate);
-		}
-		
-		return result;
-	}
-	
-	void load( const std::string url )
-	{
-		if ( url.empty() )
-			return;
-		
-		// Stop and unload any existing movie before starting another one.
-		unload();
-			
-		setStatus(STATUS_LOADING);
-		
-		//In case std::string::c_str() makes a copy of the url data,
-		//make sure there is memory to hold it before allocating memory for handle.
-		//if fails, NewHandleClear(...) should return NULL.
-		const char* url_string = url.c_str() ;
-		Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) );
-		if ( NULL == handle || noErr != MemError() || NULL == *handle )
-		{
-			setStatus(STATUS_ERROR);
-			return;
-		}
-
-		BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) );
-
-		OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType );
-		DisposeHandle( handle );
-		if ( noErr != err )
-		{
-			setStatus(STATUS_ERROR);
-			return;
-		};
-
-		// do pre-roll actions (typically fired for streaming movies but not always)
-		PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this );
-
-		Rect movie_rect = rectFromSize(mWidth, mHeight);
-
-		// make a new movie controller
-		mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie );
-
-		// movie controller
-		MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this );
-
-		SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize );
-
-		// function that gets called when a frame is drawn
-		SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this );
-
-		setStatus(STATUS_LOADED);
-		
-		sizeChanged();
-	};
-
-	bool unload()
-	{
-		if ( mMovieHandle )
-		{
-			StopMovie( mMovieHandle );
-			if ( mMovieController )
-			{
-				MCMovieChanged( mMovieController, mMovieHandle );
-			};
-		};
-
-		if ( mMovieController )
-		{
-			MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this );
-			DisposeMovieController( mMovieController );
-			mMovieController = NULL;
-		};
-
-		if ( mMovieHandle )
-		{
-			SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this );
-			DisposeMovie( mMovieHandle );
-			mMovieHandle = NULL;
-		};
-
-		if ( mGWorldHandle )
-		{
-			DisposeGWorld( mGWorldHandle );
-			mGWorldHandle = NULL;
-		};
-		
-		setStatus(STATUS_NONE);
-
-		return true;
-	}
-
-	bool navigateTo( const std::string url )
-	{
-		unload();
-		load( url );
-		
-		return true;
-	};
-
-	bool sizeChanged()
-	{
-		if ( ! mMovieHandle )
-			return false;
-		
-		// Check to see whether the movie's natural size has updated
-		{
-			int width, height;
-			getMovieNaturalSize(&width, &height);
-			if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight)))
-			{
-				mNaturalWidth = width;
-				mNaturalHeight = height;
-
-				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request");
-				message.setValue("name", mTextureSegmentName);
-				message.setValueS32("width", width);
-				message.setValueS32("height", height);
-				sendMessage(message);
-				//std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl;
-			}
-		}
-		
-		// sanitize destination size
-		Rect dest_rect = rectFromSize(mWidth, mHeight);
-
-		// media depth won't change
-		int depth_bits = mDepth * 8;
-		long rowbytes = mDepth * mTextureWidth;
-				
-		GWorldPtr old_gworld_handle = mGWorldHandle;
-
-		if(mPixels != NULL)
-		{
-			// We have pixels.  Set up a GWorld pointing at the texture.
-			OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes);
-			if ( noErr != result )
-			{
-				// TODO: unrecoverable??  throw exception?  return something?
-				return false;
-			}
-		}
-		else
-		{
-			// We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally.
-			Rect tempRect = rectFromSize(1, 1);
-			OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0);
-			if ( noErr != result )
-			{
-				// TODO: unrecoverable??  throw exception?  return something?
-				return false;
-			}
-		}
-
-		SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) );
-
-		// If the GWorld was already set up, delete it.
-		if(old_gworld_handle != NULL)
-		{
-			DisposeGWorld( old_gworld_handle );
-		}
-		
-		// Set up the movie display matrix
-		{
-			// scale movie to fit rect and invert vertically to match opengl image format
-			MatrixRecord transform;
-			SetIdentityMatrix( &transform );	// transforms are additive so start from identify matrix
-			double scaleX = (double) mWidth / mNaturalWidth;
-			double scaleY = -1.0 * (double) mHeight / mNaturalHeight;
-			double centerX = mWidth / 2.0;
-			double centerY = mHeight / 2.0;
-			ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) );
-			SetMovieMatrix( mMovieHandle, &transform );
-		}
-		
-		// update movie controller
-		if ( mMovieController )
-		{
-			MCSetControllerPort( mMovieController, mGWorldHandle );
-			MCPositionController( mMovieController, &dest_rect, &dest_rect,
-								  mcTopLeftMovie | mcPositionDontInvalidate );
-			MCMovieChanged( mMovieController, mMovieHandle );
-		}
-
-
-		// Emit event with size change so the calling app knows about it too
-		// TODO:
-		//LLMediaEvent event( this );
-		//mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event );
-
-		return true;
-	}
-
-	static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref )
-	{
-		Boolean result = false;
-
-		MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
-
-		switch( action )
-		{
-			// handle window resizing
-			case mcActionControllerSizeChanged:				
-				// Ensure that the movie draws correctly at the new size
-				self->sizeChanged();						
-				break;
-
-			// Block any movie controller actions that open URLs.
-			case mcActionLinkToURL:
-			case mcActionGetNextURL:
-			case mcActionLinkToURLExtended:
-				// Prevent the movie controller from handling the message
-				result = true;
-				break;
-
-			default:
-				break;
-		};
-
-		return result;
-	};
-
-	static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref )
-	{
-		MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
-
-		// IMPORTANT: typically, a consumer who is observing this event will set a flag
-		// when this event is fired then render later. Be aware that the media stream
-		// can change during this period - dimensions, depth, format etc.
-		//LLMediaEvent event( self );
-//		self->updateQuickTime();
-		// TODO ^^^
-
-		if ( self->mWidth > 0 && self->mHeight > 0 )
-			self->setDirty( 0, 0, self->mWidth, self->mHeight );
-
-		return noErr;
-	};
-
-	static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref )
-	{
-		//MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
-
-		// TODO:
-		//LLMediaEvent event( self );
-		//self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event );
-	};
-
-
-	void rewind()
-	{
-		GoToBeginningOfMovie( mMovieHandle );
-		MCMovieChanged( mMovieController, mMovieHandle );
-	};
-
-	bool processState()
-	{
-		if ( mCommand == COMMAND_PLAY )
-		{
-			if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING )
-			{
-				long state = GetMovieLoadState( mMovieHandle );
-
-				if ( state >= kMovieLoadStatePlaythroughOK )
-				{
-					// if the movie is at the end (generally because it reached it naturally)
-					// and we play is requested, jump back to the start of the movie.
-					// note: this is different from having loop flag set.
-					if ( IsMovieDone( mMovieHandle ) )
-					{
-						Fixed rate = X2Fix( 0.0 );
-						MCDoAction( mMovieController, mcActionPlay, (void*)rate );
-						rewind();
-					};
-					
-					MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
-					MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
-					setStatus(STATUS_PLAYING);
-					mCommand = COMMAND_NONE;
-				};
-			};
-		}
-		else
-		if ( mCommand == COMMAND_STOP )
-		{
-			if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED )
-			{
-				if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
-				{
-					Fixed rate = X2Fix( 0.0 );
-					MCDoAction( mMovieController, mcActionPlay, (void*)rate );
-					rewind();
-
-					setStatus(STATUS_LOADED);
-					mCommand = COMMAND_NONE;
-				};
-			};
-		}
-		else
-		if ( mCommand == COMMAND_PAUSE )
-		{
-			if ( mStatus == STATUS_PLAYING )
-			{				
-				if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
-				{
-					Fixed rate = X2Fix( 0.0 );
-					MCDoAction( mMovieController, mcActionPlay, (void*)rate );
-					setStatus(STATUS_PAUSED);
-					mCommand = COMMAND_NONE;
-				};
-			};
-		};
-
-		return true;
-	};
-
-	void play(F64 rate)
-	{
-		mPlayRate = rate;
-		mCommand = COMMAND_PLAY;
-	};
-
-	void stop()
-	{
-		mCommand = COMMAND_STOP;
-	};
-
-	void pause()
-	{
-		mCommand = COMMAND_PAUSE;
-	};
-
-	void getMovieNaturalSize(int *movie_width, int *movie_height)
-	{
-		Rect rect;
-		
-		GetMovieNaturalBoundsRect( mMovieHandle, &rect );
-
-		int width  = ( rect.right - rect.left );
-		int height = ( rect.bottom - rect.top );
-
-		// make sure width and height fall in valid range
-		if ( width < mMinWidth )
-			width = mMinWidth;
-
-		if ( width > mMaxWidth )
-			width = mMaxWidth;
-
-		if ( height < mMinHeight )
-			height = mMinHeight;
-
-		if ( height > mMaxHeight )
-			height = mMaxHeight;
-
-		// return the new rect
-		*movie_width = width;
-		*movie_height = height;
-	}
-	
-	void updateQuickTime(int milliseconds)
-	{
-		if ( ! mMovieHandle )
-			return;
-
-		if ( ! mMovieController )
-			return;
-
-		// service QuickTime
-		// Calling it this way doesn't have good behavior on Windows...
-//		MoviesTask( mMovieHandle, milliseconds );
-		// This was the original, but I think using both MoviesTask and MCIdle is redundant.  Trying with only MCIdle.
-//		MoviesTask( mMovieHandle, 0 );
-
-		MCIdle( mMovieController );
-
-		if ( ! mGWorldHandle )
-			return;
-
-		if ( mMediaSizeChanging )
-			return;
-
-		// update state machine
-		processState();
-
-		// special code for looping - need to rewind at the end of the movie
-		if ( mIsLooping )
-		{
-			// QT call to see if we are at the end - can't do with controller
-			if ( IsMovieDone( mMovieHandle ) )
-			{
-				// go back to start
-				rewind();
-
-				if ( mMovieController )
-				{
-					// kick off new play
-					MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
-
-					// set the volume
-					MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
-				};
-			};
-		};
-	};
-
-	int getDataWidth() const
-	{
-		if ( mGWorldHandle )
-		{
-			int depth = mDepth;
-
-			if (depth < 1)
-				depth = 1;
-
-			// ALWAYS use the row bytes from the PixMap if we have a GWorld because
-			// sometimes it's not the same as mMediaDepth * mMediaWidth !
-			PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
-			return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth;
-		}
-		else
-		{
-			// TODO :   return LLMediaImplCommon::getaDataWidth();
-			return 0;
-		}
-	};
-
-	void seek( F64 time )
-	{
-		if ( mMovieController )
-		{
-			TimeRecord when;
-			when.scale = GetMovieTimeScale( mMovieHandle );
-			when.base = 0;
-
-			// 'time' is in (floating point) seconds.  The timebase time will be in 'units', where
-			// there are 'scale' units per second.
-			SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) );
-
-			when.value.hi = ( SInt32 )( raw_time >> 32 );
-			when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) );
-
-			MCDoAction( mMovieController, mcActionGoToTime, &when );
-		};
-	};
-
-	F64 getDuration()
-	{
-		TimeValue duration = GetMovieDuration( mMovieHandle );
-		TimeValue scale = GetMovieTimeScale( mMovieHandle );
-
-		return (F64)duration / (F64)scale;
-	};
-
-	F64 getCurrentTime()
-	{
-		TimeValue curr_time = GetMovieTime( mMovieHandle, 0 );
-		TimeValue scale = GetMovieTimeScale( mMovieHandle );
-
-		return (F64)curr_time / (F64)scale;
-	};
-
-	void setVolume( F64 volume )
-	{
-		mCurVolume = (short)(volume * ( double ) 0x100 );
-
-		if ( mMovieController )
-		{
-			MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
-		};
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void update(int milliseconds = 0)
-	{
-		updateQuickTime(milliseconds);
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseDown( int x, int y )
-	{
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseUp( int x, int y )
-	{
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseMove( int x, int y )
-	{
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void keyPress( unsigned char key )
-	{
-	};
-
-};
-
-MediaPluginQuickTime::MediaPluginQuickTime(
-	LLPluginInstance::sendMessageFunction host_send_func,
-	void *host_user_data ) :
-	MediaPluginBase(host_send_func, host_user_data),
-	mMinWidth( 0 ),
-	mMaxWidth( 2048 ),
-	mMinHeight( 0 ),
-	mMaxHeight( 2048 )
-{
-//	std::cerr << "MediaPluginQuickTime constructor" << std::endl;
-
-	mNaturalWidth = -1;
-	mNaturalHeight = -1;
-	mMovieHandle = 0;
-	mGWorldHandle = 0;
-	mMovieController = 0;
-	mCurVolume = 0x99;
-	mMediaSizeChanging = false;
-	mIsLooping = false;
-	mCommand = COMMAND_NONE;
-	mPlayRate = 0.0f;
-	mStatus = STATUS_NONE;
-}
-
-MediaPluginQuickTime::~MediaPluginQuickTime()
-{
-//	std::cerr << "MediaPluginQuickTime destructor" << std::endl;
-
-	ExitMovies();
-
-#ifdef LL_WINDOWS
-	TerminateQTML();
-//		std::cerr << "QuickTime closing down" << std::endl;
-#endif
-}
-
-
-void MediaPluginQuickTime::receiveMessage(const char *message_string)
-{
-//	std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
-	LLPluginMessage message_in;
-
-	if(message_in.parse(message_string) >= 0)
-	{
-		std::string message_class = message_in.getClass();
-		std::string message_name = message_in.getName();
-		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
-		{
-			if(message_name == "init")
-			{
-				LLPluginMessage message("base", "init_response");
-				LLSD versions = LLSD::emptyMap();
-				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
-				// Normally a plugin would only specify one of these two subclasses, but this is a demo...
-//				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
-				message.setValueLLSD("versions", versions);
-
-				#ifdef LL_WINDOWS
-				if ( InitializeQTML( 0L ) != noErr )
-				{
-					//TODO: If no QT on Windows, this fails - respond accordingly.
-					//return false;
-				}
-				else
-				{
-//					std::cerr << "QuickTime initialized" << std::endl;
-				};
-				#endif
-
-				EnterMovies();
-
-				std::string plugin_version = "QuickTime media plugin, QuickTime version ";
-
-				long version = 0;
-				Gestalt( gestaltQuickTimeVersion, &version );
-				std::ostringstream codec( "" );
-				codec << std::hex << version << std::dec;
-				plugin_version += codec.str();
-				message.setValue("plugin_version", plugin_version);
-				sendMessage(message);
-
-				// Plugin gets to decide the texture parameters to use.
-				message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
-				#if defined(LL_WINDOWS)
-					// Values for Windows
-					mDepth = 3;	
-					message.setValueU32("format", GL_RGB);
-					message.setValueU32("type", GL_UNSIGNED_BYTE);
-
-					// We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even.
-					// Padding to a multiple of 3*32 guarantees it'll divide out properly.
-					message.setValueU32("padding", 32 * 3);
-				#else
-					// Values for Mac
-					mDepth = 4;	
-					message.setValueU32("format", GL_BGRA_EXT);
-					#ifdef __BIG_ENDIAN__
-						message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV );
-					#else
-						message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8);
-					#endif
-
-					// Pad texture width to a multiple of 32 bytes, to line up with cache lines.
-					message.setValueU32("padding", 32);
-				#endif
-				message.setValueS32("depth", mDepth);
-				message.setValueU32("internalformat", GL_RGB);
-				message.setValueBoolean("coords_opengl", true);	// true == use OpenGL-style coordinates, false == (0,0) is upper left.
-				message.setValueBoolean("allow_downsample", true);
-				sendMessage(message);
-			}
-			else if(message_name == "idle")
-			{
-				// no response is necessary here.
-				F64 time = message_in.getValueReal("time");
-				
-				// Convert time to milliseconds for update()
-				update((int)(time * 1000.0f));
-			}
-			else if(message_name == "cleanup")
-			{
-				// TODO: clean up here
-			}
-			else if(message_name == "shm_added")
-			{
-				SharedSegmentInfo info;
-				info.mAddress = message_in.getValuePointer("address");
-				info.mSize = (size_t)message_in.getValueS32("size");
-				std::string name = message_in.getValue("name");
-
-
-//				std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name
-//					<< ", size: " << info.mSize
-//					<< ", address: " << info.mAddress
-//					<< std::endl;
-
-				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-
-			}
-			else if(message_name == "shm_remove")
-			{
-				std::string name = message_in.getValue("name");
-
-//				std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl;
-
-				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-				if(iter != mSharedSegments.end())
-				{
-					if(mPixels == iter->second.mAddress)
-					{
-						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
-						mPixels = NULL;
-						mTextureSegmentName.clear();
-						
-						// Make sure the movie GWorld is no longer pointed at the shared segment.
-						sizeChanged();						
-					}
-					mSharedSegments.erase(iter);
-				}
-				else
-				{
-//					std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl;
-				}
-
-				// Send the response so it can be cleaned up.
-				LLPluginMessage message("base", "shm_remove_response");
-				message.setValue("name", name);
-				sendMessage(message);
-			}
-			else
-			{
-//				std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl;
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
-		{
-			if(message_name == "size_change")
-			{
-				std::string name = message_in.getValue("name");
-				S32 width = message_in.getValueS32("width");
-				S32 height = message_in.getValueS32("height");
-				S32 texture_width = message_in.getValueS32("texture_width");
-				S32 texture_height = message_in.getValueS32("texture_height");
-
-				//std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl;
-
-				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
-				message.setValue("name", name);
-				message.setValueS32("width", width);
-				message.setValueS32("height", height);
-				message.setValueS32("texture_width", texture_width);
-				message.setValueS32("texture_height", texture_height);
-				sendMessage(message);
-
-				if(!name.empty())
-				{
-					// Find the shared memory region with this name
-					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-					if(iter != mSharedSegments.end())
-					{
-//						std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl;
-//						std::cerr << "%%%%  texture size is " << texture_width << " by " << texture_height << std::endl;
-
-						mPixels = (unsigned char*)iter->second.mAddress;
-						mTextureSegmentName = name;
-						mWidth = width;
-						mHeight = height;
-
-						mTextureWidth = texture_width;
-						mTextureHeight = texture_height;
-
-						mMediaSizeChanging = false;
-						
-						sizeChanged();
-						
-						update();
-					};
-				};
-			}
-			else if(message_name == "load_uri")
-			{
-				std::string uri = message_in.getValue("uri");
-				load( uri );
-				sendStatus();		
-			}
-			else if(message_name == "mouse_event")
-			{
-				std::string event = message_in.getValue("event");
-				S32 x = message_in.getValueS32("x");
-				S32 y = message_in.getValueS32("y");
-				
-				if(event == "down")
-				{
-					mouseDown(x, y);
-				}
-				else if(event == "up")
-				{
-					mouseUp(x, y);
-				}
-				else if(event == "move")
-				{
-					mouseMove(x, y);
-				};
-			};
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
-		{
-			if(message_name == "stop")
-			{
-				stop();
-			}
-			else if(message_name == "start")
-			{
-				F64 rate = 0.0;
-				if(message_in.hasValue("rate"))
-				{
-					rate = message_in.getValueReal("rate");
-				}
-				play(rate);
-			}
-			else if(message_name == "pause")
-			{
-				pause();
-			}
-			else if(message_name == "seek")
-			{
-				F64 time = message_in.getValueReal("time");
-				seek(time);
-			}
-			else if(message_name == "set_loop")
-			{
-				bool loop = message_in.getValueBoolean("loop");
-				mIsLooping = loop;
-			}
-			else if(message_name == "set_volume")
-			{
-				F64 volume = message_in.getValueReal("volume");
-				setVolume(volume);
-			}
-		}
-		else
-		{
-//			std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl;
-		};
-	};
-}
-
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
-	MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data);
-	*plugin_send_func = MediaPluginQuickTime::staticReceiveMessage;
-	*plugin_user_data = (void*)self;
-
-	return 0;
-}
-
-#else // LL_QUICKTIME_ENABLED
-
-// Stubbed-out class with constructor/destructor (necessary or windows linker
-// will just think its dead code and optimize it all out)
-class MediaPluginQuickTime : public MediaPluginBase
-{
-public:
-	MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
-	~MediaPluginQuickTime();
-	/* virtual */ void receiveMessage(const char *message_string);
-};
-
-MediaPluginQuickTime::MediaPluginQuickTime(
-	LLPluginInstance::sendMessageFunction host_send_func,
-	void *host_user_data ) :
-	MediaPluginBase(host_send_func, host_user_data)
-{
-    // no-op
-}
-
-MediaPluginQuickTime::~MediaPluginQuickTime()
-{
-    // no-op
-}
-
-void MediaPluginQuickTime::receiveMessage(const char *message_string)
-{
-    // no-op 
-}
-
-// We're building without quicktime enabled.  Just refuse to initialize.
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
-    return -1;
-}
-
-#endif // LL_QUICKTIME_ENABLED
+/**
+ * @file media_plugin_quicktime.cpp
+ * @brief QuickTime plugin for LLMedia API plugin system
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llgl.h"
+
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.h"
+
+#if LL_QUICKTIME_ENABLED
+
+#if defined(LL_DARWIN)
+	#include <QuickTime/QuickTime.h>
+#elif defined(LL_WINDOWS)
+	#include "MacTypes.h"
+	#include "QTML.h"
+	#include "Movies.h"
+	#include "QDoffscreen.h"
+	#include "FixMath.h"
+	#include "QTLoadLibraryUtils.h"
+#endif
+
+// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
+////////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginQuickTime : public MediaPluginBase
+{
+public:
+	MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+	~MediaPluginQuickTime();
+
+	/* virtual */ void receiveMessage(const char *message_string);
+
+private:
+
+	int mNaturalWidth;
+	int mNaturalHeight;
+	Movie mMovieHandle;
+	GWorldPtr mGWorldHandle;
+	ComponentInstance mMovieController;
+	int mCurVolume;
+	bool mMediaSizeChanging;
+	bool mIsLooping;
+	std::string mMovieTitle;
+	bool mReceivedTitle;
+	const int mMinWidth;
+	const int mMaxWidth;
+	const int mMinHeight;
+	const int mMaxHeight;
+	F64 mPlayRate;
+
+	enum ECommand {
+		COMMAND_NONE,
+		COMMAND_STOP,
+		COMMAND_PLAY,
+		COMMAND_FAST_FORWARD,
+		COMMAND_FAST_REWIND,
+		COMMAND_PAUSE,
+		COMMAND_SEEK,
+	};
+	ECommand mCommand;
+
+	// Override this to add current time and duration to the message
+	/*virtual*/ void setDirty(int left, int top, int right, int bottom)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
+
+		message.setValueS32("left", left);
+		message.setValueS32("top", top);
+		message.setValueS32("right", right);
+		message.setValueS32("bottom", bottom);
+
+		if(mMovieHandle)
+		{
+			message.setValueReal("current_time", getCurrentTime());
+			message.setValueReal("duration", getDuration());
+			message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle)));
+		}
+
+		sendMessage(message);
+	}
+
+
+	static Rect rectFromSize(int width, int height)
+	{
+		Rect result;
+
+
+		result.left = 0;
+		result.top = 0;
+		result.right = width;
+		result.bottom = height;
+
+		return result;
+	}
+
+	Fixed getPlayRate(void)
+	{
+		Fixed result;
+		if(mPlayRate == 0.0f)
+		{
+			// Default to the movie's preferred rate
+			result = GetMoviePreferredRate(mMovieHandle);
+			if(result == 0)
+			{
+				// Don't return a 0 play rate, ever.
+				std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl;
+				result = X2Fix(1.0f);
+			}
+		}
+		else
+		{
+			result = X2Fix(mPlayRate);
+		}
+
+		return result;
+	}
+
+	void load( const std::string url )
+	{
+
+		if ( url.empty() )
+			return;
+
+		// Stop and unload any existing movie before starting another one.
+		unload();
+
+		setStatus(STATUS_LOADING);
+
+		//In case std::string::c_str() makes a copy of the url data,
+		//make sure there is memory to hold it before allocating memory for handle.
+		//if fails, NewHandleClear(...) should return NULL.
+		const char* url_string = url.c_str() ;
+		Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) );
+
+		if ( NULL == handle || noErr != MemError() || NULL == *handle )
+		{
+			setStatus(STATUS_ERROR);
+			return;
+		}
+
+		BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) );
+
+		OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType );
+		DisposeHandle( handle );
+		if ( noErr != err )
+		{
+			setStatus(STATUS_ERROR);
+			return;
+		};
+
+		// do pre-roll actions (typically fired for streaming movies but not always)
+		PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this );
+
+		Rect movie_rect = rectFromSize(mWidth, mHeight);
+
+		// make a new movie controller
+		mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie );
+
+		// movie controller
+		MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this );
+
+		SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize );
+
+		// function that gets called when a frame is drawn
+		SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this );
+
+		setStatus(STATUS_LOADED);
+
+		sizeChanged();
+	};
+
+	bool unload()
+	{
+		// new movie and have to get title again
+		mReceivedTitle = false;
+
+		if ( mMovieHandle )
+		{
+			StopMovie( mMovieHandle );
+			if ( mMovieController )
+			{
+				MCMovieChanged( mMovieController, mMovieHandle );
+			};
+		};
+
+		if ( mMovieController )
+		{
+			MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this );
+			DisposeMovieController( mMovieController );
+			mMovieController = NULL;
+		};
+
+		if ( mMovieHandle )
+		{
+			SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this );
+			DisposeMovie( mMovieHandle );
+			mMovieHandle = NULL;
+		};
+
+		if ( mGWorldHandle )
+		{
+			DisposeGWorld( mGWorldHandle );
+			mGWorldHandle = NULL;
+		};
+
+		setStatus(STATUS_NONE);
+
+		return true;
+	}
+
+	bool navigateTo( const std::string url )
+	{
+		unload();
+		load( url );
+
+		return true;
+	};
+
+	bool sizeChanged()
+	{
+		if ( ! mMovieHandle )
+			return false;
+
+		// Check to see whether the movie's natural size has updated
+		{
+			int width, height;
+			getMovieNaturalSize(&width, &height);
+			if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight)))
+			{
+				mNaturalWidth = width;
+				mNaturalHeight = height;
+
+				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request");
+				message.setValue("name", mTextureSegmentName);
+				message.setValueS32("width", width);
+				message.setValueS32("height", height);
+				sendMessage(message);
+				//std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl;
+			}
+		}
+
+		// sanitize destination size
+		Rect dest_rect = rectFromSize(mWidth, mHeight);
+
+		// media depth won't change
+		int depth_bits = mDepth * 8;
+		long rowbytes = mDepth * mTextureWidth;
+
+		GWorldPtr old_gworld_handle = mGWorldHandle;
+
+		if(mPixels != NULL)
+		{
+			// We have pixels.  Set up a GWorld pointing at the texture.
+			OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes);
+			if ( noErr != result )
+			{
+				// TODO: unrecoverable??  throw exception?  return something?
+				return false;
+			}
+		}
+		else
+		{
+			// We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally.
+			Rect tempRect = rectFromSize(1, 1);
+			OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0);
+			if ( noErr != result )
+			{
+				// TODO: unrecoverable??  throw exception?  return something?
+				return false;
+			}
+		}
+
+		SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) );
+
+		// If the GWorld was already set up, delete it.
+		if(old_gworld_handle != NULL)
+		{
+			DisposeGWorld( old_gworld_handle );
+		}
+
+		// Set up the movie display matrix
+		{
+			// scale movie to fit rect and invert vertically to match opengl image format
+			MatrixRecord transform;
+			SetIdentityMatrix( &transform );	// transforms are additive so start from identify matrix
+			double scaleX = (double) mWidth / mNaturalWidth;
+			double scaleY = -1.0 * (double) mHeight / mNaturalHeight;
+			double centerX = mWidth / 2.0;
+			double centerY = mHeight / 2.0;
+			ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) );
+			SetMovieMatrix( mMovieHandle, &transform );
+		}
+
+		// update movie controller
+		if ( mMovieController )
+		{
+			MCSetControllerPort( mMovieController, mGWorldHandle );
+			MCPositionController( mMovieController, &dest_rect, &dest_rect,
+								  mcTopLeftMovie | mcPositionDontInvalidate );
+			MCMovieChanged( mMovieController, mMovieHandle );
+		}
+
+
+		// Emit event with size change so the calling app knows about it too
+		// TODO:
+		//LLMediaEvent event( this );
+		//mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event );
+
+		return true;
+	}
+	static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref )
+	{
+		Boolean result = false;
+
+		MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
+
+		switch( action )
+		{
+			// handle window resizing
+			case mcActionControllerSizeChanged:
+				// Ensure that the movie draws correctly at the new size
+				self->sizeChanged();
+				break;
+
+			// Block any movie controller actions that open URLs.
+			case mcActionLinkToURL:
+			case mcActionGetNextURL:
+			case mcActionLinkToURLExtended:
+				// Prevent the movie controller from handling the message
+				result = true;
+				break;
+
+			default:
+				break;
+		};
+
+		return result;
+	};
+
+	static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref )
+	{
+		MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
+
+		// IMPORTANT: typically, a consumer who is observing this event will set a flag
+		// when this event is fired then render later. Be aware that the media stream
+		// can change during this period - dimensions, depth, format etc.
+		//LLMediaEvent event( self );
+//		self->updateQuickTime();
+		// TODO ^^^
+
+
+		if ( self->mWidth > 0 && self->mHeight > 0 )
+			self->setDirty( 0, 0, self->mWidth, self->mHeight );
+
+		return noErr;
+	};
+
+	static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref )
+	{
+		//MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
+
+		// TODO:
+		//LLMediaEvent event( self );
+		//self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event );
+	};
+
+
+	void rewind()
+	{
+		GoToBeginningOfMovie( mMovieHandle );
+		MCMovieChanged( mMovieController, mMovieHandle );
+	};
+
+	bool processState()
+	{
+		if ( mCommand == COMMAND_PLAY )
+		{
+			if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING )
+			{
+				long state = GetMovieLoadState( mMovieHandle );
+
+				if ( state >= kMovieLoadStatePlaythroughOK )
+				{
+					// if the movie is at the end (generally because it reached it naturally)
+					// and we play is requested, jump back to the start of the movie.
+					// note: this is different from having loop flag set.
+					if ( IsMovieDone( mMovieHandle ) )
+					{
+						Fixed rate = X2Fix( 0.0 );
+						MCDoAction( mMovieController, mcActionPlay, (void*)rate );
+						rewind();
+					};
+
+					MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
+					MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
+					setStatus(STATUS_PLAYING);
+					mCommand = COMMAND_NONE;
+				};
+			};
+		}
+		else
+		if ( mCommand == COMMAND_STOP )
+		{
+			if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED )
+			{
+				if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
+				{
+					Fixed rate = X2Fix( 0.0 );
+					MCDoAction( mMovieController, mcActionPlay, (void*)rate );
+					rewind();
+
+					setStatus(STATUS_LOADED);
+					mCommand = COMMAND_NONE;
+				};
+			};
+		}
+		else
+		if ( mCommand == COMMAND_PAUSE )
+		{
+			if ( mStatus == STATUS_PLAYING )
+			{
+				if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
+				{
+					Fixed rate = X2Fix( 0.0 );
+					MCDoAction( mMovieController, mcActionPlay, (void*)rate );
+					setStatus(STATUS_PAUSED);
+					mCommand = COMMAND_NONE;
+				};
+			};
+		};
+
+		return true;
+	};
+
+	void play(F64 rate)
+	{
+		mPlayRate = rate;
+		mCommand = COMMAND_PLAY;
+	};
+
+	void stop()
+	{
+		mCommand = COMMAND_STOP;
+	};
+
+	void pause()
+	{
+		mCommand = COMMAND_PAUSE;
+	};
+
+	void getMovieNaturalSize(int *movie_width, int *movie_height)
+	{
+		Rect rect;
+
+		GetMovieNaturalBoundsRect( mMovieHandle, &rect );
+
+		int width  = ( rect.right - rect.left );
+		int height = ( rect.bottom - rect.top );
+
+		// make sure width and height fall in valid range
+		if ( width < mMinWidth )
+			width = mMinWidth;
+
+		if ( width > mMaxWidth )
+			width = mMaxWidth;
+
+		if ( height < mMinHeight )
+			height = mMinHeight;
+
+		if ( height > mMaxHeight )
+			height = mMaxHeight;
+
+		// return the new rect
+		*movie_width = width;
+		*movie_height = height;
+	}
+
+	void updateQuickTime(int milliseconds)
+	{
+		if ( ! mMovieHandle )
+			return;
+
+		if ( ! mMovieController )
+			return;
+
+		// service QuickTime
+		// Calling it this way doesn't have good behavior on Windows...
+//		MoviesTask( mMovieHandle, milliseconds );
+		// This was the original, but I think using both MoviesTask and MCIdle is redundant.  Trying with only MCIdle.
+//		MoviesTask( mMovieHandle, 0 );
+
+		MCIdle( mMovieController );
+
+		if ( ! mGWorldHandle )
+			return;
+
+		if ( mMediaSizeChanging )
+			return;
+
+		// update state machine
+		processState();
+
+		// see if title arrived and if so, update member variable with contents
+		checkTitle();
+
+		// special code for looping - need to rewind at the end of the movie
+		if ( mIsLooping )
+		{
+			// QT call to see if we are at the end - can't do with controller
+			if ( IsMovieDone( mMovieHandle ) )
+			{
+				// go back to start
+				rewind();
+
+				if ( mMovieController )
+				{
+					// kick off new play
+					MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
+
+					// set the volume
+					MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
+				};
+			};
+		};
+	};
+
+	int getDataWidth() const
+	{
+		if ( mGWorldHandle )
+		{
+			int depth = mDepth;
+
+			if (depth < 1)
+				depth = 1;
+
+			// ALWAYS use the row bytes from the PixMap if we have a GWorld because
+			// sometimes it's not the same as mMediaDepth * mMediaWidth !
+			PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
+			return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth;
+		}
+		else
+		{
+			// TODO :   return LLMediaImplCommon::getaDataWidth();
+			return 0;
+		}
+	};
+
+	void seek( F64 time )
+	{
+		if ( mMovieController )
+		{
+			TimeRecord when;
+			when.scale = GetMovieTimeScale( mMovieHandle );
+			when.base = 0;
+
+			// 'time' is in (floating point) seconds.  The timebase time will be in 'units', where
+			// there are 'scale' units per second.
+			SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) );
+
+			when.value.hi = ( SInt32 )( raw_time >> 32 );
+			when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) );
+
+			MCDoAction( mMovieController, mcActionGoToTime, &when );
+		};
+	};
+
+	F64 getLoadedDuration() 	  	 
+	{ 	  	 
+		TimeValue duration; 	  	 
+		if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr) 	  	 
+		{ 	  	 
+			// If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie. 	  	 
+			duration = GetMovieDuration( mMovieHandle ); 	  	 
+		} 	  	 
+		TimeValue scale = GetMovieTimeScale( mMovieHandle ); 	  	 
+
+		return (F64)duration / (F64)scale; 	  	 
+	}; 	  	 
+
+	F64 getDuration()
+	{
+		TimeValue duration = GetMovieDuration( mMovieHandle );
+		TimeValue scale = GetMovieTimeScale( mMovieHandle );
+
+		return (F64)duration / (F64)scale;
+	};
+
+	F64 getCurrentTime()
+	{
+		TimeValue curr_time = GetMovieTime( mMovieHandle, 0 );
+		TimeValue scale = GetMovieTimeScale( mMovieHandle );
+
+		return (F64)curr_time / (F64)scale;
+	};
+
+	void setVolume( F64 volume )
+	{
+		mCurVolume = (short)(volume * ( double ) 0x100 );
+
+		if ( mMovieController )
+		{
+			MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
+		};
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void update(int milliseconds = 0)
+	{
+		updateQuickTime(milliseconds);
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void mouseDown( int x, int y )
+	{
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void mouseUp( int x, int y )
+	{
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void mouseMove( int x, int y )
+	{
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void keyPress( unsigned char key )
+	{
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	// Grab movie title into mMovieTitle - should be called repeatedly
+	// until it returns true since movie title takes a while to become 
+	// available.
+	const bool getMovieTitle()
+	{
+		// grab meta data from movie
+		QTMetaDataRef media_data_ref;
+		OSErr result = QTCopyMovieMetaData( mMovieHandle, &media_data_ref );
+		if ( noErr != result ) 
+			return false;
+
+		// look up "Display Name" in meta data
+		OSType meta_data_key = kQTMetaDataCommonKeyDisplayName;
+		QTMetaDataItem item = kQTMetaDataItemUninitialized;
+		result = QTMetaDataGetNextItem( media_data_ref, kQTMetaDataStorageFormatWildcard, 
+										0, kQTMetaDataKeyFormatCommon, 
+										(const UInt8 *)&meta_data_key, 
+										sizeof( meta_data_key ), &item );
+		if ( noErr != result ) 
+			return false;
+
+		// find the size of the title
+		ByteCount size;
+		result = QTMetaDataGetItemValue( media_data_ref, item, NULL, 0, &size );
+		if ( noErr != result || size <= 0 ) 
+			return false;
+
+		// allocate some space and grab it
+		UInt8* item_data = new UInt8( size );
+		memset( item_data, 0, size * sizeof( UInt8* ) );
+		result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL );
+		if ( noErr != result ) 
+			return false;
+
+		// save it
+		mMovieTitle = std::string( (char* )item_data );
+
+		// clean up
+		delete [] item_data;
+
+		return true;
+	};
+
+	// called regularly to see if title changed
+	void checkTitle()
+	{
+		// we did already receive title so keep checking
+		if ( ! mReceivedTitle )
+		{
+			// grab title from movie meta data
+			if ( getMovieTitle() )
+			{
+				// pass back to host application
+				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+				message.setValue("name", mMovieTitle );
+				sendMessage( message );
+
+				// stop looking once we find a title for this movie.
+				// TODO: this may to be reset if movie title changes
+				// during playback but this is okay for now
+				mReceivedTitle = true;
+			};
+		};
+	};
+};
+
+MediaPluginQuickTime::MediaPluginQuickTime(
+	LLPluginInstance::sendMessageFunction host_send_func,
+	void *host_user_data ) :
+	MediaPluginBase(host_send_func, host_user_data),
+	mMinWidth( 0 ),
+	mMaxWidth( 2048 ),
+	mMinHeight( 0 ),
+	mMaxHeight( 2048 )
+{
+//	std::cerr << "MediaPluginQuickTime constructor" << std::endl;
+
+	mNaturalWidth = -1;
+	mNaturalHeight = -1;
+	mMovieHandle = 0;
+	mGWorldHandle = 0;
+	mMovieController = 0;
+	mCurVolume = 0x99;
+	mMediaSizeChanging = false;
+	mIsLooping = false;
+	mMovieTitle = std::string();
+	mReceivedTitle = false;
+	mCommand = COMMAND_NONE;
+	mPlayRate = 0.0f;
+	mStatus = STATUS_NONE;
+}
+
+MediaPluginQuickTime::~MediaPluginQuickTime()
+{
+//	std::cerr << "MediaPluginQuickTime destructor" << std::endl;
+
+	ExitMovies();
+
+#ifdef LL_WINDOWS
+	TerminateQTML();
+//		std::cerr << "QuickTime closing down" << std::endl;
+#endif
+}
+
+
+void MediaPluginQuickTime::receiveMessage(const char *message_string)
+{
+//	std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+	LLPluginMessage message_in;
+
+	if(message_in.parse(message_string) >= 0)
+	{
+		std::string message_class = message_in.getClass();
+		std::string message_name = message_in.getName();
+		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+		{
+			if(message_name == "init")
+			{
+				LLPluginMessage message("base", "init_response");
+				LLSD versions = LLSD::emptyMap();
+				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+				// Normally a plugin would only specify one of these two subclasses, but this is a demo...
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
+				message.setValueLLSD("versions", versions);
+
+				#ifdef LL_WINDOWS
+
+				// QuickTime 7.6.4 has an issue (that was not present in 7.6.2) with initializing QuickTime
+				// according to this article: http://lists.apple.com/archives/QuickTime-API/2009/Sep/msg00097.html
+				// The solution presented there appears to work.
+				QTLoadLibrary("qtcf.dll");
+
+				// main initialization for QuickTime - only required on Windows
+				OSErr result = InitializeQTML( 0L );
+				if ( result != noErr )
+				{
+					//TODO: If no QT on Windows, this fails - respond accordingly.
+				}
+				else
+				{
+					//std::cerr << "QuickTime initialized" << std::endl;
+				};
+				#endif
+
+				// required for both Windows and Mac
+				EnterMovies();
+
+				std::string plugin_version = "QuickTime media plugin, QuickTime version ";
+
+				long version = 0;
+				Gestalt( gestaltQuickTimeVersion, &version );
+				std::ostringstream codec( "" );
+				codec << std::hex << version << std::dec;
+				plugin_version += codec.str();
+				message.setValue("plugin_version", plugin_version);
+				sendMessage(message);
+
+				// Plugin gets to decide the texture parameters to use.
+				message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+				#if defined(LL_WINDOWS)
+					// Values for Windows
+					mDepth = 3;
+					message.setValueU32("format", GL_RGB);
+					message.setValueU32("type", GL_UNSIGNED_BYTE);
+
+					// We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even.
+					// Padding to a multiple of 3*32 guarantees it'll divide out properly.
+					message.setValueU32("padding", 32 * 3);
+				#else
+					// Values for Mac
+					mDepth = 4;
+					message.setValueU32("format", GL_BGRA_EXT);
+					#ifdef __BIG_ENDIAN__
+						message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV );
+					#else
+						message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8);
+					#endif
+
+					// Pad texture width to a multiple of 32 bytes, to line up with cache lines.
+					message.setValueU32("padding", 32);
+				#endif
+				message.setValueS32("depth", mDepth);
+				message.setValueU32("internalformat", GL_RGB);
+				message.setValueBoolean("coords_opengl", true);	// true == use OpenGL-style coordinates, false == (0,0) is upper left.
+				message.setValueBoolean("allow_downsample", true);
+				sendMessage(message);
+			}
+			else if(message_name == "idle")
+			{
+				// no response is necessary here.
+				F64 time = message_in.getValueReal("time");
+
+				// Convert time to milliseconds for update()
+				update((int)(time * 1000.0f));
+			}
+			else if(message_name == "cleanup")
+			{
+				// TODO: clean up here
+			}
+			else if(message_name == "shm_added")
+			{
+				SharedSegmentInfo info;
+				info.mAddress = message_in.getValuePointer("address");
+				info.mSize = (size_t)message_in.getValueS32("size");
+				std::string name = message_in.getValue("name");
+//				std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name
+//					<< ", size: " << info.mSize
+//					<< ", address: " << info.mAddress
+//					<< std::endl;
+
+				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+			}
+			else if(message_name == "shm_remove")
+			{
+				std::string name = message_in.getValue("name");
+
+//				std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl;
+
+				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+				if(iter != mSharedSegments.end())
+				{
+					if(mPixels == iter->second.mAddress)
+					{
+						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
+						mPixels = NULL;
+						mTextureSegmentName.clear();
+
+						// Make sure the movie GWorld is no longer pointed at the shared segment.
+						sizeChanged();
+					}
+					mSharedSegments.erase(iter);
+				}
+				else
+				{
+//					std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl;
+				}
+
+				// Send the response so it can be cleaned up.
+				LLPluginMessage message("base", "shm_remove_response");
+				message.setValue("name", name);
+				sendMessage(message);
+			}
+			else
+			{
+//				std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl;
+			}
+		}
+		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+		{
+			if(message_name == "size_change")
+			{
+				std::string name = message_in.getValue("name");
+				S32 width = message_in.getValueS32("width");
+				S32 height = message_in.getValueS32("height");
+				S32 texture_width = message_in.getValueS32("texture_width");
+				S32 texture_height = message_in.getValueS32("texture_height");
+
+				//std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl;
+
+				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+				message.setValue("name", name);
+				message.setValueS32("width", width);
+				message.setValueS32("height", height);
+				message.setValueS32("texture_width", texture_width);
+				message.setValueS32("texture_height", texture_height);
+				sendMessage(message);
+
+				if(!name.empty())
+				{
+					// Find the shared memory region with this name
+					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+					if(iter != mSharedSegments.end())
+					{
+//						std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl;
+//						std::cerr << "%%%%  texture size is " << texture_width << " by " << texture_height << std::endl;
+
+						mPixels = (unsigned char*)iter->second.mAddress;
+						mTextureSegmentName = name;
+						mWidth = width;
+						mHeight = height;
+
+						mTextureWidth = texture_width;
+						mTextureHeight = texture_height;
+
+						mMediaSizeChanging = false;
+
+						sizeChanged();
+
+						update();
+					};
+				};
+			}
+			else if(message_name == "load_uri")
+			{
+				std::string uri = message_in.getValue("uri");
+				load( uri );
+				sendStatus();
+			}
+			else if(message_name == "mouse_event")
+			{
+				std::string event = message_in.getValue("event");
+				S32 x = message_in.getValueS32("x");
+				S32 y = message_in.getValueS32("y");
+
+				if(event == "down")
+				{
+					mouseDown(x, y);
+				}
+				else if(event == "up")
+				{
+					mouseUp(x, y);
+				}
+				else if(event == "move")
+				{
+					mouseMove(x, y);
+				};
+			};
+		}
+		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+		{
+			if(message_name == "stop")
+			{
+				stop();
+			}
+			else if(message_name == "start")
+			{
+				F64 rate = 0.0;
+				if(message_in.hasValue("rate"))
+				{
+					rate = message_in.getValueReal("rate");
+				}
+				play(rate);
+			}
+			else if(message_name == "pause")
+			{
+				pause();
+			}
+			else if(message_name == "seek")
+			{
+				F64 time = message_in.getValueReal("time");
+				seek(time);
+			}
+			else if(message_name == "set_loop")
+			{
+				bool loop = message_in.getValueBoolean("loop");
+				mIsLooping = loop;
+			}
+			else if(message_name == "set_volume")
+			{
+				F64 volume = message_in.getValueReal("volume");
+				setVolume(volume);
+			}
+		}
+		else
+		{
+//			std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl;
+		};
+	};
+}
+
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
+{
+	MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data);
+	*plugin_send_func = MediaPluginQuickTime::staticReceiveMessage;
+	*plugin_user_data = (void*)self;
+
+	return 0;
+}
+
+#else // LL_QUICKTIME_ENABLED
+
+// Stubbed-out class with constructor/destructor (necessary or windows linker
+// will just think its dead code and optimize it all out)
+class MediaPluginQuickTime : public MediaPluginBase
+{
+public:
+	MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+	~MediaPluginQuickTime();
+	/* virtual */ void receiveMessage(const char *message_string);
+};
+
+MediaPluginQuickTime::MediaPluginQuickTime(
+	LLPluginInstance::sendMessageFunction host_send_func,
+	void *host_user_data ) :
+	MediaPluginBase(host_send_func, host_user_data)
+{
+    // no-op
+}
+
+MediaPluginQuickTime::~MediaPluginQuickTime()
+{
+    // no-op
+}
+
+void MediaPluginQuickTime::receiveMessage(const char *message_string)
+{
+    // no-op
+}
+
+// We're building without quicktime enabled.  Just refuse to initialize.
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
+{
+    return -1;
+}
+
+#endif // LL_QUICKTIME_ENABLED
diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt
index d96477279d86207438fc8c9be9e44cb12feebc63..5bccd589d80de18d27311d7591971814997f087d 100644
--- a/indra/media_plugins/webkit/CMakeLists.txt
+++ b/indra/media_plugins/webkit/CMakeLists.txt
@@ -52,6 +52,14 @@ add_dependencies(media_plugin_webkit
   ${LLCOMMON_LIBRARIES}
 )
 
+if (WINDOWS)
+  set_target_properties(
+    media_plugin_webkit
+    PROPERTIES
+    LINK_FLAGS "/MANIFEST:NO"
+    )
+endif (WINDOWS)
+
 if (DARWIN)
   # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name
   set_target_properties(
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index eb2457744ab5d67bd91832a421f26c7215274dcd..6c54f63859b3eb5115370be7f57077262a3b86c3 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -1,797 +1,842 @@
-/** 
- * @file media_plugin_webkit.cpp
- * @brief Webkit plugin for LLMedia API plugin system
- *
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- *
- * Copyright (c) 2008, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llqtwebkit.h"
-
-#include "linden_common.h"
-#include "indra_constants.h" // for indra keyboard codes
-
-#include "llgl.h"
-
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "media_plugin_base.h"
-
-#if LL_WINDOWS
-#include <direct.h>
-#else
-#include <unistd.h>
-#include <stdlib.h>
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-//
-class MediaPluginWebKit : 
-		public MediaPluginBase,
-		public LLEmbeddedBrowserWindowObserver
-{
-public:
-	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
-	~MediaPluginWebKit();
-
-	/*virtual*/ void receiveMessage(const char *message_string);
-
-private:
-
-	int mBrowserWindowId;
-	bool mBrowserInitialized;
-	bool mNeedsUpdate;
-
-	bool	mCanCut;
-	bool	mCanCopy;
-	bool	mCanPaste;
-	
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void update(int milliseconds)
-	{
-		LLQtWebKit::getInstance()->pump( milliseconds );
-		
-		checkEditState();
-		
-		if ( mNeedsUpdate )
-		{
-			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
-
-			unsigned int buffer_size = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) * LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
-			
-//			std::cerr << "webkit plugin: updating" << std::endl;
-			
-			// TODO: should get rid of this memcpy if possible
-			if ( mPixels && browser_pixels )
-			{
-//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl;
-				memcpy( mPixels, browser_pixels, buffer_size );
-			}
-
-			if ( mWidth > 0 && mHeight > 0 )
-			{
-//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
-				setDirty( 0, 0, mWidth, mHeight );
-			}
-
-			mNeedsUpdate = false;
-		};
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	bool initBrowser()
-	{
-		// already initialized
-		if ( mBrowserInitialized )
-			return true;
-
-		// not enough information to initialize the browser yet.
-		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || 
-				mTextureWidth < 0 || mTextureHeight < 0 )
-		{
-			return false;
-		};
-
-		// set up directories
-		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
-		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-		{
-			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
-			return false;
-		}
-		std::string application_dir = std::string( cwd );
-		std::string component_dir = application_dir;
-		std::string profileDir = application_dir + "/" + "browser_profile";		// cross platform?
-
-		// window handle - needed on Windows and must be app window.
-#if LL_WINDOWS
-		char window_title[ MAX_PATH ];
-		GetConsoleTitleA( window_title, MAX_PATH );
-		void* native_window_handle = (void*)FindWindowA( NULL, window_title );
-#else
-		void* native_window_handle = 0;
-#endif
-
-		// main browser initialization
-		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, profileDir, native_window_handle );
-		if ( result )
-		{
-			// create single browser window
-			mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight );
-
-#if LL_WINDOWS
-			// Enable plugins
-			LLQtWebKit::getInstance()->enablePlugins(false);
-#elif LL_DARWIN
-			// Disable plugins
-			LLQtWebKit::getInstance()->enablePlugins(false);
-#elif LL_LINUX
-			// Disable plugins
-			LLQtWebKit::getInstance()->enablePlugins(false);
-#endif
-            
-			// tell LLQtWebKit about the size of the browser window
-			LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-
-			// observer events that LLQtWebKit emits
-			LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
-
-			// append details to agent string
-			LLQtWebKit::getInstance()->setBrowserAgentId( "LLPluginMedia Web Browser" );
-
-			// don't flip bitmap
-			LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
-			
-			// Set the background color to black
-			LLQtWebKit::getInstance()->
-			// set background color to be black - mostly for initial login page
-			LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 );
-
-			// go to the "home page"
-			// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
-//			LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
-
-			// set flag so we don't do this again
-			mBrowserInitialized = true;
-
-			return true;
-		};
-
-		return false;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onCursorChanged(const EventType& event)
-	{
-		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
-		std::string name;
-
-		switch(llqt_cursor)
-		{
-			case LLQtWebKit::C_ARROW:
-				name = "arrow";
-			break;
-			case LLQtWebKit::C_IBEAM:
-				name = "ibeam";
-			break;
-			case LLQtWebKit::C_SPLITV:
-				name = "splitv";
-			break;
-			case LLQtWebKit::C_SPLITH:
-				name = "splith";
-			break;
-			case LLQtWebKit::C_POINTINGHAND:
-				name = "hand";
-			break;
-			
-			default:
-				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
-			break;
-		}
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
-		message.setValue("name", name);
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onPageChanged( const EventType& event )
-	{
-		// flag that an update is required
-		mNeedsUpdate = true;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateBegin(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
-		message.setValue("uri", event.getEventUri());
-		sendMessage(message);
-
-		setStatus(STATUS_LOADING);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateComplete(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
-		message.setValue("uri", event.getEventUri());
-		message.setValueS32("result_code", event.getIntValue());
-		message.setValue("result_string", event.getStringValue());
-		message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
-		message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
-		sendMessage(message);
-		
-		setStatus(STATUS_LOADED);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onUpdateProgress(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
-		message.setValueS32("percent", event.getIntValue());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onStatusTextChange(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
-		message.setValue("status", event.getStringValue());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onLocationChange(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
-		message.setValue("uri", event.getEventUri());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onClickLinkHref(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
-		message.setValue("uri", event.getStringValue());
-		message.setValue("target", event.getStringValue2());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onClickLinkNoFollow(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
-		message.setValue("uri", event.getStringValue());
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseDown( int x, int y )
-	{
-		LLQtWebKit::getInstance()->mouseDown( mBrowserWindowId, x, y );
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseUp( int x, int y )
-	{
-		LLQtWebKit::getInstance()->mouseUp( mBrowserWindowId, x, y );
-		LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, true );
-		checkEditState();
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseMove( int x, int y )
-	{
-		LLQtWebKit::getInstance()->mouseMove( mBrowserWindowId, x, y );
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void keyPress( int key )
-	{
-		int llqt_key;
-		
-		// The incoming values for 'key' will be the ones from indra_constants.h
-		// the outgoing values are the ones from llqtwebkit.h
-		
-		switch((KEY)key)
-		{
-			// This is the list that the llqtwebkit implementation actually maps into Qt keys.
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_CANCEL;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_HELP;			break;
-			case KEY_BACKSPACE:		llqt_key = LL_DOM_VK_BACK_SPACE;		break;
-			case KEY_TAB:			llqt_key = LL_DOM_VK_TAB;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_CLEAR;			break;
-			case KEY_RETURN:		llqt_key = LL_DOM_VK_RETURN;			break;
-			case KEY_PAD_RETURN:	llqt_key = LL_DOM_VK_ENTER;			break;
-			case KEY_SHIFT:			llqt_key = LL_DOM_VK_SHIFT;			break;
-			case KEY_CONTROL:		llqt_key = LL_DOM_VK_CONTROL;		break;
-			case KEY_ALT:			llqt_key = LL_DOM_VK_ALT;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_PAUSE;			break;
-			case KEY_CAPSLOCK:		llqt_key = LL_DOM_VK_CAPS_LOCK;		break;
-			case KEY_ESCAPE:		llqt_key = LL_DOM_VK_ESCAPE;			break;
-			case KEY_PAGE_UP:		llqt_key = LL_DOM_VK_PAGE_UP;		break;
-			case KEY_PAGE_DOWN:		llqt_key = LL_DOM_VK_PAGE_DOWN;		break;
-			case KEY_END:			llqt_key = LL_DOM_VK_END;			break;
-			case KEY_HOME:			llqt_key = LL_DOM_VK_HOME;			break;
-			case KEY_LEFT:			llqt_key = LL_DOM_VK_LEFT;			break;
-			case KEY_UP:			llqt_key = LL_DOM_VK_UP;				break;
-			case KEY_RIGHT:			llqt_key = LL_DOM_VK_RIGHT;			break;
-			case KEY_DOWN:			llqt_key = LL_DOM_VK_DOWN;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_PRINTSCREEN;	break;
-			case KEY_INSERT:		llqt_key = LL_DOM_VK_INSERT;			break;
-			case KEY_DELETE:		llqt_key = LL_DOM_VK_DELETE;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_CONTEXT_MENU;	break;
-			
-			default:
-				if(key < KEY_SPECIAL)
-				{
-					// Pass the incoming key through -- it should be regular ASCII, which should be correct for webkit.
-					llqt_key = key;
-				}
-				else
-				{
-					// Don't pass through untranslated special keys -- they'll be all wrong.
-					llqt_key = 0;
-				}
-			break;
-		}
-		
-//		std::cerr << "keypress, original code = 0x" << std::hex << key << ", converted code = 0x" << std::hex << llqt_key << std::dec << std::endl;
-		
-		if(llqt_key != 0)
-		{
-			LLQtWebKit::getInstance()->keyPress( mBrowserWindowId, llqt_key );
-		}
-
-		checkEditState();
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void unicodeInput( const std::string &utf8str )
-	{
-		LLWString wstr = utf8str_to_wstring(utf8str);
-		
-		unsigned int i;
-		for(i=0; i < wstr.size(); i++)
-		{
-//			std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl;
-			
-			LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i]);
-		}
-
-		checkEditState();
-	};
-	
-	void checkEditState(void)
-	{
-		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
-		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
-		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
-					
-		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
-			
-			if(can_cut != mCanCut)
-			{
-				mCanCut = can_cut;
-				message.setValueBoolean("cut", can_cut);
-			}
-
-			if(can_copy != mCanCopy)
-			{
-				mCanCopy = can_copy;
-				message.setValueBoolean("copy", can_copy);
-			}
-
-			if(can_paste != mCanPaste)
-			{
-				mCanPaste = can_paste;
-				message.setValueBoolean("paste", can_paste);
-			}
-			
-			sendMessage(message);
-			
-		}
-	}
-
-};
-
-MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
-	MediaPluginBase(host_send_func, host_user_data)
-{
-//	std::cerr << "MediaPluginWebKit constructor" << std::endl;
-
-	mBrowserWindowId = 0;
-	mBrowserInitialized = false;
-	mNeedsUpdate = true;
-	mCanCut = false;
-	mCanCopy = false;
-	mCanPaste = false;
-}
-
-MediaPluginWebKit::~MediaPluginWebKit()
-{
-	// unhook observer
-	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
-
-	// clean up
-	LLQtWebKit::getInstance()->reset();
-
-//	std::cerr << "MediaPluginWebKit destructor" << std::endl;
-}
-
-void MediaPluginWebKit::receiveMessage(const char *message_string)
-{
-//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
-	LLPluginMessage message_in;
-	
-	if(message_in.parse(message_string) >= 0)
-	{
-		std::string message_class = message_in.getClass();
-		std::string message_name = message_in.getName();
-		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
-		{
-			if(message_name == "init")
-			{
-				LLPluginMessage message("base", "init_response");
-				LLSD versions = LLSD::emptyMap();
-				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
-				message.setValueLLSD("versions", versions);
-
-				std::string plugin_version = "Webkit media plugin, Webkit version ";
-				plugin_version += LLQtWebKit::getInstance()->getVersion();
-				message.setValue("plugin_version", plugin_version);
-				sendMessage(message);
-				
-				// Plugin gets to decide the texture parameters to use.
-				mDepth = 4;
-
-				message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
-				message.setValueS32("default_width", 1024);
-				message.setValueS32("default_height", 1024);
-				message.setValueS32("depth", mDepth);
-				message.setValueU32("internalformat", GL_RGBA);
-				message.setValueU32("format", GL_RGBA);
-				message.setValueU32("type", GL_UNSIGNED_BYTE);
-				message.setValueBoolean("coords_opengl", true);
-				sendMessage(message);
-			}
-			else if(message_name == "idle")
-			{
-				// no response is necessary here.
-				F64 time = message_in.getValueReal("time");
-				
-				// Convert time to milliseconds for update()
-				update((int)(time * 1000.0f));
-			}
-			else if(message_name == "cleanup")
-			{
-				// TODO: clean up here
-			}
-			else if(message_name == "shm_added")
-			{
-				SharedSegmentInfo info;
-				info.mAddress = message_in.getValuePointer("address");
-				info.mSize = (size_t)message_in.getValueS32("size");
-				std::string name = message_in.getValue("name");
-				
-				
-//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name 
-//					<< ", size: " << info.mSize 
-//					<< ", address: " << info.mAddress 
-//					<< std::endl;
-
-				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-			
-			}
-			else if(message_name == "shm_remove")
-			{
-				std::string name = message_in.getValue("name");
-				
-//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
-
-				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-				if(iter != mSharedSegments.end())
-				{
-					if(mPixels == iter->second.mAddress)
-					{
-						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
-						mPixels = NULL;
-						mTextureSegmentName.clear();
-					}
-					mSharedSegments.erase(iter);
-				}
-				else
-				{
-//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
-				}
-
-				// Send the response so it can be cleaned up.
-				LLPluginMessage message("base", "shm_remove_response");
-				message.setValue("name", name);
-				sendMessage(message);
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
-		{
-			if(message_name == "size_change")
-			{
-				std::string name = message_in.getValue("name");
-				S32 width = message_in.getValueS32("width");
-				S32 height = message_in.getValueS32("height");
-				S32 texture_width = message_in.getValueS32("texture_width");
-				S32 texture_height = message_in.getValueS32("texture_height");
-				
-				if(!name.empty())
-				{
-					// Find the shared memory region with this name
-					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-					if(iter != mSharedSegments.end())
-					{
-						mPixels = (unsigned char*)iter->second.mAddress;
-						mWidth = width;
-						mHeight = height;
-
-						// initialize (only gets called once)
-						initBrowser();
-
-						// size changed so tell the browser
-						LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-						
-//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight 
-//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
-								
-						S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); 
-						
-						// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
-						if(real_width <= texture_width)
-						{
-							texture_width = real_width;
-						}
-						else
-						{
-							// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error.
-//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
-							mDeleteMe = true;
-							return;
-						}
-						
-						mTextureWidth = texture_width;
-						mTextureHeight = texture_height;
-						
-					};
-				};
-
-				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
-				message.setValue("name", name);
-				message.setValueS32("width", width);
-				message.setValueS32("height", height);
-				message.setValueS32("texture_width", texture_width);
-				message.setValueS32("texture_height", texture_height);
-				sendMessage(message);
-
-			}
-			else if(message_name == "load_uri")
-			{
-				std::string uri = message_in.getValue("uri");
-
-//				std::cout << "loading URI: " << uri << std::endl;
-				
-				if(!uri.empty())
-				{
-					LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
-				}
-			}
-			else if(message_name == "mouse_event")
-			{
-				std::string event = message_in.getValue("event");
-				S32 x = message_in.getValueS32("x");
-				S32 y = message_in.getValueS32("y");
-				// std::string modifiers = message.getValue("modifiers");
-	
-				if(event == "down")
-				{
-					mouseDown(x, y);
-					//std::cout << "Mouse down at " << x << " x " << y << std::endl;
-				}
-				else if(event == "up")
-				{
-					mouseUp(x, y);
-					//std::cout << "Mouse up at " << x << " x " << y << std::endl;
-				}
-				else if(event == "move")
-				{
-					mouseMove(x, y);
-					//std::cout << ">>>>>>>>>>>>>>>>>>>> Mouse move at " << x << " x " << y << std::endl;
-				}
-			}
-			else if(message_name == "scroll_event")
-			{
-				// S32 x = message_in.getValueS32("x");
-				S32 y = message_in.getValueS32("y");
-				// std::string modifiers = message.getValue("modifiers");
-				
-				// We currently ignore horizontal scrolling.
-				// The scroll values are roughly 1 per wheel click, so we need to magnify them by some factor.
-				// Arbitrarily, I choose 16.
-				y *= 16;
-				LLQtWebKit::getInstance()->scrollByLines(mBrowserWindowId, y);
-			}
-			else if(message_name == "key_event")
-			{
-				std::string event = message_in.getValue("event");
-
-				// act on "key down" or "key repeat"
-				if ( (event == "down") || (event == "repeat") )
-				{
-					S32 key = message_in.getValueS32("key");
-					keyPress( key );
-				};
-			}
-			else if(message_name == "text_event")
-			{
-				std::string text = message_in.getValue("text");
-				
-				unicodeInput(text);
-			}
-			if(message_name == "edit_cut")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
-			}
-			if(message_name == "edit_copy")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
-			}
-			if(message_name == "edit_paste")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
-			};
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
-		{
-			if(message_name == "focus")
-			{
-				bool val = message_in.getValueBoolean("focused");
-				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
-			}
-			else if(message_name == "clear_cache")
-			{
-				LLQtWebKit::getInstance()->clearCache();
-			}
-			else if(message_name == "clear_cookies")
-			{
-				LLQtWebKit::getInstance()->clearAllCookies();
-			}
-			else if(message_name == "enable_cookies")
-			{
-				bool val = message_in.getValueBoolean("enable");
-				LLQtWebKit::getInstance()->enableCookies( val );
-			}
-			else if(message_name == "proxy_setup")
-			{
-				bool val = message_in.getValueBoolean("enable");
-				std::string host = message_in.getValue("host");
-				int port = message_in.getValueS32("port");
-				LLQtWebKit::getInstance()->enableProxy( val, host, port );
-			}
-			else if(message_name == "browse_stop")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
-			}
-			else if(message_name == "browse_reload")
-			{
-				// foo = message_in.getValueBoolean("ignore_cache");
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
-			}
-			else if(message_name == "browse_forward")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
-			}
-			else if(message_name == "browse_back")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
-			}
-			else if(message_name == "set_status_redirect")
-			{
-				int code = message_in.getValueS32("code");
-				std::string url = message_in.getValue("url");
-				if ( 404 == code )	// browser lib only supports 404 right now
-				{
-					LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
-				};
-			}
-			else if(message_name == "set_user_agent")
-			{
-				std::string user_agent = message_in.getValue("user_agent");
-				LLQtWebKit::getInstance()->setBrowserAgentId( user_agent );
-			}
-			else if(message_name == "init_history")
-			{
-				// Initialize browser history
-				LLSD history = message_in.getValueLLSD("history");
-				// First, clear the URL history
-				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
-				// Then, add the history items in order
-				LLSD::array_iterator iter_history = history.beginArray();
-				LLSD::array_iterator end_history = history.endArray();
-				for(; iter_history != end_history; ++iter_history)
-				{
-					std::string url = (*iter_history).asString();
-					if(! url.empty()) {
-						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
-					}
-				}
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
-			};
-		}
-		else
-		{
-//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
-		};
-	}
-}
-
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
-	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
-	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
-	*plugin_user_data = (void*)self;
-
-	return 0;
-}
-
+/** 
+ * @file media_plugin_webkit.cpp
+ * @brief Webkit plugin for LLMedia API plugin system
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llqtwebkit.h"
+
+#include "linden_common.h"
+#include "indra_constants.h" // for indra keyboard codes
+
+#include "llgl.h"
+
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.h"
+
+#if LL_WINDOWS
+#include <direct.h>
+#else
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+
+#if LL_WINDOWS
+	// *NOTE:Mani - This captures the module handle fo rthe dll. This is used below
+	// to get the path to this dll for webkit initialization.
+	// I don't know how/if this can be done with apr...
+	namespace {	HMODULE gModuleHandle;};
+	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+	{
+		gModuleHandle = (HMODULE) hinstDLL;
+		return TRUE;
+	}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginWebKit : 
+		public MediaPluginBase,
+		public LLEmbeddedBrowserWindowObserver
+{
+public:
+	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+	~MediaPluginWebKit();
+
+	/*virtual*/ void receiveMessage(const char *message_string);
+
+private:
+
+	int mBrowserWindowId;
+	bool mBrowserInitialized;
+	bool mNeedsUpdate;
+
+	bool	mCanCut;
+	bool	mCanCopy;
+	bool	mCanPaste;
+	
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void update(int milliseconds)
+	{
+		LLQtWebKit::getInstance()->pump( milliseconds );
+		
+		checkEditState();
+		
+		if ( mNeedsUpdate )
+		{
+			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
+
+			unsigned int buffer_size = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) * LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
+			
+//			std::cerr << "webkit plugin: updating" << std::endl;
+			
+			// TODO: should get rid of this memcpy if possible
+			if ( mPixels && browser_pixels )
+			{
+//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl;
+				memcpy( mPixels, browser_pixels, buffer_size );
+			}
+
+			if ( mWidth > 0 && mHeight > 0 )
+			{
+//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
+				setDirty( 0, 0, mWidth, mHeight );
+			}
+
+			mNeedsUpdate = false;
+		};
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	bool initBrowser()
+	{
+		// already initialized
+		if ( mBrowserInitialized )
+			return true;
+
+		// not enough information to initialize the browser yet.
+		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || 
+				mTextureWidth < 0 || mTextureHeight < 0 )
+		{
+			return false;
+		};
+
+		// set up directories
+		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
+		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
+		{
+			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
+			return false;
+		}
+		std::string application_dir = std::string( cwd );
+
+#if LL_WINDOWS
+		//*NOTE:Mani - On windows, at least, the component path is the
+		// location of this dll's image file. 
+		std::string component_dir;
+		char dll_path[_MAX_PATH];
+		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH);
+		while(len && dll_path[ len ] != ('\\') )
+		{
+			len--;
+		}
+		if(len >= 0)
+		{
+			dll_path[len] = 0;
+			component_dir = dll_path;
+		}
+		else
+		{
+			// *NOTE:Mani - This case should be an rare exception. 
+			// GetModuleFileNameA should always give you a full path, no?
+			component_dir = application_dir;
+		}
+#else
+		std::string component_dir = application_dir;
+#endif
+		std::string profileDir = application_dir + "/" + "browser_profile";		// cross platform?
+
+		// window handle - needed on Windows and must be app window.
+#if LL_WINDOWS
+		char window_title[ MAX_PATH ];
+		GetConsoleTitleA( window_title, MAX_PATH );
+		void* native_window_handle = (void*)FindWindowA( NULL, window_title );
+#else
+		void* native_window_handle = 0;
+#endif
+
+		// main browser initialization
+		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, profileDir, native_window_handle );
+		if ( result )
+		{
+			// create single browser window
+			mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight );
+
+#if LL_WINDOWS
+			// Enable plugins
+			LLQtWebKit::getInstance()->enablePlugins(true);
+#elif LL_DARWIN
+			// Disable plugins
+			LLQtWebKit::getInstance()->enablePlugins(false);
+#elif LL_LINUX
+			// Disable plugins
+			LLQtWebKit::getInstance()->enablePlugins(false);
+#endif
+            
+			// tell LLQtWebKit about the size of the browser window
+			LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
+
+			// observer events that LLQtWebKit emits
+			LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
+
+			// append details to agent string
+			LLQtWebKit::getInstance()->setBrowserAgentId( "LLPluginMedia Web Browser" );
+
+			// don't flip bitmap
+			LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
+			
+			// Set the background color to black
+			LLQtWebKit::getInstance()->
+			// set background color to be black - mostly for initial login page
+			LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 );
+
+			// go to the "home page"
+			// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
+//			LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
+
+			// set flag so we don't do this again
+			mBrowserInitialized = true;
+
+			return true;
+		};
+
+		return false;
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onCursorChanged(const EventType& event)
+	{
+		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
+		std::string name;
+
+		switch(llqt_cursor)
+		{
+			case LLQtWebKit::C_ARROW:
+				name = "arrow";
+			break;
+			case LLQtWebKit::C_IBEAM:
+				name = "ibeam";
+			break;
+			case LLQtWebKit::C_SPLITV:
+				name = "splitv";
+			break;
+			case LLQtWebKit::C_SPLITH:
+				name = "splith";
+			break;
+			case LLQtWebKit::C_POINTINGHAND:
+				name = "hand";
+			break;
+			
+			default:
+				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
+			break;
+		}
+		
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
+		message.setValue("name", name);
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onPageChanged( const EventType& event )
+	{
+		// flag that an update is required
+		mNeedsUpdate = true;
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onNavigateBegin(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
+		message.setValue("uri", event.getEventUri());
+		sendMessage(message);
+
+		setStatus(STATUS_LOADING);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onNavigateComplete(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
+		message.setValue("uri", event.getEventUri());
+		message.setValueS32("result_code", event.getIntValue());
+		message.setValue("result_string", event.getStringValue());
+		message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
+		message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
+		sendMessage(message);
+		
+		setStatus(STATUS_LOADED);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onUpdateProgress(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
+		message.setValueS32("percent", event.getIntValue());
+		sendMessage(message);
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onStatusTextChange(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
+		message.setValue("status", event.getStringValue());
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onTitleChange(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+		message.setValue("name", event.getStringValue());
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onLocationChange(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
+		message.setValue("uri", event.getEventUri());
+		sendMessage(message);
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onClickLinkHref(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
+		message.setValue("uri", event.getStringValue());
+		message.setValue("target", event.getStringValue2());
+		sendMessage(message);
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onClickLinkNoFollow(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
+		message.setValue("uri", event.getStringValue());
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void mouseDown( int x, int y )
+	{
+		LLQtWebKit::getInstance()->mouseDown( mBrowserWindowId, x, y );
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void mouseUp( int x, int y )
+	{
+		LLQtWebKit::getInstance()->mouseUp( mBrowserWindowId, x, y );
+		LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, true );
+		checkEditState();
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void mouseMove( int x, int y )
+	{
+		LLQtWebKit::getInstance()->mouseMove( mBrowserWindowId, x, y );
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void keyPress( int key )
+	{
+		int llqt_key;
+		
+		// The incoming values for 'key' will be the ones from indra_constants.h
+		// the outgoing values are the ones from llqtwebkit.h
+		
+		switch((KEY)key)
+		{
+			// This is the list that the llqtwebkit implementation actually maps into Qt keys.
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_CANCEL;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_HELP;			break;
+			case KEY_BACKSPACE:		llqt_key = LL_DOM_VK_BACK_SPACE;		break;
+			case KEY_TAB:			llqt_key = LL_DOM_VK_TAB;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_CLEAR;			break;
+			case KEY_RETURN:		llqt_key = LL_DOM_VK_RETURN;			break;
+			case KEY_PAD_RETURN:	llqt_key = LL_DOM_VK_ENTER;			break;
+			case KEY_SHIFT:			llqt_key = LL_DOM_VK_SHIFT;			break;
+			case KEY_CONTROL:		llqt_key = LL_DOM_VK_CONTROL;		break;
+			case KEY_ALT:			llqt_key = LL_DOM_VK_ALT;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_PAUSE;			break;
+			case KEY_CAPSLOCK:		llqt_key = LL_DOM_VK_CAPS_LOCK;		break;
+			case KEY_ESCAPE:		llqt_key = LL_DOM_VK_ESCAPE;			break;
+			case KEY_PAGE_UP:		llqt_key = LL_DOM_VK_PAGE_UP;		break;
+			case KEY_PAGE_DOWN:		llqt_key = LL_DOM_VK_PAGE_DOWN;		break;
+			case KEY_END:			llqt_key = LL_DOM_VK_END;			break;
+			case KEY_HOME:			llqt_key = LL_DOM_VK_HOME;			break;
+			case KEY_LEFT:			llqt_key = LL_DOM_VK_LEFT;			break;
+			case KEY_UP:			llqt_key = LL_DOM_VK_UP;				break;
+			case KEY_RIGHT:			llqt_key = LL_DOM_VK_RIGHT;			break;
+			case KEY_DOWN:			llqt_key = LL_DOM_VK_DOWN;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_PRINTSCREEN;	break;
+			case KEY_INSERT:		llqt_key = LL_DOM_VK_INSERT;			break;
+			case KEY_DELETE:		llqt_key = LL_DOM_VK_DELETE;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_CONTEXT_MENU;	break;
+			
+			default:
+				if(key < KEY_SPECIAL)
+				{
+					// Pass the incoming key through -- it should be regular ASCII, which should be correct for webkit.
+					llqt_key = key;
+				}
+				else
+				{
+					// Don't pass through untranslated special keys -- they'll be all wrong.
+					llqt_key = 0;
+				}
+			break;
+		}
+		
+//		std::cerr << "keypress, original code = 0x" << std::hex << key << ", converted code = 0x" << std::hex << llqt_key << std::dec << std::endl;
+		
+		if(llqt_key != 0)
+		{
+			LLQtWebKit::getInstance()->keyPress( mBrowserWindowId, llqt_key );
+		}
+
+		checkEditState();
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void unicodeInput( const std::string &utf8str )
+	{
+		LLWString wstr = utf8str_to_wstring(utf8str);
+		
+		unsigned int i;
+		for(i=0; i < wstr.size(); i++)
+		{
+//			std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl;
+			
+			LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i]);
+		}
+
+		checkEditState();
+	};
+	
+	void checkEditState(void)
+	{
+		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
+		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
+		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
+					
+		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
+			
+			if(can_cut != mCanCut)
+			{
+				mCanCut = can_cut;
+				message.setValueBoolean("cut", can_cut);
+			}
+
+			if(can_copy != mCanCopy)
+			{
+				mCanCopy = can_copy;
+				message.setValueBoolean("copy", can_copy);
+			}
+
+			if(can_paste != mCanPaste)
+			{
+				mCanPaste = can_paste;
+				message.setValueBoolean("paste", can_paste);
+			}
+			
+			sendMessage(message);
+			
+		}
+	}
+
+};
+
+MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
+	MediaPluginBase(host_send_func, host_user_data)
+{
+//	std::cerr << "MediaPluginWebKit constructor" << std::endl;
+
+	mBrowserWindowId = 0;
+	mBrowserInitialized = false;
+	mNeedsUpdate = true;
+	mCanCut = false;
+	mCanCopy = false;
+	mCanPaste = false;
+}
+
+MediaPluginWebKit::~MediaPluginWebKit()
+{
+	// unhook observer
+	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
+
+	// clean up
+	LLQtWebKit::getInstance()->reset();
+
+//	std::cerr << "MediaPluginWebKit destructor" << std::endl;
+}
+
+void MediaPluginWebKit::receiveMessage(const char *message_string)
+{
+//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+	LLPluginMessage message_in;
+	
+	if(message_in.parse(message_string) >= 0)
+	{
+		std::string message_class = message_in.getClass();
+		std::string message_name = message_in.getName();
+		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+		{
+			if(message_name == "init")
+			{
+				LLPluginMessage message("base", "init_response");
+				LLSD versions = LLSD::emptyMap();
+				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
+				message.setValueLLSD("versions", versions);
+
+				std::string plugin_version = "Webkit media plugin, Webkit version ";
+				plugin_version += LLQtWebKit::getInstance()->getVersion();
+				message.setValue("plugin_version", plugin_version);
+				sendMessage(message);
+				
+				// Plugin gets to decide the texture parameters to use.
+				mDepth = 4;
+
+				message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+				message.setValueS32("default_width", 1024);
+				message.setValueS32("default_height", 1024);
+				message.setValueS32("depth", mDepth);
+				message.setValueU32("internalformat", GL_RGBA);
+				message.setValueU32("format", GL_RGBA);
+				message.setValueU32("type", GL_UNSIGNED_BYTE);
+				message.setValueBoolean("coords_opengl", true);
+				sendMessage(message);
+			}
+			else if(message_name == "idle")
+			{
+				// no response is necessary here.
+				F64 time = message_in.getValueReal("time");
+				
+				// Convert time to milliseconds for update()
+				update((int)(time * 1000.0f));
+			}
+			else if(message_name == "cleanup")
+			{
+				// TODO: clean up here
+			}
+			else if(message_name == "shm_added")
+			{
+				SharedSegmentInfo info;
+				info.mAddress = message_in.getValuePointer("address");
+				info.mSize = (size_t)message_in.getValueS32("size");
+				std::string name = message_in.getValue("name");
+				
+				
+//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name 
+//					<< ", size: " << info.mSize 
+//					<< ", address: " << info.mAddress 
+//					<< std::endl;
+
+				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+			
+			}
+			else if(message_name == "shm_remove")
+			{
+				std::string name = message_in.getValue("name");
+				
+//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
+
+				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+				if(iter != mSharedSegments.end())
+				{
+					if(mPixels == iter->second.mAddress)
+					{
+						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
+						mPixels = NULL;
+						mTextureSegmentName.clear();
+					}
+					mSharedSegments.erase(iter);
+				}
+				else
+				{
+//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
+				}
+
+				// Send the response so it can be cleaned up.
+				LLPluginMessage message("base", "shm_remove_response");
+				message.setValue("name", name);
+				sendMessage(message);
+			}
+			else
+			{
+//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
+			}
+		}
+		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+		{
+			if(message_name == "size_change")
+			{
+				std::string name = message_in.getValue("name");
+				S32 width = message_in.getValueS32("width");
+				S32 height = message_in.getValueS32("height");
+				S32 texture_width = message_in.getValueS32("texture_width");
+				S32 texture_height = message_in.getValueS32("texture_height");
+				
+				if(!name.empty())
+				{
+					// Find the shared memory region with this name
+					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+					if(iter != mSharedSegments.end())
+					{
+						mPixels = (unsigned char*)iter->second.mAddress;
+						mWidth = width;
+						mHeight = height;
+
+						// initialize (only gets called once)
+						initBrowser();
+
+						// size changed so tell the browser
+						LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
+						
+//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight 
+//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
+								
+						S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); 
+						
+						// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
+						if(real_width <= texture_width)
+						{
+							texture_width = real_width;
+						}
+						else
+						{
+							// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error.
+//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
+							mDeleteMe = true;
+							return;
+						}
+						
+						mTextureWidth = texture_width;
+						mTextureHeight = texture_height;
+						
+					};
+				};
+
+				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+				message.setValue("name", name);
+				message.setValueS32("width", width);
+				message.setValueS32("height", height);
+				message.setValueS32("texture_width", texture_width);
+				message.setValueS32("texture_height", texture_height);
+				sendMessage(message);
+
+			}
+			else if(message_name == "load_uri")
+			{
+				std::string uri = message_in.getValue("uri");
+
+//				std::cout << "loading URI: " << uri << std::endl;
+				
+				if(!uri.empty())
+				{
+					LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
+				}
+			}
+			else if(message_name == "mouse_event")
+			{
+				std::string event = message_in.getValue("event");
+				S32 x = message_in.getValueS32("x");
+				S32 y = message_in.getValueS32("y");
+				// std::string modifiers = message.getValue("modifiers");
+	
+				if(event == "down")
+				{
+					mouseDown(x, y);
+					//std::cout << "Mouse down at " << x << " x " << y << std::endl;
+				}
+				else if(event == "up")
+				{
+					mouseUp(x, y);
+					//std::cout << "Mouse up at " << x << " x " << y << std::endl;
+				}
+				else if(event == "move")
+				{
+					mouseMove(x, y);
+					//std::cout << ">>>>>>>>>>>>>>>>>>>> Mouse move at " << x << " x " << y << std::endl;
+				}
+			}
+			else if(message_name == "scroll_event")
+			{
+				// S32 x = message_in.getValueS32("x");
+				S32 y = message_in.getValueS32("y");
+				// std::string modifiers = message.getValue("modifiers");
+				
+				// We currently ignore horizontal scrolling.
+				// The scroll values are roughly 1 per wheel click, so we need to magnify them by some factor.
+				// Arbitrarily, I choose 16.
+				y *= 16;
+				LLQtWebKit::getInstance()->scrollByLines(mBrowserWindowId, y);
+			}
+			else if(message_name == "key_event")
+			{
+				std::string event = message_in.getValue("event");
+
+				// act on "key down" or "key repeat"
+				if ( (event == "down") || (event == "repeat") )
+				{
+					S32 key = message_in.getValueS32("key");
+					keyPress( key );
+				};
+			}
+			else if(message_name == "text_event")
+			{
+				std::string text = message_in.getValue("text");
+				
+				unicodeInput(text);
+			}
+			if(message_name == "edit_cut")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
+			}
+			if(message_name == "edit_copy")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
+			}
+			if(message_name == "edit_paste")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
+			}
+			else
+			{
+//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
+			};
+		}
+		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
+		{
+			if(message_name == "focus")
+			{
+				bool val = message_in.getValueBoolean("focused");
+				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
+			}
+			else if(message_name == "clear_cache")
+			{
+				LLQtWebKit::getInstance()->clearCache();
+			}
+			else if(message_name == "clear_cookies")
+			{
+				LLQtWebKit::getInstance()->clearAllCookies();
+			}
+			else if(message_name == "enable_cookies")
+			{
+				bool val = message_in.getValueBoolean("enable");
+				LLQtWebKit::getInstance()->enableCookies( val );
+			}
+			else if(message_name == "proxy_setup")
+			{
+				bool val = message_in.getValueBoolean("enable");
+				std::string host = message_in.getValue("host");
+				int port = message_in.getValueS32("port");
+				LLQtWebKit::getInstance()->enableProxy( val, host, port );
+			}
+			else if(message_name == "browse_stop")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
+			}
+			else if(message_name == "browse_reload")
+			{
+				// foo = message_in.getValueBoolean("ignore_cache");
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
+			}
+			else if(message_name == "browse_forward")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
+			}
+			else if(message_name == "browse_back")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
+			}
+			else if(message_name == "set_status_redirect")
+			{
+				int code = message_in.getValueS32("code");
+				std::string url = message_in.getValue("url");
+				if ( 404 == code )	// browser lib only supports 404 right now
+				{
+					LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
+				};
+			}
+			else if(message_name == "set_user_agent")
+			{
+				std::string user_agent = message_in.getValue("user_agent");
+				LLQtWebKit::getInstance()->setBrowserAgentId( user_agent );
+			}
+			else if(message_name == "init_history")
+			{
+				// Initialize browser history
+				LLSD history = message_in.getValueLLSD("history");
+				// First, clear the URL history
+				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
+				// Then, add the history items in order
+				LLSD::array_iterator iter_history = history.beginArray();
+				LLSD::array_iterator end_history = history.endArray();
+				for(; iter_history != end_history; ++iter_history)
+				{
+					std::string url = (*iter_history).asString();
+					if(! url.empty()) {
+						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
+					}
+				}
+			}
+			else
+			{
+//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
+			};
+		}
+		else
+		{
+//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
+		};
+	}
+}
+
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
+{
+	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
+	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
+	*plugin_user_data = (void*)self;
+
+	return 0;
+}
+
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 26170d171375176ad12c1b1ca6fd284a29323bed..dd3937a6eff2e79a81bb13bfb919a682919b3567 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -36,10 +36,8 @@ include(UI)
 include(UnixInstall)
 include(LLKDU)
 include(ViewerMiscLibs)
-
-if (WINDOWS)
-    include(CopyWinLibs)
-endif (WINDOWS)
+include(LLLogin)
+include(CMakeCopyIfDifferent)
 
 include_directories(
     ${DBUSGLIB_INCLUDE_DIRS}
@@ -61,12 +59,14 @@ include_directories(
     ${LLXUIXML_INCLUDE_DIRS}
     ${LSCRIPT_INCLUDE_DIRS}
     ${LSCRIPT_INCLUDE_DIRS}/lscript_compile
+    ${LLLOGIN_INCLUDE_DIRS}
     )
 
 set(viewer_SOURCE_FILES
     llaccordionctrltab.cpp
     llaccordionctrl.cpp
     llagent.cpp
+    llagentlistener.cpp
     llagentaccess.cpp
     llagentdata.cpp
     llagentlanguage.cpp
@@ -77,6 +77,7 @@ set(viewer_SOURCE_FILES
     llanimstatelabels.cpp
     llappearancemgr.cpp
     llappviewer.cpp
+    llappviewerlistener.cpp
     llassetuploadresponders.cpp
     llassetuploadqueue.cpp
     llaudiosourcevo.cpp
@@ -262,6 +263,7 @@ set(viewer_SOURCE_FILES
     llurllineeditorctrl.cpp
     lllogchat.cpp
     llloginhandler.cpp
+    lllogininstance.cpp
     llmanip.cpp
     llmaniprotate.cpp
     llmanipscale.cpp
@@ -333,6 +335,7 @@ set(viewer_SOURCE_FILES
     llpanelpicks.cpp
     llpanelplace.cpp
     llpanelplaceinfo.cpp
+    llpanelshower.cpp
     llpanelplaces.cpp
     llpanelplacestab.cpp
     llpanelprofile.cpp
@@ -370,7 +373,6 @@ set(viewer_SOURCE_FILES
     llspatialpartition.cpp
     llsplitbutton.cpp
     llsprite.cpp
-    llsrv.cpp
     llstartup.cpp
     llstatusbar.cpp
     llstylemap.cpp
@@ -417,19 +419,20 @@ set(viewer_SOURCE_FILES
     lltracker.cpp
     lltransientdockablefloater.cpp
     lltransientfloatermgr.cpp
+    lluilistener.cpp
     lluploaddialog.cpp
     llurl.cpp
     llurldispatcher.cpp
     llurlhistory.cpp
     llurlsimstring.cpp
     llurlwhitelist.cpp
-    lluserauth.cpp
     llvectorperfoptions.cpp
     llviewchildren.cpp
     llviewerassetstorage.cpp
     llvieweraudio.cpp
     llviewercamera.cpp
     llviewercontrol.cpp
+    llviewercontrollistener.cpp
     llviewerdisplay.cpp
     llviewerfloaterreg.cpp
     llviewergenericmessage.cpp
@@ -471,6 +474,7 @@ set(viewer_SOURCE_FILES
     llviewerthrottle.cpp
     llviewervisualparam.cpp
     llviewerwindow.cpp
+    llviewerwindowlistener.cpp
     llvlcomposition.cpp
     llvlmanager.cpp
     llvoavatar.cpp
@@ -508,6 +512,7 @@ set(viewer_SOURCE_FILES
     llworld.cpp
     llworldmap.cpp
     llworldmapview.cpp
+    llxmlrpclistener.cpp
     llxmlrpctransaction.cpp
     noise.cpp
     pipeline.cpp
@@ -536,6 +541,7 @@ set(viewer_HEADER_FILES
     llaccordionctrltab.h
     llaccordionctrl.h
     llagent.h
+    llagentlistener.h
     llagentaccess.h
     llagentdata.h
     llagentlanguage.h
@@ -546,6 +552,7 @@ set(viewer_HEADER_FILES
     llanimstatelabels.h
     llappearance.h
     llappviewer.h
+    llappviewerlistener.h
     llassetuploadresponders.h
     llassetuploadqueue.h
     llaudiosourcevo.h
@@ -734,6 +741,7 @@ set(viewer_HEADER_FILES
     llurllineeditorctrl.h
     lllogchat.h
     llloginhandler.h
+    lllogininstance.h
     llmanip.h
     llmaniprotate.h
     llmanipscale.h
@@ -801,6 +809,7 @@ set(viewer_HEADER_FILES
     llpanelpicks.h
     llpanelplace.h
     llpanelplaceinfo.h
+    llpanelshower.h
     llpanelplaces.h
     llpanelplacestab.h
     llpanelprofile.h
@@ -840,7 +849,6 @@ set(viewer_HEADER_FILES
     llspatialpartition.h
     llsplitbutton.h
     llsprite.h
-    llsrv.h
     llstartup.h
     llstatusbar.h
     llstylemap.h
@@ -889,13 +897,13 @@ set(viewer_HEADER_FILES
     lltransientdockablefloater.h
     lltransientfloatermgr.h
     lluiconstants.h
+    lluilistener.h
     lluploaddialog.h
     llurl.h
     llurldispatcher.h
     llurlhistory.h
     llurlsimstring.h
     llurlwhitelist.h
-    lluserauth.h
     llvectorperfoptions.h
     llviewchildren.h
     llviewerassetstorage.h
@@ -903,6 +911,7 @@ set(viewer_HEADER_FILES
     llviewerbuild.h
     llviewercamera.h
     llviewercontrol.h
+    llviewercontrollistener.h
     llviewerdisplay.h
     llviewerfloaterreg.h
     llviewergenericmessage.h
@@ -941,6 +950,7 @@ set(viewer_HEADER_FILES
     llviewerthrottle.h
     llviewervisualparam.h
     llviewerwindow.h
+    llviewerwindowlistener.h
     llvlcomposition.h
     llvlmanager.h
     llvoavatar.h
@@ -981,6 +991,7 @@ set(viewer_HEADER_FILES
     llworld.h
     llworldmap.h
     llworldmapview.h
+    llxmlrpclistener.h
     llxmlrpctransaction.h
     macmain.h
     noise.h
@@ -1137,7 +1148,6 @@ if (WINDOWS)
         comdlg32
         ${DINPUT_LIBRARY}
         ${DXGUID_LIBRARY}
-        fmodvc
         kernel32
         odbc32
         odbccp32
@@ -1181,6 +1191,15 @@ file(GLOB DEFAULT_WIDGET_FILE_GLOB_LIST
      ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en/widgets/*.xml)
 list(APPEND viewer_XUI_FILES ${DEFAULT_WIDGET_FILE_GLOB_LIST})
 
+file(GLOB SILVER_XUI_FILE_GLOB_LIST
+     ${CMAKE_CURRENT_SOURCE_DIR}/skins/silver/xui/en-us/*.xml)
+list(APPEND viewer_XUI_FILES ${SILVER_XUI_FILE_GLOB_LIST})
+
+# Cannot append empty lists in CMake, wait until we have files here.
+#file(GLOB SILVER_WIDGET_FILE_GLOB_LIST
+#     ${CMAKE_CURRENT_SOURCE_DIR}/skins/silver/xui/en-us/widgets/*.xml)
+#list(APPEND viewer_XUI_FILES ${SILVER_WIDGET_FILE_GLOB_LIST})
+
 list(SORT viewer_XUI_FILES)
 
 source_group("XUI Files" FILES ${viewer_XUI_FILES})
@@ -1255,23 +1274,23 @@ endif (OPENAL)
 if (FMOD)
   set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD")
 
-  if (NOT WINDOWS)
+  if (DARWIN)
     set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp)
     add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES})
-    set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY})
-    if (DARWIN)
-      list(APPEND fmodwrapper_needed_LIBRARIES ${CARBON_LIBRARY})
-      set_target_properties(
-        fmodwrapper
-        PROPERTIES
-        BUILD_WITH_INSTALL_RPATH 1
-        INSTALL_NAME_DIR "@executable_path/../Resources"
-        LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp"
-        )
-    endif (DARWIN)
+    set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY})
+    set_target_properties(
+      fmodwrapper
+      PROPERTIES
+      BUILD_WITH_INSTALL_RPATH 1
+      INSTALL_NAME_DIR "@executable_path/../Resources"
+      LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp"
+      )
     set(FMODWRAPPER_LIBRARY fmodwrapper)
     target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
-  endif (NOT WINDOWS)
+  else (DARWIN)
+    # fmodwrapper unnecessary on linux or windows
+    set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY})
+  endif (DARWIN)
 endif (FMOD)
 
 set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
@@ -1292,6 +1311,11 @@ if (LLKDU_LIBRARY)
   add_dependencies(${VIEWER_BINARY_NAME} ${LLKDU_LIBRARY})
 endif (LLKDU_LIBRARY)
 
+# add package files
+file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST
+     ${CMAKE_CURRENT_SOURCE_DIR}/../viewer_components/*.py)
+list(APPEND EVENT_HOST_SCRIPTS ${EVENT_HOST_SCRIPT_GLOB_LIST})
+
 set(PACKAGE OFF CACHE BOOL
     "Add a package target that builds an installer package.")
 
@@ -1348,7 +1372,28 @@ if (WINDOWS)
         COMMENT "Copying message.xml to the runtime folder."
         )
        
-    add_dependencies(${VIEWER_BINARY_NAME} copy_win_libs)
+    if(WINDOWS)
+      # Copy Win Libs...
+      # This happens at build time, not config time. We can't glob files in this cmake.
+      # *FIX:Mani Write a sub script to glob the files...
+      # *FIX:Mani Use actually dependencies rather than bulk copy.
+      add_custom_command(
+        TARGET ${VIEWER_BINARY_NAME} PRE_BUILD
+        COMMAND ${CMAKE_COMMAND}
+        ARGS
+          -E
+          copy_directory
+          ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}
+          ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
+        COMMENT "Copying staged dlls."
+        )
+
+      add_dependencies(${VIEWER_BINARY_NAME} stage_third_party_libs llcommon)
+      if(LLKDU_LIBRARY)
+	# kdu may not exist!
+	add_dependencies(${VIEWER_BINARY_NAME} llkdu)
+      endif(LLKDU_LIBRARY)
+    endif(WINDOWS)    
 
     if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
       add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
@@ -1374,8 +1419,29 @@ if (WINDOWS)
     add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit)
 
     if (PACKAGE)
-      add_custom_target(package ALL DEPENDS ${CMAKE_CFG_INTDIR}/touched.bat)
+      add_custom_command(
+          OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2
+          COMMAND ${PYTHON_EXECUTABLE}
+          ARGS
+            ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/..
+            ${CMAKE_CURRENT_BINARY_DIR}
+            ${CMAKE_CFG_INTDIR}
+
+          DEPENDS 
+            lleventhost 
+            ${EVENT_HOST_SCRIPTS}
+            ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py)
+
+      add_custom_target(package ALL 
+          DEPENDS 
+            ${CMAKE_CFG_INTDIR}/touched.bat)
+            # temporarily disable packaging of event_host until hg subrepos get
+            # sorted out on the parabuild cluster...
+            #${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2)
       add_dependencies(package windows-updater windows-crash-logger)
+
+
     endif (PACKAGE)
 endif (WINDOWS)
 
@@ -1412,6 +1478,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${WINDOWS_LIBRARIES}
     ${XMLRPCEPI_LIBRARIES}
     ${ELFIO_LIBRARIES}
+    ${LLLOGIN_LIBRARIES}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     )
 
@@ -1545,7 +1612,9 @@ include(LLAddBuildTest)
 SET(viewer_TEST_SOURCE_FILES
   llagentaccess.cpp
   lldateutil.cpp
+  llmediadataclient.cpp
   llviewerhelputil.cpp
+  lllogininstance.cpp
   )
 set_source_files_properties(
   ${viewer_TEST_SOURCE_FILES}
@@ -1562,6 +1631,7 @@ set(test_libs
   ${LLVFS_LIBRARIES}
   ${LLMATH_LIBRARIES}
   ${LLCOMMON_LIBRARIES} 
+  ${GOOGLEMOCK_LIBRARIES}
   )
 
 LL_ADD_INTEGRATION_TEST(llcapabilitylistener 
@@ -1576,6 +1646,16 @@ LL_ADD_INTEGRATION_TEST(llcapabilitylistener
 
 # Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py
 if (WINDOWS)
+  add_custom_command(
+      TARGET ${VIEWER_BINARY_NAME} POST_BUILD
+      COMMAND ${CMAKE_COMMAND}
+      ARGS
+        -E
+        make_directory
+        ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin
+      COMMENT "Creating llplugin dir."
+      )
+
   get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION)
   add_custom_command(
       TARGET ${VIEWER_BINARY_NAME} POST_BUILD
@@ -1611,5 +1691,72 @@ if (WINDOWS)
           ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin
         COMMENT "Copying Quicktime Plugin to the runtime folder."
         )
+
+  #*******************************
+  # Copy media plugin support dlls
+  # Debug config runtime files required for the plugins
+  set(plugins_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
+  set(plugins_debug_files
+    libeay32.dll
+    qtcored4.dll
+    qtguid4.dll
+    qtnetworkd4.dll
+    qtopengld4.dll
+    qtwebkitd4.dll
+    ssleay32.dll
+    )
+  copy_if_different(
+    ${plugins_debug_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/Debug/llplugin"
+    out_targets
+    ${plugins_debug_files}
+    )
+  set(media_plugin_targets ${media_plugin_targets} ${out_targets})
+  
+  # Release & ReleaseDebInfo config runtime files required for the plugins
+  set(plugins_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
+  set(plugins_release_files
+    libeay32.dll
+    qtcore4.dll
+    qtgui4.dll
+    qtnetwork4.dll
+    qtopengl4.dll
+    qtwebkit4.dll
+    ssleay32.dll
+    )
+  copy_if_different(
+    ${plugins_release_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/Release/llplugin"
+    out_targets
+    ${plugins_release_files}
+    )
+  set(media_plugin_targets ${media_plugin_targets} ${out_targets})
+
+  copy_if_different(
+    ${plugins_release_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/llplugin"
+    out_targets
+    ${plugins_release_files}
+    )
+  set(media_plugin_targets ${media_plugin_targets} ${out_targets})
+  
+  add_custom_target(copy_media_plugin_libs ALL
+    DEPENDS 
+    ${media_plugin_targets}
+    )
+
+  add_custom_command(
+    TARGET ${VIEWER_BINARY_NAME} POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    ARGS
+      -E
+      copy_directory
+      ${CMAKE_BINARY_DIR}/test_apps/llplugintest/${CMAKE_CFG_INTDIR}/imageformats
+      ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin/imageformats
+    COMMENT "Copying llpluging imageformat libs."
+    )
+
+  add_dependencies(${VIEWER_BINARY_NAME} llmediaplugintest copy_media_plugin_libs)
+
 endif (WINDOWS)
 
diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings
index 735424c64787ac02ecb5a4944adee4c8aab6efe2..dceaba9a4343eedec10fe62f2cff7fee2c1e8941 100644
--- a/indra/newview/English.lproj/InfoPlist.strings
+++ b/indra/newview/English.lproj/InfoPlist.strings
@@ -2,6 +2,6 @@
 
 CFBundleName = "Second Life";
 
-CFBundleShortVersionString = "Second Life version 2.0.0.0";
-CFBundleGetInfoString = "Second Life version 2.0.0.0, Copyright 2004-2009 Linden Research, Inc.";
+CFBundleShortVersionString = "Second Life version 2.0.0.3256";
+CFBundleGetInfoString = "Second Life version 2.0.0.3256, Copyright 2004-2009 Linden Research, Inc.";
 
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index 7264044d37c0a3c3bddc7a599cd99d43150fdd06..7aec8a343d60697b9e5d02297c8add0a4d6cd861 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -32,7 +32,7 @@
 		</dict>
 	</array>
 	<key>CFBundleVersion</key>
-	<string>2.0.0.0</string>
+	<string>2.0.0.3256</string>
 	<key>CSResourcesFileMapped</key>
 	<true/>
 </dict>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7e368b0c9c80308dfcfa1d6ea6b0d79c27963b14..fd0e05e7e2b5ede1c853c507706f759876a321bc 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5316,6 +5316,17 @@
       <key>Value</key>
 	  <integer>13</integer>
     </map>
+    <key>PrimMediaMaxRetries</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum number of retries for media queries.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>4</integer>
+    </map>
     <key>PrimMediaRequestQueueDelay</key>
     <map>
       <key>Comment</key>
@@ -5404,6 +5415,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>QAModeEventHostPort</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable Testing Features.</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>-1</integer>
+    </map>
     <key>QuietSnapshotsToDisk</key>
     <map>
       <key>Comment</key>
@@ -10014,7 +10036,7 @@
       <key>Comment</key>
       <string>Versioning Channel Name.</string>
       <key>Persist</key>
-      <integer>1</integer>
+      <integer>0</integer>
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
diff --git a/indra/newview/build_win32_appConfig.py b/indra/newview/build_win32_appConfig.py
index fb6a0258bcaad1ad0a286152cecea00f10ac95be..8eadf0068f559280908e40233d493301a1171846 100644
--- a/indra/newview/build_win32_appConfig.py
+++ b/indra/newview/build_win32_appConfig.py
@@ -31,11 +31,7 @@
 import sys, os, re
 from xml.dom.minidom import parse
 
-def main():
-    src_manifest_name = sys.argv[1]
-    src_config_name = sys.argv[2]
-    dst_config_name = sys.argv[3]
- 
+def munge_binding_redirect_version(src_manifest_name, src_config_name, dst_config_name):
     manifest_dom = parse(src_manifest_name)
     node = manifest_dom.getElementsByTagName('assemblyIdentity')[0]
     manifest_assm_ver = node.getAttribute('version')
@@ -47,11 +43,31 @@ def main():
     node.setAttribute('oldVersion', src_old_ver + manifest_assm_ver)
     comment = config_dom.createComment("This file is automatically generated by the build. see indra/newview/build_win32_appConfig.py")
     config_dom.insertBefore(comment, config_dom.childNodes[0])
-    
+
+    print "Writing: " + dst_config_name
     f = open(dst_config_name, 'w')
     config_dom.writexml(f)
     f.close()
+    
+    
+
+def main():
+    config = sys.argv[1]
+    src_dir = sys.argv[2]
+    dst_dir = sys.argv[3]
+    dst_name = sys.argv[4]
+    
+    if config.lower() == 'debug':
+        src_manifest_name = dst_dir + '/Microsoft.VC80.DebugCRT.manifest'
+        src_config_name = src_dir + '/SecondLifeDebug.exe.config'
+    else:
+        src_manifest_name = dst_dir + '/Microsoft.VC80.CRT.manifest'
+        src_config_name = src_dir + '/SecondLife.exe.config'
+
+    dst_config_name = dst_dir + '/' + dst_name
         
+    munge_binding_redirect_version(src_manifest_name, src_config_name, dst_config_name)
+    
     return 0
 
 if __name__ == "__main__":
diff --git a/indra/newview/character/avatar_eye.llm b/indra/newview/character/avatar_eye.llm
new file mode 100644
index 0000000000000000000000000000000000000000..8c6e74e1deb8379e7f7dbc3e01106dadaf295f44
Binary files /dev/null and b/indra/newview/character/avatar_eye.llm differ
diff --git a/indra/newview/character/avatar_eye_1.llm b/indra/newview/character/avatar_eye_1.llm
new file mode 100644
index 0000000000000000000000000000000000000000..7a3b0d6f289b1d864da66ab276653a5fc4395a15
Binary files /dev/null and b/indra/newview/character/avatar_eye_1.llm differ
diff --git a/indra/newview/character/avatar_eyelashes.llm b/indra/newview/character/avatar_eyelashes.llm
new file mode 100644
index 0000000000000000000000000000000000000000..99995b575825e1eb1c79dab31177b9734a0ad313
Binary files /dev/null and b/indra/newview/character/avatar_eyelashes.llm differ
diff --git a/indra/newview/character/avatar_hair.llm b/indra/newview/character/avatar_hair.llm
new file mode 100644
index 0000000000000000000000000000000000000000..df99de8db7b5515b06dc0ce19a92c3a5f125b1b0
Binary files /dev/null and b/indra/newview/character/avatar_hair.llm differ
diff --git a/indra/newview/character/avatar_hair_1.llm b/indra/newview/character/avatar_hair_1.llm
new file mode 100644
index 0000000000000000000000000000000000000000..6de31fdc23a3c8dc996deceae24e0ad82b0e53ee
Binary files /dev/null and b/indra/newview/character/avatar_hair_1.llm differ
diff --git a/indra/newview/character/avatar_hair_2.llm b/indra/newview/character/avatar_hair_2.llm
new file mode 100644
index 0000000000000000000000000000000000000000..47d02ba9ce03df5269c3119ef38c880599513a2a
Binary files /dev/null and b/indra/newview/character/avatar_hair_2.llm differ
diff --git a/indra/newview/character/avatar_hair_3.llm b/indra/newview/character/avatar_hair_3.llm
new file mode 100644
index 0000000000000000000000000000000000000000..107f9e2a532cc1da9aa6ce39ce8a79b483519969
Binary files /dev/null and b/indra/newview/character/avatar_hair_3.llm differ
diff --git a/indra/newview/character/avatar_hair_4.llm b/indra/newview/character/avatar_hair_4.llm
new file mode 100644
index 0000000000000000000000000000000000000000..1b9a12a0cac620df8bda2fd1188f0d907eb1914b
Binary files /dev/null and b/indra/newview/character/avatar_hair_4.llm differ
diff --git a/indra/newview/character/avatar_hair_5.llm b/indra/newview/character/avatar_hair_5.llm
new file mode 100644
index 0000000000000000000000000000000000000000..1b9a12a0cac620df8bda2fd1188f0d907eb1914b
Binary files /dev/null and b/indra/newview/character/avatar_hair_5.llm differ
diff --git a/indra/newview/character/avatar_head.llm b/indra/newview/character/avatar_head.llm
new file mode 100644
index 0000000000000000000000000000000000000000..8d8b5e0442bb98c795c4b9ab6c64c13ff9eee79d
Binary files /dev/null and b/indra/newview/character/avatar_head.llm differ
diff --git a/indra/newview/character/avatar_head_1.llm b/indra/newview/character/avatar_head_1.llm
new file mode 100644
index 0000000000000000000000000000000000000000..26291e6584b57080c6257de7884a32c55ec5e862
Binary files /dev/null and b/indra/newview/character/avatar_head_1.llm differ
diff --git a/indra/newview/character/avatar_head_2.llm b/indra/newview/character/avatar_head_2.llm
new file mode 100644
index 0000000000000000000000000000000000000000..c2b808b1a61282d52106684cd566dcb86988795a
Binary files /dev/null and b/indra/newview/character/avatar_head_2.llm differ
diff --git a/indra/newview/character/avatar_head_3.llm b/indra/newview/character/avatar_head_3.llm
new file mode 100644
index 0000000000000000000000000000000000000000..a0676b1f1ce64686913cb67701412054349b2089
Binary files /dev/null and b/indra/newview/character/avatar_head_3.llm differ
diff --git a/indra/newview/character/avatar_head_4.llm b/indra/newview/character/avatar_head_4.llm
new file mode 100644
index 0000000000000000000000000000000000000000..5035585770bfff0018608d552ea8f9e660c24fbb
Binary files /dev/null and b/indra/newview/character/avatar_head_4.llm differ
diff --git a/indra/newview/character/avatar_lower_body.llm b/indra/newview/character/avatar_lower_body.llm
new file mode 100644
index 0000000000000000000000000000000000000000..04208997399f46846dd4054c4890127155dbf070
Binary files /dev/null and b/indra/newview/character/avatar_lower_body.llm differ
diff --git a/indra/newview/character/avatar_lower_body_1.llm b/indra/newview/character/avatar_lower_body_1.llm
new file mode 100644
index 0000000000000000000000000000000000000000..1394eb848b3995d333906f293b870bd3b3310cc6
Binary files /dev/null and b/indra/newview/character/avatar_lower_body_1.llm differ
diff --git a/indra/newview/character/avatar_lower_body_2.llm b/indra/newview/character/avatar_lower_body_2.llm
new file mode 100644
index 0000000000000000000000000000000000000000..0da9c1249ea4bd0cd6fcf29d21e1dc151c5ec100
Binary files /dev/null and b/indra/newview/character/avatar_lower_body_2.llm differ
diff --git a/indra/newview/character/avatar_lower_body_3.llm b/indra/newview/character/avatar_lower_body_3.llm
new file mode 100644
index 0000000000000000000000000000000000000000..f3c49a1568d76ff16c454ff0b1fa4fafccd3b74a
Binary files /dev/null and b/indra/newview/character/avatar_lower_body_3.llm differ
diff --git a/indra/newview/character/avatar_lower_body_4.llm b/indra/newview/character/avatar_lower_body_4.llm
new file mode 100644
index 0000000000000000000000000000000000000000..e71721063ec39d799592c493b65706b76e2999c2
Binary files /dev/null and b/indra/newview/character/avatar_lower_body_4.llm differ
diff --git a/indra/newview/character/avatar_skirt.llm b/indra/newview/character/avatar_skirt.llm
new file mode 100644
index 0000000000000000000000000000000000000000..08ce3d170039ff5d2e099346ac95b128aec4866c
Binary files /dev/null and b/indra/newview/character/avatar_skirt.llm differ
diff --git a/indra/newview/character/avatar_skirt_1.llm b/indra/newview/character/avatar_skirt_1.llm
new file mode 100644
index 0000000000000000000000000000000000000000..88076c321f787d62eee2496d12510ed405c2a96d
Binary files /dev/null and b/indra/newview/character/avatar_skirt_1.llm differ
diff --git a/indra/newview/character/avatar_skirt_2.llm b/indra/newview/character/avatar_skirt_2.llm
new file mode 100644
index 0000000000000000000000000000000000000000..73b3effbc600a3e92ec695c3133aa92c2d8c528d
Binary files /dev/null and b/indra/newview/character/avatar_skirt_2.llm differ
diff --git a/indra/newview/character/avatar_skirt_3.llm b/indra/newview/character/avatar_skirt_3.llm
new file mode 100644
index 0000000000000000000000000000000000000000..ded546fdeadeaf9ce914dd05a9004cc88de25098
Binary files /dev/null and b/indra/newview/character/avatar_skirt_3.llm differ
diff --git a/indra/newview/character/avatar_skirt_4.llm b/indra/newview/character/avatar_skirt_4.llm
new file mode 100644
index 0000000000000000000000000000000000000000..b9d5cb945e3fc0b91cbf882a4df824223f7537c9
Binary files /dev/null and b/indra/newview/character/avatar_skirt_4.llm differ
diff --git a/indra/newview/character/avatar_upper_body.llm b/indra/newview/character/avatar_upper_body.llm
new file mode 100644
index 0000000000000000000000000000000000000000..da7d99054093854e6da5e0fd94e69c9d5e3a5800
Binary files /dev/null and b/indra/newview/character/avatar_upper_body.llm differ
diff --git a/indra/newview/character/avatar_upper_body_1.llm b/indra/newview/character/avatar_upper_body_1.llm
new file mode 100644
index 0000000000000000000000000000000000000000..31e104cc20b5c7bd6f7c2aae1880778eade1870e
Binary files /dev/null and b/indra/newview/character/avatar_upper_body_1.llm differ
diff --git a/indra/newview/character/avatar_upper_body_2.llm b/indra/newview/character/avatar_upper_body_2.llm
new file mode 100644
index 0000000000000000000000000000000000000000..c1f4199b9c943a4e3fb01dc4cb28ae8ccd0dcab5
Binary files /dev/null and b/indra/newview/character/avatar_upper_body_2.llm differ
diff --git a/indra/newview/character/avatar_upper_body_3.llm b/indra/newview/character/avatar_upper_body_3.llm
new file mode 100644
index 0000000000000000000000000000000000000000..9e89ed8b3e112cecf66e77de1f9dd14d5cb5267f
Binary files /dev/null and b/indra/newview/character/avatar_upper_body_3.llm differ
diff --git a/indra/newview/character/avatar_upper_body_4.llm b/indra/newview/character/avatar_upper_body_4.llm
new file mode 100644
index 0000000000000000000000000000000000000000..ec836d1dc3aebe9e570d6b33b421e87b4e9fda12
Binary files /dev/null and b/indra/newview/character/avatar_upper_body_4.llm differ
diff --git a/indra/newview/character/blush_alpha.tga b/indra/newview/character/blush_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..05be7e7e3d7f37dc76b90bee270e5597e8b2e322
Binary files /dev/null and b/indra/newview/character/blush_alpha.tga differ
diff --git a/indra/newview/character/body_skingrain.tga b/indra/newview/character/body_skingrain.tga
new file mode 100644
index 0000000000000000000000000000000000000000..7264baac144fd5d9fe8b4bbb47f97b0c4d5ff430
Binary files /dev/null and b/indra/newview/character/body_skingrain.tga differ
diff --git a/indra/newview/character/bodyfreckles_alpha.tga b/indra/newview/character/bodyfreckles_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..d30ab3d122607cf445420eb107c2457ee5ccb783
Binary files /dev/null and b/indra/newview/character/bodyfreckles_alpha.tga differ
diff --git a/indra/newview/character/bump_face_wrinkles.tga b/indra/newview/character/bump_face_wrinkles.tga
new file mode 100644
index 0000000000000000000000000000000000000000..54bf7a55be3fe90f306b454b18a7d7df18acac8c
Binary files /dev/null and b/indra/newview/character/bump_face_wrinkles.tga differ
diff --git a/indra/newview/character/bump_head_base.tga b/indra/newview/character/bump_head_base.tga
new file mode 100644
index 0000000000000000000000000000000000000000..fa3568573a4694b28dfce80e28ab6b4bca3a5d48
Binary files /dev/null and b/indra/newview/character/bump_head_base.tga differ
diff --git a/indra/newview/character/bump_lowerbody_base.tga b/indra/newview/character/bump_lowerbody_base.tga
new file mode 100644
index 0000000000000000000000000000000000000000..498ea3c721dc34f8768f16e8f5f824c8de066089
Binary files /dev/null and b/indra/newview/character/bump_lowerbody_base.tga differ
diff --git a/indra/newview/character/bump_pants_wrinkles.tga b/indra/newview/character/bump_pants_wrinkles.tga
new file mode 100644
index 0000000000000000000000000000000000000000..cca72415e808d0a760ba88041316659697d4df31
Binary files /dev/null and b/indra/newview/character/bump_pants_wrinkles.tga differ
diff --git a/indra/newview/character/bump_shirt_wrinkles.tga b/indra/newview/character/bump_shirt_wrinkles.tga
new file mode 100644
index 0000000000000000000000000000000000000000..9e0d757a48ac8f35985f27d04a66bcc42d585a1d
Binary files /dev/null and b/indra/newview/character/bump_shirt_wrinkles.tga differ
diff --git a/indra/newview/character/bump_upperbody_base.tga b/indra/newview/character/bump_upperbody_base.tga
new file mode 100644
index 0000000000000000000000000000000000000000..e57d6352e6ad449d80690b82c920a9a33c37f32a
Binary files /dev/null and b/indra/newview/character/bump_upperbody_base.tga differ
diff --git a/indra/newview/character/eyebrows_alpha.tga b/indra/newview/character/eyebrows_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..c363e482e13e1c9437fdb7c11444e4b894aa34b4
Binary files /dev/null and b/indra/newview/character/eyebrows_alpha.tga differ
diff --git a/indra/newview/character/eyeliner_alpha.tga b/indra/newview/character/eyeliner_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..1611eb3355c07ce404223a42f081c749dc4ec3ff
Binary files /dev/null and b/indra/newview/character/eyeliner_alpha.tga differ
diff --git a/indra/newview/character/eyeshadow_inner_alpha.tga b/indra/newview/character/eyeshadow_inner_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..37d791939578dbacbe6a8768a46431406c5a0854
Binary files /dev/null and b/indra/newview/character/eyeshadow_inner_alpha.tga differ
diff --git a/indra/newview/character/eyeshadow_outer_alpha.tga b/indra/newview/character/eyeshadow_outer_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..00eef9d9f7cf40ab48ad7e941a99b9f03f0c7eb6
Binary files /dev/null and b/indra/newview/character/eyeshadow_outer_alpha.tga differ
diff --git a/indra/newview/character/eyewhite.tga b/indra/newview/character/eyewhite.tga
new file mode 100644
index 0000000000000000000000000000000000000000..a720496988e33e69e4cedc05744dc0b3fb035b5a
Binary files /dev/null and b/indra/newview/character/eyewhite.tga differ
diff --git a/indra/newview/character/facehair_chincurtains_alpha.tga b/indra/newview/character/facehair_chincurtains_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..b10397063c08f084891baae79a24dfacc06f5964
Binary files /dev/null and b/indra/newview/character/facehair_chincurtains_alpha.tga differ
diff --git a/indra/newview/character/facehair_moustache_alpha.tga b/indra/newview/character/facehair_moustache_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..4068c4f2b139688c99ec444bc9fc58a1b2d3a3ba
Binary files /dev/null and b/indra/newview/character/facehair_moustache_alpha.tga differ
diff --git a/indra/newview/character/facehair_sideburns_alpha.tga b/indra/newview/character/facehair_sideburns_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..acddc2d9bddfcc242fc9bb7671bfa34177179983
Binary files /dev/null and b/indra/newview/character/facehair_sideburns_alpha.tga differ
diff --git a/indra/newview/character/facehair_soulpatch_alpha.tga b/indra/newview/character/facehair_soulpatch_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..687091a29f6a83761d1886828a26be70d52b108a
Binary files /dev/null and b/indra/newview/character/facehair_soulpatch_alpha.tga differ
diff --git a/indra/newview/character/freckles_alpha.tga b/indra/newview/character/freckles_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..a9a4ec073531c19b3588bb7ad9531caf070d2694
Binary files /dev/null and b/indra/newview/character/freckles_alpha.tga differ
diff --git a/indra/newview/character/glove_length_alpha.tga b/indra/newview/character/glove_length_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..db89ad57e7c52a73e8801bd3b0597a596bb59a16
Binary files /dev/null and b/indra/newview/character/glove_length_alpha.tga differ
diff --git a/indra/newview/character/gloves_fingers_alpha.tga b/indra/newview/character/gloves_fingers_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..dba2eec2777c7021b2e897c728ac549a2ca50cad
Binary files /dev/null and b/indra/newview/character/gloves_fingers_alpha.tga differ
diff --git a/indra/newview/character/head_alpha.tga b/indra/newview/character/head_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..8164525353a764ff53aab784a2c6e1d8d0056607
Binary files /dev/null and b/indra/newview/character/head_alpha.tga differ
diff --git a/indra/newview/character/head_color.tga b/indra/newview/character/head_color.tga
new file mode 100644
index 0000000000000000000000000000000000000000..74b1b3078b3b60df9854086b839f8383cf4dea88
Binary files /dev/null and b/indra/newview/character/head_color.tga differ
diff --git a/indra/newview/character/head_hair.tga b/indra/newview/character/head_hair.tga
new file mode 100644
index 0000000000000000000000000000000000000000..5321f35204b09610a332c40486f47f19060561ff
Binary files /dev/null and b/indra/newview/character/head_hair.tga differ
diff --git a/indra/newview/character/head_highlights_alpha.tga b/indra/newview/character/head_highlights_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..8dc5239f977da36f8f36ce3bdb62b23f12aed758
Binary files /dev/null and b/indra/newview/character/head_highlights_alpha.tga differ
diff --git a/indra/newview/character/head_shading_alpha.tga b/indra/newview/character/head_shading_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..e8ea490109d8c5401633ea33ad296aa507d8c9b3
Binary files /dev/null and b/indra/newview/character/head_shading_alpha.tga differ
diff --git a/indra/newview/character/head_skingrain.tga b/indra/newview/character/head_skingrain.tga
new file mode 100644
index 0000000000000000000000000000000000000000..b42dee08090b967ffe4db4fae19533a316cb030e
Binary files /dev/null and b/indra/newview/character/head_skingrain.tga differ
diff --git a/indra/newview/character/jacket_length_lower_alpha.tga b/indra/newview/character/jacket_length_lower_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..722bc192a832dd887ef7c90eee4055a6447cbcac
Binary files /dev/null and b/indra/newview/character/jacket_length_lower_alpha.tga differ
diff --git a/indra/newview/character/jacket_length_upper_alpha.tga b/indra/newview/character/jacket_length_upper_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..e9db7e7b1fa8cc81c046200c2a497cf852d2cd5e
Binary files /dev/null and b/indra/newview/character/jacket_length_upper_alpha.tga differ
diff --git a/indra/newview/character/jacket_open_lower_alpha.tga b/indra/newview/character/jacket_open_lower_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..db0c2fb0e3ebc004b44a42168ecb9d0fd7a10ea7
Binary files /dev/null and b/indra/newview/character/jacket_open_lower_alpha.tga differ
diff --git a/indra/newview/character/jacket_open_upper_alpha.tga b/indra/newview/character/jacket_open_upper_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..71b8a0b805b0fcbb3cd17077a9624aee944d6228
Binary files /dev/null and b/indra/newview/character/jacket_open_upper_alpha.tga differ
diff --git a/indra/newview/character/lipgloss_alpha.tga b/indra/newview/character/lipgloss_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..78ceecaf85a5b157083f05973f65702ef45429bb
Binary files /dev/null and b/indra/newview/character/lipgloss_alpha.tga differ
diff --git a/indra/newview/character/lips_mask.tga b/indra/newview/character/lips_mask.tga
new file mode 100644
index 0000000000000000000000000000000000000000..ae1401c006adda76985ed7eeaa5336c471c40f87
Binary files /dev/null and b/indra/newview/character/lips_mask.tga differ
diff --git a/indra/newview/character/lipstick_alpha.tga b/indra/newview/character/lipstick_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..2795f1bd40f076eded229e25ecfdeba83a662a3d
Binary files /dev/null and b/indra/newview/character/lipstick_alpha.tga differ
diff --git a/indra/newview/character/lowerbody_color.tga b/indra/newview/character/lowerbody_color.tga
new file mode 100644
index 0000000000000000000000000000000000000000..a63aa12fca04bb16b23f6f8bdc168371b6a7960b
Binary files /dev/null and b/indra/newview/character/lowerbody_color.tga differ
diff --git a/indra/newview/character/lowerbody_highlights_alpha.tga b/indra/newview/character/lowerbody_highlights_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..ae3413ac8bd98507416f565ebf9d9119342f62a2
Binary files /dev/null and b/indra/newview/character/lowerbody_highlights_alpha.tga differ
diff --git a/indra/newview/character/lowerbody_shading_alpha.tga b/indra/newview/character/lowerbody_shading_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..0242663a7db248b6e6af96fcc9168ee917067476
Binary files /dev/null and b/indra/newview/character/lowerbody_shading_alpha.tga differ
diff --git a/indra/newview/character/nailpolish_alpha.tga b/indra/newview/character/nailpolish_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..91af762902820acca0e0630438f7b19aef5136ed
Binary files /dev/null and b/indra/newview/character/nailpolish_alpha.tga differ
diff --git a/indra/newview/character/pants_length_alpha.tga b/indra/newview/character/pants_length_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..3c4f21c0f2ab5743e804179d792db45e69885b2e
Binary files /dev/null and b/indra/newview/character/pants_length_alpha.tga differ
diff --git a/indra/newview/character/pants_waist_alpha.tga b/indra/newview/character/pants_waist_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..35658c08968a9202710a82ba7d11b4f6c792f8cc
Binary files /dev/null and b/indra/newview/character/pants_waist_alpha.tga differ
diff --git a/indra/newview/character/rosyface_alpha.tga b/indra/newview/character/rosyface_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..a0c8513da2f860da84825a17b980bdc2f963fc82
Binary files /dev/null and b/indra/newview/character/rosyface_alpha.tga differ
diff --git a/indra/newview/character/rouge_alpha.tga b/indra/newview/character/rouge_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..a0c8513da2f860da84825a17b980bdc2f963fc82
Binary files /dev/null and b/indra/newview/character/rouge_alpha.tga differ
diff --git a/indra/newview/character/shirt_bottom_alpha.tga b/indra/newview/character/shirt_bottom_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..7cce03dbe040bc7cbe25a2b4f4be579327d12961
Binary files /dev/null and b/indra/newview/character/shirt_bottom_alpha.tga differ
diff --git a/indra/newview/character/shirt_collar_alpha.tga b/indra/newview/character/shirt_collar_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..f55f635473413cacd722c5e2b04c81e78f9a2c72
Binary files /dev/null and b/indra/newview/character/shirt_collar_alpha.tga differ
diff --git a/indra/newview/character/shirt_collar_back_alpha.tga b/indra/newview/character/shirt_collar_back_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..43a645310739931da7f9216cdde577c78a04445b
Binary files /dev/null and b/indra/newview/character/shirt_collar_back_alpha.tga differ
diff --git a/indra/newview/character/shirt_sleeve_alpha.tga b/indra/newview/character/shirt_sleeve_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..e3b18f4fc69578f65c7dda9b675cc101fa389a60
Binary files /dev/null and b/indra/newview/character/shirt_sleeve_alpha.tga differ
diff --git a/indra/newview/character/shoe_height_alpha.tga b/indra/newview/character/shoe_height_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..d08dd750f308982b4200b04f1722814474412843
Binary files /dev/null and b/indra/newview/character/shoe_height_alpha.tga differ
diff --git a/indra/newview/character/skirt_length_alpha.tga b/indra/newview/character/skirt_length_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..c86799469d5fdadc6e0e614ab45060685b0e1695
Binary files /dev/null and b/indra/newview/character/skirt_length_alpha.tga differ
diff --git a/indra/newview/character/skirt_slit_back_alpha.tga b/indra/newview/character/skirt_slit_back_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..0e49688b146a55e7d776a80ddb65ff81bffa3202
Binary files /dev/null and b/indra/newview/character/skirt_slit_back_alpha.tga differ
diff --git a/indra/newview/character/skirt_slit_front_alpha.tga b/indra/newview/character/skirt_slit_front_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..888bbf71a1193cbc9ff4a564e6c0837f6affab5a
Binary files /dev/null and b/indra/newview/character/skirt_slit_front_alpha.tga differ
diff --git a/indra/newview/character/skirt_slit_left_alpha.tga b/indra/newview/character/skirt_slit_left_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..210feac1ea0e4014ddd8187e1460ef1781a5c8e0
Binary files /dev/null and b/indra/newview/character/skirt_slit_left_alpha.tga differ
diff --git a/indra/newview/character/skirt_slit_right_alpha.tga b/indra/newview/character/skirt_slit_right_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..ce11c64bf6763e517b16f4c0d70f02065132e4c2
Binary files /dev/null and b/indra/newview/character/skirt_slit_right_alpha.tga differ
diff --git a/indra/newview/character/underpants_trial_female.tga b/indra/newview/character/underpants_trial_female.tga
new file mode 100644
index 0000000000000000000000000000000000000000..96bf732351786a699ae30e74ef2fed61b14b87b6
Binary files /dev/null and b/indra/newview/character/underpants_trial_female.tga differ
diff --git a/indra/newview/character/underpants_trial_male.tga b/indra/newview/character/underpants_trial_male.tga
new file mode 100644
index 0000000000000000000000000000000000000000..095695ca1c47993db36460a35071b9f0a5c16fc9
Binary files /dev/null and b/indra/newview/character/underpants_trial_male.tga differ
diff --git a/indra/newview/character/undershirt_trial_female.tga b/indra/newview/character/undershirt_trial_female.tga
new file mode 100644
index 0000000000000000000000000000000000000000..e17a30953154e0b135fda708c90eeddbd4189034
Binary files /dev/null and b/indra/newview/character/undershirt_trial_female.tga differ
diff --git a/indra/newview/character/upperbody_color.tga b/indra/newview/character/upperbody_color.tga
new file mode 100644
index 0000000000000000000000000000000000000000..85fcc41142102114244c28c9743d97b119e2f3e1
Binary files /dev/null and b/indra/newview/character/upperbody_color.tga differ
diff --git a/indra/newview/character/upperbody_highlights_alpha.tga b/indra/newview/character/upperbody_highlights_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..2d8102b583d3a8346afb6cb671b9b7f9f3d3780d
Binary files /dev/null and b/indra/newview/character/upperbody_highlights_alpha.tga differ
diff --git a/indra/newview/character/upperbody_shading_alpha.tga b/indra/newview/character/upperbody_shading_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..b420506b3e1407d0eb0b8bd07f63621dba6be557
Binary files /dev/null and b/indra/newview/character/upperbody_shading_alpha.tga differ
diff --git a/indra/newview/character/upperbodyfreckles_alpha.tga b/indra/newview/character/upperbodyfreckles_alpha.tga
new file mode 100644
index 0000000000000000000000000000000000000000..76c7ce8849f59a2355b55d7454af4c6703772050
Binary files /dev/null and b/indra/newview/character/upperbodyfreckles_alpha.tga differ
diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt
index d488c7487e16f48e2a507c2013600079ec52f994..1324fa1a864edcc275b9e10e0d4c9241f1993685 100644
--- a/indra/newview/licenses-mac.txt
+++ b/indra/newview/licenses-mac.txt
@@ -315,6 +315,515 @@ This product includes cryptographic software written by Eric Young
 Hudson (tjh@cryptsoft.com).
 
 
+===========
+Pth License
+===========
+   ____  _   _
+  |  _ \| |_| |__               ``Ian Fleming was a UNIX fan!
+  | |_) | __| '_ \                How do I know? Well, James Bond
+  |  __/| |_| | | |               had the (license to kill) number 007,
+  |_|    \__|_| |_|               i.e., he could execute anyone!''
+
+  GNU Pth - The GNU Portable Threads
+
+  LICENSE
+  =======
+
+  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; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  For some people, it is not clear, what is the real intention of the
+  author by using the GNU Lesser General Public License (LGPL) as the
+  distribution license for GNU Pth. This is, because the LGPL and the
+  GPL can be (and are often) interpreted very differently and some
+  interpretations seem to be not compatible with others. So an explicit
+  clarification for the use of the LGPL for GNU Pth from the authors
+  point of view might be useful.
+
+  The author places this library under the LGPL to make sure that it
+  can be used both commercially and non-commercially provided that
+  modifications to the code base are always donated back to the official
+  code base under the same license conditions. Please keep in mind that
+  especially using this library in code not staying under the GPL or
+  the LGPL _is_ allowed and that any taint or license creap into code
+  that uses the library is not the authors intention. It is just the
+  case that _including_ this library into the source tree of other
+  applications is a little bit more inconvinient because of the LGPL.
+  But it has to be this way for good reasons. And keep in mind that
+  inconvinient doesn't mean not allowed or even impossible.
+
+  Even if you want to use this library in some BSD-style licensed
+  packages, this _is_ possible as long as you are a little bit
+  carefully. Usually this means you have to make sure that the code is
+  still clearly separated into the source tree and that modifications to
+  this source area are done under the conditions of the LGPL. Read below
+  for more details on the conditions. Contact the author if you have
+  more questions.
+
+  The license text of the GNU Lesser General Public License follows:
+  __________________________________________________________________________
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
 
 =======================
 Original SSLeay License
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 0fa3b1f04df573a0dc1997ba326f5b35ea923ea4..f62606cc50fede79c1ba99ccafb4ac64882aa1b8 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -35,6 +35,7 @@
 #include "llagent.h" 
 #include "llagentwearables.h"
 
+#include "llagentlistener.h"
 #include "llanimationstates.h"
 #include "llcallingcard.h"
 #include "llconsole.h"
@@ -255,6 +256,7 @@ LLAgent::LLAgent() :
 	mHUDTargetZoom(1.f),
 	mHUDCurZoom(1.f),
 	mInitialized(FALSE),
+	mListener(),
 	mForceMouselook(FALSE),
 
 	mDoubleTapRunTimer(),
@@ -383,6 +385,8 @@ LLAgent::LLAgent() :
 	}
 
 	mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
+
+	mListener.reset(new LLAgentListener(*this));
 }
 
 // Requires gSavedSettings to be initialized.
@@ -5971,7 +5975,7 @@ bool LLAgent::teleportCore(bool is_local)
 	LLFloaterReg::hideInstance("about_land");
 
 	LLViewerParcelMgr::getInstance()->deselectLand();
-	LLViewerMediaFocus::getInstance()->setFocusFace(false, NULL, 0, NULL);
+	LLViewerMediaFocus::getInstance()->clearFocus();
 
 	// Close all pie menus, deselect land, etc.
 	// Don't change the camera until we know teleport succeeded. JC
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index b334874e6ebcca520f3a3c93800e51bdb120a875..99a9bdd8e636ec13c49e7b09999dd4e7f93b3387 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -105,6 +105,8 @@ struct LLGroupData
 	std::string mName;
 };
 
+class LLAgentListener;
+
 //------------------------------------------------------------------------
 // LLAgent
 //------------------------------------------------------------------------
@@ -142,6 +144,8 @@ class LLAgent : public LLOldEvents::LLObservable
 	BOOL			mInitialized;
 	BOOL			mFirstLogin;
 	std::string		mMOTD; 					// Message of the day
+private:
+	boost::shared_ptr<LLAgentListener> mListener;
 
 	//--------------------------------------------------------------------
 	// Session
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f00078b33ca0eef6e58e501774e1030fbfd6d13
--- /dev/null
+++ b/indra/newview/llagentlistener.cpp
@@ -0,0 +1,78 @@
+/**
+ * @file   llagentlistener.cpp
+ * @author Brad Kittenbrink
+ * @date   2009-07-10
+ * @brief  Implementation for llagentlistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llagentlistener.h"
+
+#include "llagent.h"
+#include "llcommandhandler.h"
+#include "llslurl.h"
+#include "llurldispatcher.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+
+LLAgentListener::LLAgentListener(LLAgent &agent)
+  : LLDispatchListener("LLAgent", "op"),
+    mAgent(agent)
+{
+	add("requestTeleport", &LLAgentListener::requestTeleport);
+	add("requestSit", &LLAgentListener::requestSit);
+	add("requestStand", &LLAgentListener::requestStand);
+}
+
+void LLAgentListener::requestTeleport(LLSD const & event_data) const
+{
+	if(event_data["skip_confirmation"].asBoolean())
+	{
+		LLSD params(LLSD::emptyArray());
+		params.append(event_data["regionname"]);
+		params.append(event_data["x"]);
+		params.append(event_data["y"]);
+		params.append(event_data["z"]);
+		LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, true);
+		// *TODO - lookup other LLCommandHandlers for "agent", "classified", "event", "group", "floater", "objectim", "parcel", "login", login_refresh", "balance", "chat"
+		// should we just compose LLCommandHandler and LLDispatchListener?
+	}
+	else
+	{
+		std::string url = LLSLURL::buildSLURL(event_data["regionname"], event_data["x"], event_data["y"], event_data["z"]);
+		LLURLDispatcher::dispatch(url, NULL, false);
+	}
+}
+
+void LLAgentListener::requestSit(LLSD const & event_data) const
+{
+	//mAgent.getAvatarObject()->sitOnObject();
+	// shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand()
+	// *TODO - find a permanent place to share this code properly.
+	LLViewerObject *object = gObjectList.findObject(event_data["obj_uuid"]);
+
+	if (object && object->getPCode() == LL_PCODE_VOLUME)
+	{
+		gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
+		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+		gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID());
+		gMessageSystem->addUUIDFast(_PREHASH_SessionID, mAgent.getSessionID());
+		gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
+		gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
+		gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3(0,0,0));
+
+		object->getRegion()->sendReliableMessage();
+	}
+}
+
+void LLAgentListener::requestStand(LLSD const & event_data) const
+{
+	mAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+}
+
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f0b5a54c5f0efd54b8bd116437b00779ae63879
--- /dev/null
+++ b/indra/newview/llagentlistener.h
@@ -0,0 +1,36 @@
+/**
+ * @file   llagentlistener.h
+ * @author Brad Kittenbrink
+ * @date   2009-07-09
+ * @brief  Event API for subset of LLViewerControl methods
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLAGENTLISTENER_H
+#define LL_LLAGENTLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLAgent;
+class LLSD;
+
+class LLAgentListener : public LLDispatchListener
+{
+public:
+	LLAgentListener(LLAgent &agent);
+
+private:
+	void requestTeleport(LLSD const & event_data) const;
+	void requestSit(LLSD const & event_data) const;
+	void requestStand(LLSD const & event_data) const;
+
+private:
+	LLAgent & mAgent;
+};
+
+#endif // LL_LLAGENTLISTENER_H
+
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index c673db2034f4c67b151d072a8dc60e01d0f9517d..923a66ee8e344f7ca26d6460670430be56d0782e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -73,6 +73,7 @@
 #include "llurlhistory.h"
 #include "llfirstuse.h"
 #include "llrender.h"
+#include "llteleporthistory.h"
 #include "lllocationhistory.h"
 #include "llfasttimerview.h"
 
@@ -91,14 +92,15 @@
 
 #if LL_WINDOWS
 	#include "llwindebug.h"
-#endif
-
-#if LL_WINDOWS
 #	include <share.h> // For _SH_DENYWR in initMarkerFile
 #else
 #   include <sys/file.h> // For initMarkerFile support
 #endif
 
+#include "llapr.h"
+#include "apr_dso.h"
+#include <boost/lexical_cast.hpp>
+
 #include "llnotify.h"
 #include "llviewerkeyboard.h"
 #include "lllfsthread.h"
@@ -154,7 +156,6 @@
 #include "llfolderview.h"
 #include "lltoolbar.h"
 #include "llagentpilot.h"
-#include "llsrv.h"
 #include "llvovolume.h"
 #include "llflexibleobject.h" 
 #include "llvosurfacepatch.h"
@@ -192,7 +193,19 @@
 //----------------------------------------------------------------------------
 // llviewernetwork.h
 #include "llviewernetwork.h"
+// define a self-registering event API object
+#include "llappviewerlistener.h"
+
+#if (LL_LINUX || LL_SOLARIS) && LL_GTK
+#include "glib.h"
+#endif // (LL_LINUX || LL_SOLARIS) && LL_GTK
 
+#if LL_MSVC
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
+static LLAppViewerListener sAppViewerListener("LLAppViewer", LLAppViewer::instance);
 
 ////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
 //
@@ -218,9 +231,6 @@ BOOL gAllowTapTapHoldRun = TRUE;
 BOOL gShowObjectUpdates = FALSE;
 BOOL gUseQuickTime = TRUE;
 
-BOOL gAcceptTOS = FALSE;
-BOOL gAcceptCriticalMessage = FALSE;
-
 eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
 
 LLSD gDebugInfo;
@@ -565,9 +575,9 @@ LLAppViewer::LLAppViewer() :
 	mYieldTime(-1),
 	mMainloopTimeout(NULL),
 	mAgentRegionLastAlive(false),
-	mFastTimerLogThread(NULL),
 	mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)),
-	mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE))
+	mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
+	mFastTimerLogThread(NULL)
 {
 	if(NULL != sInstance)
 	{
@@ -877,6 +887,11 @@ bool LLAppViewer::init()
 
 	LLViewerJoystick::getInstance()->init(false);
 	gGLActive = FALSE;
+	if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
+	{
+		loadEventHostModule(gSavedSettings.getS32("QAModeEventHostPort"));
+	}
+	
 	return true;
 }
 
@@ -1191,6 +1206,21 @@ bool LLAppViewer::mainLoop()
 
 bool LLAppViewer::cleanup()
 {
+	// workaround for DEV-35406 crash on shutdown
+	LLEventPumps::instance().reset();
+
+	// *TODO - generalize this and move DSO wrangling to a helper class -brad
+	std::set<struct apr_dso_handle_t *>::const_iterator i;
+	for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
+	{
+		int (*ll_plugin_stop_func)(void) = NULL;
+		apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop");
+		ll_plugin_stop_func();
+
+		rv = apr_dso_unload(*i);
+	}
+	mPlugins.clear();
+
 	//----------------------------------------------
 	//this test code will be removed after the test
 	//test manual call stack tracer
@@ -1498,7 +1528,6 @@ bool LLAppViewer::cleanup()
 	//Note:
 	//LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown()
 	//because some new image might be generated during cleaning up media. --bao
-	LLViewerMediaFocus::cleanupClass();
 	LLViewerMedia::cleanupClass();
 	LLViewerParcelMedia::cleanupClass();
 	gTextureList.shutdown(); // shutdown again in case a callback added something
@@ -3694,6 +3723,17 @@ void LLAppViewer::idleShutdown()
 	{
 		return;
 	}
+	
+	// ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup()
+	// *TODO: ugly
+	static bool saved_teleport_history = false;
+	if (!saved_teleport_history)
+	{
+		saved_teleport_history = true;
+		LLTeleportHistory::getInstance()->dump();
+		LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this
+		return;
+	}
 
 	static bool saved_snapshot = false;
 	if (!saved_snapshot)
@@ -3988,7 +4028,7 @@ void LLAppViewer::forceErrorBadMemoryAccess()
     return;
 }
 
-void LLAppViewer::forceErrorInifiniteLoop()
+void LLAppViewer::forceErrorInfiniteLoop()
 {
     while(true)
     {
@@ -4109,3 +4149,198 @@ void LLAppViewer::handleLoginComplete()
 
 	writeDebugInfo();
 }
+
+// *TODO - generalize this and move DSO wrangling to a helper class -brad
+void LLAppViewer::loadEventHostModule(S32 listen_port)
+{
+	std::string dso_name =
+#if LL_WINDOWS
+	    "lleventhost.dll";
+#elif LL_DARWIN
+	    "liblleventhost.dylib";
+#else
+	    "liblleventhost.so";
+#endif
+
+	std::string dso_path = gDirUtilp->findFile(dso_name,
+		gDirUtilp->getAppRODataDir(),
+		gDirUtilp->getExecutableDir());
+
+	if(dso_path == "")
+	{
+		llwarns << "QAModeEventHost requested but module \"" << dso_name << "\" not found!" << llendl;
+		return;
+	}
+
+	apr_dso_handle_t * eventhost_dso_handle = NULL;
+	apr_pool_t * eventhost_dso_memory_pool = NULL;
+
+	//attempt to load the shared library
+	apr_pool_create(&eventhost_dso_memory_pool, NULL);
+	apr_status_t rv = apr_dso_load(&eventhost_dso_handle,
+		dso_path.c_str(),
+		eventhost_dso_memory_pool);
+	ll_apr_assert_status(rv);
+	llassert_always(eventhost_dso_handle != NULL);
+
+	int (*ll_plugin_start_func)(LLSD const &) = NULL;
+	rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start");
+
+	ll_apr_assert_status(rv);
+	llassert_always(ll_plugin_start_func != NULL);
+
+	LLSD args;
+	args["listen_port"] = listen_port;
+
+	int status = ll_plugin_start_func(args);
+
+	if(status != 0)
+	{
+		llwarns << "problem loading eventhost plugin, status: " << status << llendl;
+	}
+
+	mPlugins.insert(eventhost_dso_handle);
+}
+
+void LLAppViewer::launchUpdater()
+{
+		LLSD query_map = LLSD::emptyMap();
+	// *TODO place os string in a global constant
+#if LL_WINDOWS  
+	query_map["os"] = "win";
+#elif LL_DARWIN
+	query_map["os"] = "mac";
+#elif LL_LINUX
+	query_map["os"] = "lnx";
+#elif LL_SOLARIS
+	query_map["os"] = "sol";
+#endif
+	// *TODO change userserver to be grid on both viewer and sim, since
+	// userserver no longer exists.
+	query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel();
+	query_map["channel"] = gSavedSettings.getString("VersionChannelName");
+	// *TODO constantize this guy
+	// *NOTE: This URL is also used in win_setup/lldownloader.cpp
+	LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
+	
+	if(LLAppViewer::sUpdaterInfo)
+	{
+		delete LLAppViewer::sUpdaterInfo;
+	}
+	LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
+
+	// if a sim name was passed in via command line parameter (typically through a SLURL)
+	if ( LLURLSimString::sInstance.mSimString.length() )
+	{
+		// record the location to start at next time
+		gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); 
+	};
+
+#if LL_WINDOWS
+	LLAppViewer::sUpdaterInfo->mUpdateExePath = gDirUtilp->getTempFilename();
+	if (LLAppViewer::sUpdaterInfo->mUpdateExePath.empty())
+	{
+		delete LLAppViewer::sUpdaterInfo ;
+		LLAppViewer::sUpdaterInfo = NULL ;
+
+		// We're hosed, bail
+		LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL;
+		return;
+	}
+
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe";
+
+	std::string updater_source = gDirUtilp->getAppRODataDir();
+	updater_source += gDirUtilp->getDirDelimiter();
+	updater_source += "updater.exe";
+
+	LL_DEBUGS("AppInit") << "Calling CopyFile source: " << updater_source
+			<< " dest: " << LLAppViewer::sUpdaterInfo->mUpdateExePath
+			<< LL_ENDL;
+
+
+	if (!CopyFileA(updater_source.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), FALSE))
+	{
+		delete LLAppViewer::sUpdaterInfo ;
+		LLAppViewer::sUpdaterInfo = NULL ;
+
+		LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL;
+
+		return;
+	}
+
+	LLAppViewer::sUpdaterInfo->mParams << "-url \"" << update_url.asString() << "\"";
+
+	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL;
+
+	//Explicitly remove the marker file, otherwise we pass the lock onto the child process and things get weird.
+	LLAppViewer::instance()->removeMarkerFile(); // In case updater fails
+
+	// *NOTE:Mani The updater is spawned as the last thing before the WinMain exit.
+	// see LLAppViewerWin32.cpp
+	
+#elif LL_DARWIN
+	LLAppViewer::sUpdaterInfo->mUpdateExePath = "'";
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir();
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url \"";
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
+	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
+
+	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
+
+	// Run the auto-updater.
+	system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */
+
+#elif (LL_LINUX || LL_SOLARIS) && LL_GTK
+	// we tell the updater where to find the xml containing string
+	// translations which it can use for its own UI
+	std::string xml_strings_file = "strings.xml";
+	std::vector<std::string> xui_path_vec = LLUI::getXUIPaths();
+	std::string xml_search_paths;
+	std::vector<std::string>::const_iterator iter;
+	// build comma-delimited list of xml paths to pass to updater
+	for (iter = xui_path_vec.begin(); iter != xui_path_vec.end(); )
+	{
+		std::string this_skin_dir = gDirUtilp->getDefaultSkinDir()
+			+ gDirUtilp->getDirDelimiter()
+			+ (*iter);
+		llinfos << "Got a XUI path: " << this_skin_dir << llendl;
+		xml_search_paths.append(this_skin_dir);
+		++iter;
+		if (iter != xui_path_vec.end())
+			xml_search_paths.append(","); // comma-delimit
+	}
+	// build the overall command-line to run the updater correctly
+	LLAppViewer::sUpdaterInfo->mUpdateExePath = 
+		gDirUtilp->getExecutableDir() + "/" + "linux-updater.bin" + 
+		" --url \"" + update_url.asString() + "\"" +
+		" --name \"" + LLAppViewer::instance()->getSecondLifeTitle() + "\"" +
+		" --dest \"" + gDirUtilp->getAppRODataDir() + "\"" +
+		" --stringsdir \"" + xml_search_paths + "\"" +
+		" --stringsfile \"" + xml_strings_file + "\"";
+
+	LL_INFOS("AppInit") << "Calling updater: " 
+			    << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
+
+	// *TODO: we could use the gdk equivalent to ensure the updater
+	// gets started on the same screen.
+	GError *error = NULL;
+	if (!g_spawn_command_line_async(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), &error))
+	{
+		llerrs << "Failed to launch updater: "
+		       << error->message
+		       << llendl;
+	}
+	if (error) {
+		g_error_free(error);
+	}
+#else
+	OSMessageBox(LLTrans::getString("MBNoAutoUpdate"), LLStringUtil::null, OSMB_OK);
+#endif
+
+	// *REMOVE:Mani - Saving for reference...
+	// LLAppViewer::instance()->forceQuit();
+}
+
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 646b67726497c98d5f3e28a618fb12228436f51e..f95d7cb412c4b687e6ab36d37e6e4bbb5ba9ef11 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -47,6 +47,8 @@ class LLVFS;
 class LLWatchdogTimeout;
 class LLWorkerThread;
 
+struct apr_dso_handle_t;
+
 
 class LLAppViewer : public LLApp
 {
@@ -124,7 +126,7 @@ class LLAppViewer : public LLApp
     virtual void forceErrorLLError();
     virtual void forceErrorBreakpoint();
     virtual void forceErrorBadMemoryAccess();
-    virtual void forceErrorInifiniteLoop();
+    virtual void forceErrorInfiniteLoop();
     virtual void forceErrorSoftwareException();
     virtual void forceErrorDriverCrash();
 
@@ -210,6 +212,8 @@ class LLAppViewer : public LLApp
     void sendLogoutRequest();
     void disconnectViewer();
 
+	void loadEventHostModule(S32 listen_port);
+	
 	// *FIX: the app viewer class should be some sort of singleton, no?
 	// Perhaps its child class is the singleton and this should be an abstract base.
 	static LLAppViewer* sInstance; 
@@ -255,6 +259,8 @@ class LLAppViewer : public LLApp
 
     LLAllocator mAlloc;
 
+	std::set<struct apr_dso_handle_t*> mPlugins;
+
 public:
 	//some information for updater
 	typedef struct
@@ -263,6 +269,8 @@ class LLAppViewer : public LLApp
 		std::ostringstream mParams;
 	}LLUpdaterInfo ;
 	static LLUpdaterInfo *sUpdaterInfo ;
+
+	void launchUpdater();
 };
 
 // consts from viewer.h
@@ -278,10 +286,6 @@ extern LLSD gDebugInfo;
 extern BOOL	gAllowTapTapHoldRun;
 extern BOOL	gShowObjectUpdates;
 
-extern BOOL gAcceptTOS;
-extern BOOL gAcceptCriticalMessage;
-
-
 typedef enum 
 {
 	LAST_EXEC_NORMAL = 0,
diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3259309eee76872a69e8aa2b8cd16563c77dd10a
--- /dev/null
+++ b/indra/newview/llappviewerlistener.cpp
@@ -0,0 +1,40 @@
+/**
+ * @file   llappviewerlistener.cpp
+ * @author Nat Goodspeed
+ * @date   2009-06-23
+ * @brief  Implementation for llappviewerlistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "llviewerprecompiledheaders.h"
+// associated header
+#include "llappviewerlistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llappviewer.h"
+
+LLAppViewerListener::LLAppViewerListener(const std::string& pumpname,
+                                         const LLAppViewerGetter& getter):
+    LLDispatchListener(pumpname, "op"),
+    mAppViewerGetter(getter)
+{
+    // add() every method we want to be able to invoke via this event API.
+    add("requestQuit", &LLAppViewerListener::requestQuit);
+    add("forceQuit", &LLAppViewerListener::forceQuit);
+}
+
+void LLAppViewerListener::requestQuit(const LLSD& event)
+{
+    mAppViewerGetter()->requestQuit();
+}
+
+void LLAppViewerListener::forceQuit(const LLSD& event)
+{
+    mAppViewerGetter()->forceQuit();
+}
diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..73227cb95a771e2a74092f3cf74197ae230a2c52
--- /dev/null
+++ b/indra/newview/llappviewerlistener.h
@@ -0,0 +1,37 @@
+/**
+ * @file   llappviewerlistener.h
+ * @author Nat Goodspeed
+ * @date   2009-06-18
+ * @brief  Wrap subset of LLAppViewer API in event API
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLAPPVIEWERLISTENER_H)
+#define LL_LLAPPVIEWERLISTENER_H
+
+#include "lleventdispatcher.h"
+#include <boost/function.hpp>
+
+class LLAppViewer;
+class LLSD;
+
+/// Listen on an LLEventPump with specified name for LLAppViewer request events.
+class LLAppViewerListener: public LLDispatchListener
+{
+public:
+    typedef boost::function<LLAppViewer*(void)> LLAppViewerGetter;
+    /// Specify the pump name on which to listen, and bind the LLAppViewer
+    /// instance to use (e.g. LLAppViewer::instance()).
+    LLAppViewerListener(const std::string& pumpname, const LLAppViewerGetter& getter);
+
+private:
+    void requestQuit(const LLSD& event);
+    void forceQuit(const LLSD& event);
+
+    LLAppViewerGetter mAppViewerGetter;
+};
+
+#endif /* ! defined(LL_LLAPPVIEWERLISTENER_H) */
diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp
index 4a3e9aec9c14763ccd7c2ab6acb4535b8dafdf48..ed9613c1bccf2c69039490edfb700abf93874888 100644
--- a/indra/newview/llcapabilitylistener.cpp
+++ b/indra/newview/llcapabilitylistener.cpp
@@ -114,6 +114,7 @@ bool LLCapabilityListener::capListener(const LLSD& request)
         // This capability is supported by the region to which we're talking.
         LLHTTPClient::post(url, payload,
                            new LLSDMessage::EventResponder(LLEventPumps::instance(),
+                                                           request,
                                                            mProvider.getDescription(),
                                                            cap, reply, error),
                            LLSD(),  // headers
diff --git a/indra/newview/llclassifiedinfo.cpp b/indra/newview/llclassifiedinfo.cpp
index 5cf1579d0e0cc71616d80cadd6e93eb9545d1448..5fcafbeca6097461b41dbbcba25614fd140c1e22 100644
--- a/indra/newview/llclassifiedinfo.cpp
+++ b/indra/newview/llclassifiedinfo.cpp
@@ -38,35 +38,19 @@
 LLClassifiedInfo::cat_map LLClassifiedInfo::sCategories;
 
 // static
-void LLClassifiedInfo::loadCategories(LLUserAuth::options_t classified_options)
+void LLClassifiedInfo::loadCategories(const LLSD& options)
 {
-	LLUserAuth::options_t::iterator resp_it;
-	for (resp_it = classified_options.begin(); 
-		 resp_it != classified_options.end(); 
-		 ++resp_it)
+	for(LLSD::array_const_iterator resp_it = options.beginArray(),
+		end = options.endArray(); resp_it != end; ++resp_it)
 	{
-		const LLUserAuth::response_t& response = *resp_it;
-
-		LLUserAuth::response_t::const_iterator option_it;
-
-		S32 cat_id = 0;
-		option_it = response.find("category_id");
-		if (option_it != response.end())
+		LLSD name = (*resp_it)["category_name"];
+		if(name.isDefined())
 		{
-			cat_id = atoi(option_it->second.c_str());
+			LLSD id = (*resp_it)["category_id"];
+			if(id.isDefined())
+			{
+				LLClassifiedInfo::sCategories[id.asInteger()] = name.asString();
+			}
 		}
-		else
-		{
-			continue;
-		}
-
-		// Add the category id/name pair
-		option_it = response.find("category_name");
-		if (option_it != response.end())
-		{
-			LLClassifiedInfo::sCategories[cat_id] = option_it->second;
-		}
-
 	}
-
 }
diff --git a/indra/newview/llclassifiedinfo.h b/indra/newview/llclassifiedinfo.h
index cc5a6bf28fe341d4630c1afbaff91f3150060cca..37134c7e5bbd7cb7223f0d57c1c8b7f72bf05b9c 100644
--- a/indra/newview/llclassifiedinfo.h
+++ b/indra/newview/llclassifiedinfo.h
@@ -37,7 +37,6 @@
 
 #include "v3dmath.h"
 #include "lluuid.h"
-#include "lluserauth.h"
 
 class LLMessageSystem;
 
@@ -46,7 +45,7 @@ class LLClassifiedInfo
 public:
 	LLClassifiedInfo() {}
 
-	static void loadCategories(LLUserAuth::options_t event_options);
+	static void loadCategories(const LLSD& options);
 
 	typedef std::map<U32, std::string> cat_map;
 	static	cat_map sCategories;
diff --git a/indra/newview/lleventinfo.cpp b/indra/newview/lleventinfo.cpp
index d4175b6c846a9f3ee9919c32e1868bafa8d6e565..9be45d18fb0e833997386e87814340a4212384ae 100644
--- a/indra/newview/lleventinfo.cpp
+++ b/indra/newview/lleventinfo.cpp
@@ -87,35 +87,19 @@ void LLEventInfo::unpack(LLMessageSystem *msg)
 }
 
 // static
-void LLEventInfo::loadCategories(LLUserAuth::options_t event_options)
+void LLEventInfo::loadCategories(const LLSD& options)
 {
-	LLUserAuth::options_t::iterator resp_it;
-	for (resp_it = event_options.begin(); 
-		 resp_it != event_options.end(); 
-		 ++resp_it)
+	for(LLSD::array_const_iterator resp_it = options.beginArray(),
+		end = options.endArray(); resp_it != end; ++resp_it)
 	{
-		const LLUserAuth::response_t& response = *resp_it;
-
-		LLUserAuth::response_t::const_iterator option_it;
-
-		S32 cat_id = 0;
-		option_it = response.find("category_id");
-		if (option_it != response.end())
+		LLSD name = (*resp_it)["category_name"];
+		if(name.isDefined())
 		{
-			cat_id = atoi(option_it->second.c_str());
+			LLSD id = (*resp_it)["category_id"];
+			if(id.isDefined())
+			{
+				LLEventInfo::sCategories[id.asInteger()] = name.asString();
+			}
 		}
-		else
-		{
-			continue;
-		}
-
-		// Add the category id/name pair
-		option_it = response.find("category_name");
-		if (option_it != response.end())
-		{
-			LLEventInfo::sCategories[cat_id] = option_it->second;
-		}
-
 	}
-
 }
diff --git a/indra/newview/lleventinfo.h b/indra/newview/lleventinfo.h
index 880517a9f4b5f3cb3608348d19ea1d41b4da22ec..493c6599837bb97bdc5101b9686ac17fad1929d9 100644
--- a/indra/newview/lleventinfo.h
+++ b/indra/newview/lleventinfo.h
@@ -37,7 +37,6 @@
 
 #include "v3dmath.h"
 #include "lluuid.h"
-#include "lluserauth.h"
 
 class LLMessageSystem;
 
@@ -48,7 +47,7 @@ class LLEventInfo
 
 	void unpack(LLMessageSystem *msg);
 
-	static void loadCategories(LLUserAuth::options_t event_options);
+	static void loadCategories(const LLSD& options);
 
 public:
 	std::string mName;
diff --git a/indra/newview/lleventnotifier.cpp b/indra/newview/lleventnotifier.cpp
index 867fb0255a2ed94b14531d2fe669b3b24187833a..da20766e7ee48d389bceb3bbcb4dfe85475627c2 100644
--- a/indra/newview/lleventnotifier.cpp
+++ b/indra/newview/lleventnotifier.cpp
@@ -94,18 +94,16 @@ void LLEventNotifier::update()
 	}
 }
 
-void LLEventNotifier::load(const LLUserAuth::options_t& event_options)
+void LLEventNotifier::load(const LLSD& event_options)
 {
-	LLUserAuth::options_t::const_iterator resp_it;
-	for (resp_it = event_options.begin(); 
-		 resp_it != event_options.end(); 
-		 ++resp_it)
+	for(LLSD::array_const_iterator resp_it = event_options.beginArray(),
+		end = event_options.endArray(); resp_it != end; ++resp_it)
 	{
-		const LLUserAuth::response_t& response = *resp_it;
+		LLSD response = *resp_it;
 
 		LLEventNotification *new_enp = new LLEventNotification();
 
-		if (!new_enp->load(response))
+		if(!new_enp->load(response))
 		{
 			delete new_enp;
 			continue;
@@ -208,49 +206,46 @@ bool LLEventNotification::handleResponse(const LLSD& notification, const LLSD& r
 	return false;
 }
 
-BOOL LLEventNotification::load(const LLUserAuth::response_t &response)
+BOOL LLEventNotification::load(const LLSD& response)
 {
-
-	LLUserAuth::response_t::const_iterator option_it;
 	BOOL event_ok = TRUE;
-	option_it = response.find("event_id");
-	if (option_it != response.end())
+	LLSD option = response.get("event_id");
+	if (option.isDefined())
 	{
-		mEventID = atoi(option_it->second.c_str());
+		mEventID = option.asInteger();
 	}
 	else
 	{
 		event_ok = FALSE;
 	}
 
-	option_it = response.find("event_name");
-	if (option_it != response.end())
+	option = response.get("event_name");
+	if (option.isDefined())
 	{
-		llinfos << "Event: " << option_it->second << llendl;
-		mEventName = option_it->second;
+		llinfos << "Event: " << option.asString() << llendl;
+		mEventName = option.asString();
 	}
 	else
 	{
 		event_ok = FALSE;
 	}
 
-
-	option_it = response.find("event_date");
-	if (option_it != response.end())
+	option = response.get("event_date");
+	if (option.isDefined())
 	{
-		llinfos << "EventDate: " << option_it->second << llendl;
-		mEventDateStr = option_it->second;
+		llinfos << "EventDate: " << option.asString() << llendl;
+		mEventDateStr = option.asString();
 	}
 	else
 	{
 		event_ok = FALSE;
 	}
 
-	option_it = response.find("event_date_ut");
-	if (option_it != response.end())
+	option = response.get("event_date_ut");
+	if (option.isDefined())
 	{
-		llinfos << "EventDate: " << option_it->second << llendl;
-		mEventDate = strtoul(option_it->second.c_str(), NULL, 10);
+		llinfos << "EventDate: " << option.asString() << llendl;
+		mEventDate = strtoul(option.asString().c_str(), NULL, 10);
 	}
 	else
 	{
@@ -262,44 +257,44 @@ BOOL LLEventNotification::load(const LLUserAuth::response_t &response)
 	S32 x_region = 0;
 	S32 y_region = 0;
 
-	option_it = response.find("grid_x");
-	if (option_it != response.end())
+	option = response.get("grid_x");
+	if (option.isDefined())
 	{
-		llinfos << "GridX: " << option_it->second << llendl;
-		grid_x= atoi(option_it->second.c_str());
+		llinfos << "GridX: " << option.asInteger() << llendl;
+		grid_x= option.asInteger();
 	}
 	else
 	{
 		event_ok = FALSE;
 	}
 
-	option_it = response.find("grid_y");
-	if (option_it != response.end())
+	option = response.get("grid_y");
+	if (option.isDefined())
 	{
-		llinfos << "GridY: " << option_it->second << llendl;
-		grid_y = atoi(option_it->second.c_str());
+		llinfos << "GridY: " << option.asInteger() << llendl;
+		grid_y = option.asInteger();
 	}
 	else
 	{
 		event_ok = FALSE;
 	}
 
-	option_it = response.find("x_region");
-	if (option_it != response.end())
+	option = response.get("x_region");
+	if (option.isDefined())
 	{
-		llinfos << "RegionX: " << option_it->second << llendl;
-		x_region = atoi(option_it->second.c_str());
+		llinfos << "RegionX: " << option.asInteger() << llendl;
+		x_region = option.asInteger();
 	}
 	else
 	{
 		event_ok = FALSE;
 	}
 
-	option_it = response.find("y_region");
-	if (option_it != response.end())
+	option = response.get("y_region");
+	if (option.isDefined())
 	{
-		llinfos << "RegionY: " << option_it->second << llendl;
-		y_region = atoi(option_it->second.c_str());
+		llinfos << "RegionY: " << option.asInteger() << llendl;
+		y_region = option.asInteger();
 	}
 	else
 	{
diff --git a/indra/newview/lleventnotifier.h b/indra/newview/lleventnotifier.h
index feb734948c2853428a3ecb608476199849c2a660..6fdde876465c3409fe5b1d6cc535ea3a1f2ab314 100644
--- a/indra/newview/lleventnotifier.h
+++ b/indra/newview/lleventnotifier.h
@@ -34,7 +34,6 @@
 #define LL_LLEVENTNOTIFIER_H
 
 #include "llframetimer.h"
-#include "lluserauth.h"
 #include "v3dmath.h"
 
 class LLEventInfo;
@@ -49,7 +48,7 @@ class LLEventNotifier
 
 	void update();	// Notify the user of the event if it's coming up
 
-	void load(const LLUserAuth::options_t& event_options);	// In the format that it comes in from LLUserAuth
+	void load(const LLSD& event_options);	// In the format that it comes in from login
 	void add(LLEventInfo &event_info);	// Add a new notification for an event
 	void remove(U32 event_id);
 
@@ -69,7 +68,7 @@ class LLEventNotification
 	LLEventNotification();
 	virtual ~LLEventNotification();
 
-	BOOL load(const LLUserAuth::response_t &en);		// In the format it comes in from LLUserAuth
+	BOOL load(const LLSD& en);		// In the format it comes in from login
 	BOOL load(const LLEventInfo &event_info);		// From existing event_info on the viewer.
 	//void setEventID(const U32 event_id);
 	//void setEventName(std::string &event_name);
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index f44cdc1a989860c886c641eb361738335c45240e..2ab17d622005815fadde7d52321d089ffde26ada 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -996,8 +996,12 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is)
 			std::string label = iter->first;
 
 			F64 time = iter->second["Time"].asReal();
-			
-			total_time += time;
+
+			// Skip the total figure
+			if(label.compare("Total") != 0)
+			{
+				total_time += time;
+			}			
 
 			if (time > 0.0)
 			{
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 2a8365b3f0d9c1bc9712ff0051b99f3e549ab159..fb724f30e072b604995307db09fa685d0d2fd723 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -44,6 +44,7 @@
 #include "llgl.h"
 #include "llsecondlifeurls.h"
 
+#include "llappviewer.h"
 #include "llviewercontrol.h"
 #include "llworld.h"
 #include "lldrawpoolterrain.h"
@@ -58,11 +59,6 @@
 #include "lldxhardware.h"
 #endif
 
-//
-// externs
-//
-extern LLMemoryInfo gSysMemory;
-extern LLCPUInfo gSysCPU;
 
 #if LL_DARWIN
 const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt";
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index a4c38d03aa5e7180873b835b043b4ef88045abbd..92ad28a105a5e6a927087ad34fc15a2d52628cb9 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -1,293 +1,292 @@
-/** 
- * @file llfloaterabout.cpp
- * @author James Cook
- * @brief The about box from Help->About
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- * 
- * Copyright (c) 2001-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- 
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloaterabout.h"
-
-// Viewer includes
-#include "llagent.h"
-#include "llappviewer.h" 
-#include "llsecondlifeurls.h"
-#include "lluictrlfactory.h"
-#include "llviewertexteditor.h"
-#include "llviewercontrol.h"
-#include "llviewerstats.h"
-#include "llviewerregion.h"
-#include "llversionviewer.h"
-#include "llviewerbuild.h"
-#include "llweb.h"
-
-// Linden library includes
-#include "llaudioengine.h"
-#include "llbutton.h"
-#include "llcurl.h"
-#include "llglheaders.h"
-#include "llfloater.h"
-#include "llfloaterreg.h"
-#include "llimagej2c.h"
-#include "llsys.h"
-#include "lltrans.h"
-#include "lluri.h"
-#include "v3dmath.h"
-#include "llwindow.h"
-
-#if LL_WINDOWS
-#include "lldxhardware.h"
-#endif
-
-extern LLCPUInfo gSysCPU;
-extern LLMemoryInfo gSysMemory;
-extern U32 gPacketsIn;
-
-static std::string get_viewer_release_notes_url();
-
-
-///----------------------------------------------------------------------------
-/// Class LLFloaterAbout
-///----------------------------------------------------------------------------
-class LLFloaterAbout 
-	: public LLFloater
-{
-	friend class LLFloaterReg;
-private:
-	LLFloaterAbout(const LLSD& key);
-	virtual ~LLFloaterAbout();
-
-public:
-	/*virtual*/ BOOL postBuild();
-	void onClickCopyToClipboard();
-};
-
-
-// Default constructor
-LLFloaterAbout::LLFloaterAbout(const LLSD& key) 
-:	LLFloater(key)
-{
-	//LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml");
-	
-}
-
-// Destroys the object
-LLFloaterAbout::~LLFloaterAbout()
-{
-}
-
-BOOL LLFloaterAbout::postBuild()
-{
-	center();
-	LLViewerTextEditor *support_widget = 
-		getChild<LLViewerTextEditor>("support_editor", true);
-
-	LLViewerTextEditor *credits_widget = 
-		getChild<LLViewerTextEditor>("credits_editor", true);
-
-	getChild<LLUICtrl>("copy_btn")->setCommitCallback(
-		boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
-
-	// Version string
-	std::string version = LLTrans::getString("APP_NAME")
-		+ llformat(" %d.%d.%d (%d) %s %s (%s)\n",
-				   LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD,
-				   __DATE__, __TIME__,
-				   gSavedSettings.getString("VersionChannelName").c_str());
-
-	std::string support;
-	support.append(version);
-	support.append("[" + get_viewer_release_notes_url() + " " +
-				   LLTrans::getString("ReleaseNotes") + "]");
-	support.append("\n\n");
-
-#if LL_MSVC
-    support.append(llformat("Built with MSVC version %d\n\n", _MSC_VER));
-#endif
-
-#if LL_GNUC
-    support.append(llformat("Built with GCC version %d\n\n", GCC_VERSION));
-#endif
-
-	// Position
-	LLViewerRegion* region = gAgent.getRegion();
-	if (region)
-	{
-		const LLVector3d &pos = gAgent.getPositionGlobal();
-		LLUIString pos_text = getString("you_are_at");
-		pos_text.setArg("[POSITION]",
-						llformat("%.1f, %.1f, %.1f ", pos.mdV[VX], pos.mdV[VY], pos.mdV[VZ]));
-		support.append(pos_text);
-
-		LLUIString region_text = getString ("in_region") + " ";
-		region_text.setArg("[REGION]", llformat ("%s", gAgent.getRegion()->getName().c_str()));
-		support.append(region_text);
-
-		std::string buffer;
-		buffer = gAgent.getRegion()->getHost().getHostName();
-		support.append(buffer);
-		support.append(" (");
-		buffer = gAgent.getRegion()->getHost().getString();
-		support.append(buffer);
-		support.append(")\n");
-		support.append(gLastVersionChannel);
-		support.append("\n");
-		support.append("[" + LLWeb::escapeURL(region->getCapability("ServerReleaseNotes")) +
-					   " " + LLTrans::getString("ReleaseNotes") + "]");
-		support.append("\n\n");
-	}
-
-	// *NOTE: Do not translate text like GPU, Graphics Card, etc -
-	//  Most PC users that know what these mean will be used to the english versions,
-	//  and this info sometimes gets sent to support
-	
-	// CPU
-	support.append(getString("CPU") + " ");
-	support.append( gSysCPU.getCPUString() );
-	support.append("\n");
-
-	U32 memory = gSysMemory.getPhysicalMemoryKB() / 1024;
-	// Moved hack adjustment to Windows memory size into llsys.cpp
-
-	LLStringUtil::format_map_t args;
-	args["[MEM]"] = llformat ("%u", memory);
-	support.append(getString("Memory", args) + "\n");
-
-	support.append(getString("OSVersion") + " ");
-	support.append( LLAppViewer::instance()->getOSInfo().getOSString() );
-	support.append("\n");
-
-	support.append(getString("GraphicsCardVendor") + " ");
-	support.append( (const char*) glGetString(GL_VENDOR) );
-	support.append("\n");
-
-	support.append(getString("GraphicsCard") + " ");
-	support.append( (const char*) glGetString(GL_RENDERER) );
-	support.append("\n");
-
-#if LL_WINDOWS
-    getWindow()->incBusyCount();
-    getWindow()->setCursor(UI_CURSOR_ARROW);
-    support.append("Windows Graphics Driver Version: ");
-    LLSD driver_info = gDXHardware.getDisplayInfo();
-    if (driver_info.has("DriverVersion"))
-    {
-        support.append(driver_info["DriverVersion"]);
-    }
-    support.append("\n");
-    getWindow()->decBusyCount();
-    getWindow()->setCursor(UI_CURSOR_ARROW);
-#endif
-
-	support.append(getString("OpenGLVersion") + " ");
-	support.append( (const char*) glGetString(GL_VERSION) );
-	support.append("\n");
-
-	support.append("\n");
-
-	support.append(getString("LibCurlVersion") + " ");
-	support.append( LLCurl::getVersionString() );
-	support.append("\n");
-
-	support.append(getString("J2CDecoderVersion") + " ");
-	support.append( LLImageJ2C::getEngineInfo() );
-	support.append("\n");
-
-	support.append(getString("AudioDriverVersion") + " ");
-	bool want_fullname = true;
-	support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : getString("none") );
-	support.append("\n");
-
-	// TODO: Implement media plugin version query
-
-	support.append(getString("LLQtWebkitVersion") + " ");
-	support.append("\n");
-
-	if (gPacketsIn > 0)
-	{
-		args["[LOST]"] = llformat ("%.0f", LLViewerStats::getInstance()->mPacketsLostStat.getCurrent());
-		args["[IN]"] = llformat ("%.0f", F32(gPacketsIn));
-		args["[PCT]"] = llformat ("%.1f", 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) );
-		support.append(getString ("PacketsLost", args) + "\n");
-	}
-
-	support_widget->appendText(support, 
-								FALSE, 
-								LLStyle::Params()
-									.color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor")));
-	support_widget->blockUndo();
-
-	// Fix views
-	support_widget->setCursorPos(0);
-	support_widget->setEnabled(FALSE);
-
-	credits_widget->setCursorPos(0);
-	credits_widget->setEnabled(FALSE);
-
-	return TRUE;
-}
-
-
-static std::string get_viewer_release_notes_url()
-{
-	std::ostringstream version;
-	version << LL_VERSION_MAJOR << "."
-		<< LL_VERSION_MINOR << "."
-		<< LL_VERSION_PATCH << "."
-		<< LL_VERSION_BUILD;
-
-	LLSD query;
-	query["channel"] = gSavedSettings.getString("VersionChannelName");
-	query["version"] = version.str();
-
-	std::ostringstream url;
-	url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query);
-
-	return LLWeb::escapeURL(url.str());
-}
-
-void LLFloaterAbout::onClickCopyToClipboard()
-{
-	LLViewerTextEditor *support_widget = 
-		getChild<LLViewerTextEditor>("support_editor", true);
-	support_widget->selectAll();
-	support_widget->copy();
-	support_widget->deselect();
-}
-
-///----------------------------------------------------------------------------
-/// LLFloaterAboutUtil
-///----------------------------------------------------------------------------
-void LLFloaterAboutUtil::registerFloater()
-{
-	LLFloaterReg::add("sl_about", "floater_about.xml",
-		&LLFloaterReg::build<LLFloaterAbout>);
-
-}
+/** 
+ * @file llfloaterabout.cpp
+ * @author James Cook
+ * @brief The about box from Help->About
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+ 
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterabout.h"
+
+// Viewer includes
+#include "llagent.h"
+#include "llappviewer.h" 
+#include "llsecondlifeurls.h"
+#include "lluictrlfactory.h"
+#include "llviewertexteditor.h"
+#include "llviewercontrol.h"
+#include "llviewerstats.h"
+#include "llviewerregion.h"
+#include "llversionviewer.h"
+#include "llviewerbuild.h"
+#include "llweb.h"
+
+// Linden library includes
+#include "llaudioengine.h"
+#include "llbutton.h"
+#include "llcurl.h"
+#include "llglheaders.h"
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "llimagej2c.h"
+#include "llsys.h"
+#include "lltrans.h"
+#include "lluri.h"
+#include "v3dmath.h"
+#include "llwindow.h"
+
+#if LL_WINDOWS
+#include "lldxhardware.h"
+#endif
+
+extern LLMemoryInfo gSysMemory;
+extern U32 gPacketsIn;
+
+static std::string get_viewer_release_notes_url();
+
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterAbout
+///----------------------------------------------------------------------------
+class LLFloaterAbout 
+	: public LLFloater
+{
+	friend class LLFloaterReg;
+private:
+	LLFloaterAbout(const LLSD& key);
+	virtual ~LLFloaterAbout();
+
+public:
+	/*virtual*/ BOOL postBuild();
+	void onClickCopyToClipboard();
+};
+
+
+// Default constructor
+LLFloaterAbout::LLFloaterAbout(const LLSD& key) 
+:	LLFloater(key)
+{
+	//LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml");
+	
+}
+
+// Destroys the object
+LLFloaterAbout::~LLFloaterAbout()
+{
+}
+
+BOOL LLFloaterAbout::postBuild()
+{
+	center();
+	LLViewerTextEditor *support_widget = 
+		getChild<LLViewerTextEditor>("support_editor", true);
+
+	LLViewerTextEditor *credits_widget = 
+		getChild<LLViewerTextEditor>("credits_editor", true);
+
+	getChild<LLUICtrl>("copy_btn")->setCommitCallback(
+		boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
+
+	// Version string
+	std::string version = LLTrans::getString("APP_NAME")
+		+ llformat(" %d.%d.%d (%d) %s %s (%s)\n",
+				   LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD,
+				   __DATE__, __TIME__,
+				   gSavedSettings.getString("VersionChannelName").c_str());
+
+	std::string support;
+	support.append(version);
+	support.append("[" + get_viewer_release_notes_url() + " " +
+				   LLTrans::getString("ReleaseNotes") + "]");
+	support.append("\n\n");
+
+#if LL_MSVC
+    support.append(llformat("Built with MSVC version %d\n\n", _MSC_VER));
+#endif
+
+#if LL_GNUC
+    support.append(llformat("Built with GCC version %d\n\n", GCC_VERSION));
+#endif
+
+	// Position
+	LLViewerRegion* region = gAgent.getRegion();
+	if (region)
+	{
+		const LLVector3d &pos = gAgent.getPositionGlobal();
+		LLUIString pos_text = getString("you_are_at");
+		pos_text.setArg("[POSITION]",
+						llformat("%.1f, %.1f, %.1f ", pos.mdV[VX], pos.mdV[VY], pos.mdV[VZ]));
+		support.append(pos_text);
+
+		LLUIString region_text = getString ("in_region") + " ";
+		region_text.setArg("[REGION]", llformat ("%s", gAgent.getRegion()->getName().c_str()));
+		support.append(region_text);
+
+		std::string buffer;
+		buffer = gAgent.getRegion()->getHost().getHostName();
+		support.append(buffer);
+		support.append(" (");
+		buffer = gAgent.getRegion()->getHost().getString();
+		support.append(buffer);
+		support.append(")\n");
+		support.append(gLastVersionChannel);
+		support.append("\n");
+		support.append("[" + LLWeb::escapeURL(region->getCapability("ServerReleaseNotes")) +
+					   " " + LLTrans::getString("ReleaseNotes") + "]");
+		support.append("\n\n");
+	}
+
+	// *NOTE: Do not translate text like GPU, Graphics Card, etc -
+	//  Most PC users that know what these mean will be used to the english versions,
+	//  and this info sometimes gets sent to support
+	
+	// CPU
+	support.append(getString("CPU") + " ");
+	support.append( gSysCPU.getCPUString() );
+	support.append("\n");
+
+	U32 memory = gSysMemory.getPhysicalMemoryKB() / 1024;
+	// Moved hack adjustment to Windows memory size into llsys.cpp
+
+	LLStringUtil::format_map_t args;
+	args["[MEM]"] = llformat ("%u", memory);
+	support.append(getString("Memory", args) + "\n");
+
+	support.append(getString("OSVersion") + " ");
+	support.append( LLAppViewer::instance()->getOSInfo().getOSString() );
+	support.append("\n");
+
+	support.append(getString("GraphicsCardVendor") + " ");
+	support.append( (const char*) glGetString(GL_VENDOR) );
+	support.append("\n");
+
+	support.append(getString("GraphicsCard") + " ");
+	support.append( (const char*) glGetString(GL_RENDERER) );
+	support.append("\n");
+
+#if LL_WINDOWS
+    getWindow()->incBusyCount();
+    getWindow()->setCursor(UI_CURSOR_ARROW);
+    support.append("Windows Graphics Driver Version: ");
+    LLSD driver_info = gDXHardware.getDisplayInfo();
+    if (driver_info.has("DriverVersion"))
+    {
+        support.append(driver_info["DriverVersion"]);
+    }
+    support.append("\n");
+    getWindow()->decBusyCount();
+    getWindow()->setCursor(UI_CURSOR_ARROW);
+#endif
+
+	support.append(getString("OpenGLVersion") + " ");
+	support.append( (const char*) glGetString(GL_VERSION) );
+	support.append("\n");
+
+	support.append("\n");
+
+	support.append(getString("LibCurlVersion") + " ");
+	support.append( LLCurl::getVersionString() );
+	support.append("\n");
+
+	support.append(getString("J2CDecoderVersion") + " ");
+	support.append( LLImageJ2C::getEngineInfo() );
+	support.append("\n");
+
+	support.append(getString("AudioDriverVersion") + " ");
+	bool want_fullname = true;
+	support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : getString("none") );
+	support.append("\n");
+
+	// TODO: Implement media plugin version query
+
+	support.append(getString("LLQtWebkitVersion") + " ");
+	support.append("\n");
+
+	if (gPacketsIn > 0)
+	{
+		args["[LOST]"] = llformat ("%.0f", LLViewerStats::getInstance()->mPacketsLostStat.getCurrent());
+		args["[IN]"] = llformat ("%.0f", F32(gPacketsIn));
+		args["[PCT]"] = llformat ("%.1f", 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) );
+		support.append(getString ("PacketsLost", args) + "\n");
+	}
+
+	support_widget->appendText(support, 
+								FALSE, 
+								LLStyle::Params()
+									.color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor")));
+	support_widget->blockUndo();
+
+	// Fix views
+	support_widget->setCursorPos(0);
+	support_widget->setEnabled(FALSE);
+
+	credits_widget->setCursorPos(0);
+	credits_widget->setEnabled(FALSE);
+
+	return TRUE;
+}
+
+
+static std::string get_viewer_release_notes_url()
+{
+	std::ostringstream version;
+	version << LL_VERSION_MAJOR << "."
+		<< LL_VERSION_MINOR << "."
+		<< LL_VERSION_PATCH << "."
+		<< LL_VERSION_BUILD;
+
+	LLSD query;
+	query["channel"] = gSavedSettings.getString("VersionChannelName");
+	query["version"] = version.str();
+
+	std::ostringstream url;
+	url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query);
+
+	return LLWeb::escapeURL(url.str());
+}
+
+void LLFloaterAbout::onClickCopyToClipboard()
+{
+	LLViewerTextEditor *support_widget = 
+		getChild<LLViewerTextEditor>("support_editor", true);
+	support_widget->selectAll();
+	support_widget->copy();
+	support_widget->deselect();
+}
+
+///----------------------------------------------------------------------------
+/// LLFloaterAboutUtil
+///----------------------------------------------------------------------------
+void LLFloaterAboutUtil::registerFloater()
+{
+	LLFloaterReg::add("sl_about", "floater_about.xml",
+		&LLFloaterReg::build<LLFloaterAbout>);
+
+}
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index cb0d304aa0624f78c9e2c1fb73eb13d69361f586..262dc1804d3b5e1e1c0c28b89b5c9a1b6d586eab 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -58,6 +58,7 @@
 #include "llui.h"
 #include "llrender.h"
 #include "llsdutil.h"
+#include "llsdutil_math.h"
 
 ///----------------------------------------------------------------------------
 /// Local function declarations, constants, enums, and typedefs
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index 2c2a5107f53c50071885b75572df695568073769..36f031579046d6201445598a96e5c12c82f6f5d8 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -81,6 +81,8 @@ class LLFloaterBuyLandUI
 	LLFloaterBuyLandUI(const LLSD& key);
 	virtual ~LLFloaterBuyLandUI();
 	
+	/*virtual*/ void onClose(bool app_quitting);
+	
 private:
 	class SelectionObserver : public LLParcelObserver
 	{
@@ -300,11 +302,21 @@ LLFloaterBuyLandUI::LLFloaterBuyLandUI(const LLSD& key)
 LLFloaterBuyLandUI::~LLFloaterBuyLandUI()
 {
 	LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver);
-	LLViewerParcelMgr::getInstance()->deleteParcelBuy(mParcelBuyInfo);
+	LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo);
 	
 	delete mTransaction;
 }
 
+// virtual
+void LLFloaterBuyLandUI::onClose(bool app_quitting)
+{
+	// This object holds onto observer, transactions, and parcel state.
+	// Despite being single_instance, destroy it to call destructors and clean
+	// everything up.
+	setVisible(FALSE);
+	destroy();
+}
+
 void LLFloaterBuyLandUI::SelectionObserver::changed()
 {
 	if (LLViewerParcelMgr::getInstance()->selectionEmpty())
@@ -756,7 +768,7 @@ void LLFloaterBuyLandUI::sendBuyLand()
 	if (mParcelBuyInfo)
 	{
 		LLViewerParcelMgr::getInstance()->sendParcelBuy(mParcelBuyInfo);
-		LLViewerParcelMgr::getInstance()->deleteParcelBuy(mParcelBuyInfo);
+		LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo);
 		mBought = true;
 	}
 }
diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h
index 9242f00c912177a8fc113fd23bbe6589df78a9e5..9c6660c0dc2abd55300827685ed115146ebed96a 100644
--- a/indra/newview/llfloaterfriends.h
+++ b/indra/newview/llfloaterfriends.h
@@ -74,6 +74,9 @@ class LLPanelFriends : public LLPanel, public LLEventTimer
 
 	virtual BOOL postBuild();
 
+	// *HACK Made public to remove friends from LLAvatarIconCtrl context menu
+	static bool handleRemove(const LLSD& notification, const LLSD& response);
+
 private:
 
 	enum FRIENDS_COLUMN_ORDER
diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp
index aa457de2d87bb418784877e56f8bfbfb5248a9c3..d941f24f49e0ca81c338306eebb48b51f22974ca 100644
--- a/indra/newview/llfloatermediasettings.cpp
+++ b/indra/newview/llfloatermediasettings.cpp
@@ -118,6 +118,7 @@ BOOL LLFloaterMediaSettings::postBuild()
 	mTabContainer->addTabPanel( 
 			LLTabContainer::TabPanelParams().
 			panel(mPanelMediaSettingsSecurity));
+	mPanelMediaSettingsSecurity->setParent( this );
 		
 	// restore the last tab viewed from persistance variable storage
 	if (!mTabContainer->selectTab(gSavedSettings.getS32("LastMediaSettingsTab")))
@@ -248,3 +249,28 @@ void LLFloaterMediaSettings::enableOkApplyBtns( bool enable )
 	childSetEnabled( "OK", enable );
 	childSetEnabled( "Apply", enable );
 }
+
+////////////////////////////////////////////////////////////////////////////////
+//
+const std::string LLFloaterMediaSettings::getHomeUrl()
+{
+	if ( mPanelMediaSettingsGeneral )
+		return mPanelMediaSettingsGeneral->getHomeUrl();
+	else
+		return std::string( "" );
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool LLFloaterMediaSettings::passesWhiteList( const std::string& test_url )
+{
+	// sanity check - don't think this can happen
+	if ( mPanelMediaSettingsSecurity )
+		// version in security dialog code is specialized so we pass in 
+		// empty string for first parameter since it's not used
+		return mPanelMediaSettingsSecurity->passesWhiteList( "", test_url );
+	else
+		// this is all we can do
+		return false;
+}
diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h
index e2683039cc2ef30f59a560e59399fc4f3a0ac2e0..17a47cb0f5a4b04cd3846574261f251a9855fac8 100644
--- a/indra/newview/llfloatermediasettings.h
+++ b/indra/newview/llfloatermediasettings.h
@@ -56,6 +56,8 @@ class LLFloaterMediaSettings :
 	static void clearValues( bool editable);
 	void enableOkApplyBtns( bool enable );
 	LLPanelMediaSettingsSecurity* getPanelSecurity(){return mPanelMediaSettingsSecurity;};
+	const std::string getHomeUrl();
+	bool passesWhiteList( const std::string& test_url );
 
 	bool mIdenticalHasMediaInfo;
 	bool mMultipleMedia;
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index e15fdd3e3511be4598842357d2eb79c4eddd5e70..11544f5b7b58780180ce9022df5bd14c7ac5c5cc 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -442,52 +442,43 @@ LLPanelRegionInfo::LLPanelRegionInfo()
 {
 }
 
-// static
-void LLPanelRegionInfo::onBtnSet(void* user_data)
+void LLPanelRegionInfo::onBtnSet()
 {
-	LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data;
-	if(!panel) return;
-	if (panel->sendUpdate())
+	if (sendUpdate())
 	{
-		panel->disableButton("apply_btn");
+		disableButton("apply_btn");
 	}
 }
 
-//static 
-void LLPanelRegionInfo::onChangeChildCtrl(LLUICtrl* ctrl, void* user_data)
+void LLPanelRegionInfo::onChangeChildCtrl(LLUICtrl* ctrl)
 {
-	if (ctrl)
-	{
-		LLPanelRegionInfo* panel = (LLPanelRegionInfo*) ctrl->getParent();
-		panel->updateChild(ctrl);
-	}
+	updateChild(ctrl); // virtual function
 }
 
-// static
 // Enables the "set" button if it is not already enabled
-void LLPanelRegionInfo::onChangeAnything(LLUICtrl* ctrl, void* user_data)
+void LLPanelRegionInfo::onChangeAnything()
 {
-	LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data;
-	if(panel)
-	{
-		panel->enableButton("apply_btn");
-		panel->refresh();
-	}
+	enableButton("apply_btn");
+	refresh();
 }
 
 // static
 // Enables set button on change to line editor
 void LLPanelRegionInfo::onChangeText(LLLineEditor* caller, void* user_data)
 {
-	// reuse the previous method
-	onChangeAnything(0, user_data);
+	LLPanelRegionInfo* panel = dynamic_cast<LLPanelRegionInfo*>(caller->getParent());
+	if(panel)
+	{
+		panel->enableButton("apply_btn");
+		panel->refresh();
+	}
 }
 
 
 // virtual
 BOOL LLPanelRegionInfo::postBuild()
 {
-	childSetAction("apply_btn", onBtnSet, this);
+	getChild<LLUICtrl>("apply_btn")->setCommitCallback(boost::bind(&LLPanelRegionInfo::onBtnSet, this));
 	childDisable("apply_btn");
 	refresh();
 	return TRUE;
@@ -550,19 +541,17 @@ void LLPanelRegionInfo::disableButton(const std::string& btn_name)
 
 void LLPanelRegionInfo::initCtrl(const std::string& name)
 {
-	childSetCommitCallback(name, onChangeAnything, this);
+	getChild<LLUICtrl>(name)->setCommitCallback(boost::bind(&LLPanelRegionInfo::onChangeAnything, this));
 }
 
 void LLPanelRegionInfo::initHelpBtn(const std::string& name, const std::string& xml_alert)
 {
-	childSetAction(name, onClickHelp, new std::string(xml_alert));
+	getChild<LLUICtrl>(name)->setCommitCallback(boost::bind(&LLPanelRegionInfo::onClickHelp, this, xml_alert));
 }
 
-// static
-void LLPanelRegionInfo::onClickHelp(void* data)
+void LLPanelRegionInfo::onClickHelp(std::string xml_alert)
 {
-	std::string* xml_alert = (std::string*)data;
-	LLNotifications::instance().add(*xml_alert);
+	LLNotifications::instance().add(xml_alert);
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -1207,9 +1196,9 @@ BOOL LLPanelRegionTerrainInfo::postBuild()
 	initCtrl("terrain_lower_spin");
 
 	initCtrl("fixed_sun_check");
-	childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this);
-	childSetCommitCallback("use_estate_sun_check", onChangeUseEstateTime, this);
-	childSetCommitCallback("sun_hour_slider", onChangeSunHour, this);
+	getChild<LLUICtrl>("fixed_sun_check")->setCommitCallback(boost::bind(&LLPanelRegionTerrainInfo::onChangeFixedSun, this));
+	getChild<LLUICtrl>("use_estate_sun_check")->setCommitCallback(boost::bind(&LLPanelRegionTerrainInfo::onChangeUseEstateTime, this));
+	getChild<LLUICtrl>("sun_hour_slider")->setCommitCallback(boost::bind(&LLPanelRegionTerrainInfo::onChangeSunHour, this));
 
 	childSetAction("download_raw_btn", onClickDownloadRaw, this);
 	childSetAction("upload_raw_btn", onClickUploadRaw, this);
@@ -1292,39 +1281,29 @@ BOOL LLPanelRegionTerrainInfo::sendUpdate()
 	return TRUE;
 }
 
-// static 
-void LLPanelRegionTerrainInfo::onChangeUseEstateTime(LLUICtrl* ctrl, void* user_data)
+void LLPanelRegionTerrainInfo::onChangeUseEstateTime()
 {
-	LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data;
-	if (!panel) return;
-	BOOL use_estate_sun = panel->childGetValue("use_estate_sun_check").asBoolean();
-	panel->childSetEnabled("fixed_sun_check", !use_estate_sun);
-	panel->childSetEnabled("sun_hour_slider", !use_estate_sun);
+	BOOL use_estate_sun = childGetValue("use_estate_sun_check").asBoolean();
+	childSetEnabled("fixed_sun_check", !use_estate_sun);
+	childSetEnabled("sun_hour_slider", !use_estate_sun);
 	if (use_estate_sun)
 	{
-		panel->childSetValue("fixed_sun_check", LLSD(FALSE));
-		panel->childSetValue("sun_hour_slider", LLSD(0.f));
+		childSetValue("fixed_sun_check", LLSD(FALSE));
+		childSetValue("sun_hour_slider", LLSD(0.f));
 	}
-	panel->childEnable("apply_btn");
+	childEnable("apply_btn");
 }
 
-// static 
-void LLPanelRegionTerrainInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data)
+void LLPanelRegionTerrainInfo::onChangeFixedSun()
 {
-	LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data;
-	if (!panel) return;
 	// Just enable the apply button.  We let the sun-hour slider be enabled
 	// for both fixed-sun and non-fixed-sun. JC
-	panel->childEnable("apply_btn");
+	childEnable("apply_btn");
 }
 
-// static 
-void LLPanelRegionTerrainInfo::onChangeSunHour(LLUICtrl* ctrl, void*)
+void LLPanelRegionTerrainInfo::onChangeSunHour()
 {
-	// can't use userdata to get panel, slider uses it internally
-	LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) ctrl->getParent();
-	if (!panel) return;
-	panel->childEnable("apply_btn");
+	childEnable("apply_btn");
 }
 
 // static
@@ -1420,32 +1399,23 @@ void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch)
 	estate_dispatch_initialized = true;
 }
 
-// static
 // Disables the sun-hour slider and the use fixed time check if the use global time is check
-void LLPanelEstateInfo::onChangeUseGlobalTime(LLUICtrl* ctrl, void* user_data)
+void LLPanelEstateInfo::onChangeUseGlobalTime()
 {
-	LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data;
-	if (panel)
-	{
-		bool enabled = !panel->childGetValue("use_global_time_check").asBoolean();
-		panel->childSetEnabled("sun_hour_slider", enabled);
-		panel->childSetEnabled("fixed_sun_check", enabled);
-		panel->childSetValue("fixed_sun_check", LLSD(FALSE));
-		panel->enableButton("apply_btn");
-	}
+	bool enabled = !childGetValue("use_global_time_check").asBoolean();
+	childSetEnabled("sun_hour_slider", enabled);
+	childSetEnabled("fixed_sun_check", enabled);
+	childSetValue("fixed_sun_check", LLSD(FALSE));
+	enableButton("apply_btn");
 }
 
 // Enables the sun-hour slider if the fixed-sun checkbox is set
-void LLPanelEstateInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data)
+void LLPanelEstateInfo::onChangeFixedSun()
 {
-	LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data;
-	if (panel)
-	{
-		bool enabled = !panel->childGetValue("fixed_sun_check").asBoolean();
-		panel->childSetEnabled("use_global_time_check", enabled);
-		panel->childSetValue("use_global_time_check", LLSD(FALSE));
-		panel->enableButton("apply_btn");
-	}
+	bool enabled = !childGetValue("fixed_sun_check").asBoolean();
+	childSetEnabled("use_global_time_check", enabled);
+	childSetValue("use_global_time_check", LLSD(FALSE));
+	enableButton("apply_btn");
 }
 
 
@@ -2130,7 +2100,7 @@ BOOL LLPanelEstateInfo::postBuild()
 	initCtrl("limit_payment");
 	initCtrl("limit_age_verified");
 	initCtrl("voice_chat_check");
-	childSetCommitCallback("abuse_email_address", onChangeAnything, this);
+	getChild<LLUICtrl>("abuse_email_address")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeAnything, this));
 	getChild<LLLineEditor>("abuse_email_address")->setKeystrokeCallback(onChangeText, this);
 
 	initHelpBtn("estate_manager_help",			"HelpEstateEstateManager");
@@ -2144,15 +2114,15 @@ BOOL LLPanelEstateInfo::postBuild()
 	initHelpBtn("allow_resident_help",			"HelpEstateAllowResident");
 	initHelpBtn("allow_group_help",				"HelpEstateAllowGroup");
 	initHelpBtn("ban_resident_help",			"HelpEstateBanResident");
-	initHelpBtn("abuse_email_address_help",         "HelpEstateAbuseEmailAddress");
-	initHelpBtn("voice_chat_help",                  "HelpEstateVoiceChat");
+	initHelpBtn("abuse_email_address_help",     "HelpEstateAbuseEmailAddress");
+	initHelpBtn("voice_chat_help",              "HelpEstateVoiceChat");
 
 	// set up the use global time checkbox
-	childSetCommitCallback("use_global_time_check", onChangeUseGlobalTime, this);
-	childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this);
-	childSetCommitCallback("sun_hour_slider", onChangeChildCtrl, this);
-
-	childSetCommitCallback("allowed_avatar_name_list", onChangeChildCtrl, this);
+	getChild<LLUICtrl>("use_global_time_check")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeUseGlobalTime, this));
+	getChild<LLUICtrl>("fixed_sun_check")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeFixedSun, this));
+	getChild<LLUICtrl>("sun_hour_slider")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
+	
+	getChild<LLUICtrl>("allowed_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));	
 	LLNameListCtrl *avatar_name_list = getChild<LLNameListCtrl>("allowed_avatar_name_list");
 	if (avatar_name_list)
 	{
@@ -2163,7 +2133,7 @@ BOOL LLPanelEstateInfo::postBuild()
 	childSetAction("add_allowed_avatar_btn", onClickAddAllowedAgent, this);
 	childSetAction("remove_allowed_avatar_btn", onClickRemoveAllowedAgent, this);
 
-	childSetCommitCallback("allowed_group_name_list", onChangeChildCtrl, this);
+	getChild<LLUICtrl>("allowed_group_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
 	LLNameListCtrl* group_name_list = getChild<LLNameListCtrl>("allowed_group_name_list");
 	if (group_name_list)
 	{
@@ -2174,7 +2144,7 @@ BOOL LLPanelEstateInfo::postBuild()
 	getChild<LLUICtrl>("add_allowed_group_btn")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onClickAddAllowedGroup, this));
 	childSetAction("remove_allowed_group_btn", onClickRemoveAllowedGroup, this);
 
-	childSetCommitCallback("banned_avatar_name_list", onChangeChildCtrl, this);
+	getChild<LLUICtrl>("banned_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
 	LLNameListCtrl* banned_name_list = getChild<LLNameListCtrl>("banned_avatar_name_list");
 	if (banned_name_list)
 	{
@@ -2185,7 +2155,7 @@ BOOL LLPanelEstateInfo::postBuild()
 	childSetAction("add_banned_avatar_btn", onClickAddBannedAgent, this);
 	childSetAction("remove_banned_avatar_btn", onClickRemoveBannedAgent, this);
 
-	childSetCommitCallback("estate_manager_name_list", onChangeChildCtrl, this);
+	getChild<LLUICtrl>("estate_manager_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
 	LLNameListCtrl* manager_name_list = getChild<LLNameListCtrl>("estate_manager_name_list");
 	if (manager_name_list)
 	{
@@ -2299,13 +2269,18 @@ void LLPanelEstateInfo::getEstateOwner()
 class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
 {
 public:
-	LLEstateChangeInfoResponder(void* userdata) : mpPanel((LLPanelEstateInfo*)userdata) {};
+	LLEstateChangeInfoResponder(LLPanelEstateInfo* panel)
+	{
+		mpPanel = panel->getHandle();
+	}
 	
 	// if we get a normal response, handle it here
 	virtual void result(const LLSD& content)
 	{
 	    // refresh the panel from the database
-		mpPanel->refresh();
+		LLPanelEstateInfo* panel = dynamic_cast<LLPanelEstateInfo*>(mpPanel.get());
+		if (panel)
+			panel->refresh();
 	}
 	
 	// if we get an error response
@@ -2315,7 +2290,7 @@ class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
 			<< status << ": " << reason << llendl;
 	}
 private:
-	LLPanelEstateInfo* mpPanel;
+	LLHandle<LLPanel> mpPanel;
 };
 
 // tries to send estate info using a cap; returns true if it succeeded
@@ -2353,7 +2328,7 @@ bool LLPanelEstateInfo::commitEstateInfoCaps()
 	body["owner_abuse_email"] = childGetValue("abuse_email_address").asString();
 
 	// we use a responder so that we can re-get the data after committing to the database
-	LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder((void*)this));
+	LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder(this));
     return true;
 }
 
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index 68ed4e0c897ac71b70159bd62794ea2fe428b339..95833af8a107f3bf9c7c8e4a5c6468a421260073 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -109,9 +109,9 @@ class LLPanelRegionInfo : public LLPanel
 public:
 	LLPanelRegionInfo();
 	
-	static void onBtnSet(void* user_data);
-	static void onChangeChildCtrl(LLUICtrl* ctrl, void* user_data);
-	static void onChangeAnything(LLUICtrl* ctrl, void* user_data);
+	void onBtnSet();
+	void onChangeChildCtrl(LLUICtrl* ctrl);
+	void onChangeAnything();
 	static void onChangeText(LLLineEditor* caller, void* user_data);
 	
 	virtual bool refreshFromRegion(LLViewerRegion* region);
@@ -128,7 +128,7 @@ class LLPanelRegionInfo : public LLPanel
 	void initHelpBtn(const std::string& name, const std::string& xml_alert);
 
 	// Callback for all help buttons, data is name of XML alert to show.
-	static void onClickHelp(void* data);
+	void onClickHelp(std::string xml_alert);
 	
 	// Returns TRUE if update sent and apply button should be
 	// disabled.
@@ -239,9 +239,9 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo
 protected:
 	virtual BOOL sendUpdate();
 
-	static void onChangeUseEstateTime(LLUICtrl* ctrl, void* user_data);
-	static void onChangeFixedSun(LLUICtrl* ctrl, void* user_data);
-	static void onChangeSunHour(LLUICtrl* ctrl, void*);
+	void onChangeUseEstateTime();
+	void onChangeFixedSun();
+	void onChangeSunHour();
 
 	static void onClickDownloadRaw(void*);
 	static void onClickUploadRaw(void*);
@@ -256,8 +256,8 @@ class LLPanelEstateInfo : public LLPanelRegionInfo
 public:
 	static void initDispatch(LLDispatcher& dispatch);
 	
-	static void onChangeFixedSun(LLUICtrl* ctrl, void* user_data);
-	static void onChangeUseGlobalTime(LLUICtrl* ctrl, void* user_data);
+	void onChangeFixedSun();
+	void onChangeUseGlobalTime();
 	
 	static void onClickEditSky(void* userdata);
 	static void onClickEditSkyHelp(void* userdata);	
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index e00b352c9bd9da8963241cfef8278d65eddcfbc2..92980c22c7cee6c09ade8e4e2db5599828c53676 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1038,12 +1038,13 @@ void LLFloaterTools::getMediaState()
 		  &&first_object->permModify() 
 	      ))
 	{
-		childSetEnabled("media_tex", FALSE);
+		childSetEnabled("Add_Media",  FALSE);
+/*		childSetEnabled("media_tex", FALSE);
 		childSetEnabled("add_media", FALSE);
 		childSetEnabled("delete_media", FALSE);
 		childSetEnabled("edit_media", FALSE);
 		childSetEnabled("media_info", FALSE);
-		media_info->setEnabled(FALSE);
+		media_info->setEnabled(FALSE);*/
 		media_info->clear();
 		clearMediaSettings();
 		return;
@@ -1054,13 +1055,14 @@ void LLFloaterTools::getMediaState()
 	
 	if(!has_media_capability)
 	{
-		childSetEnabled("media_tex", FALSE);
+		childSetEnabled("Add_Media",  FALSE);
+	/*	childSetEnabled("media_tex", FALSE);
 		childSetEnabled("add_media", FALSE);
 		childSetEnabled("delete_media", FALSE);
 		childSetEnabled("edit_media", FALSE);
 		childSetEnabled("media_info", FALSE);
 		media_info->setEnabled(FALSE);
-		media_info->clear();	
+		media_info->clear();*/	
 		clearMediaSettings();
 		return;
 	}
@@ -1081,6 +1083,7 @@ void LLFloaterTools::getMediaState()
 	LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue( &func, has_media );
 	bool bool_has_media = (has_media & LLTextureEntry::MF_HAS_MEDIA);
 
+	
 	const LLMediaEntry default_media_data;
 	
 	struct functor_getter_media_data : public LLSelectedTEGetFunctor< LLMediaEntry>
@@ -1108,6 +1111,7 @@ void LLFloaterTools::getMediaState()
 	// update UI depending on whether "object" (prim or face) has media
 	// and whether or not you are allowed to edit it.
 	
+	childSetEnabled("Add_Media",  editable);
 	// IF all the faces have media (or all dont have media)
 	if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
 	{
@@ -1120,7 +1124,7 @@ void LLFloaterTools::getMediaState()
 			if(media_data_get!=default_media_data)
 			{
 				//TODO: get media title
-				//media_title =  media_data_get->getTile();
+				//media_title =  media_data_get->getTitle();
 				//LLFloaterMediaSettings::getInstance()->mIdenticalValidMedia = true;
 				media_title = media_data_get.getHomeURL();
 			}
@@ -1155,7 +1159,7 @@ void LLFloaterTools::getMediaState()
 			if(media_data_get!=default_media_data)
 			{
 				//TODO: get media title
-				//media_title =  media_data_get->getTile();
+				//media_title =  media_data_get->getTitle();
 				media_title = media_data_get.getHomeURL();
 			}
 			
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index 1c3443ae809533dab69e185390e4148481727123..8d2d48f1af876bf5b4de26c5e7d36a23db3aaadb 100644
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -35,8 +35,6 @@
 #include "llfloatertos.h"
 
 // viewer includes
-#include "llappviewer.h"
-#include "llstartup.h"
 #include "llviewerstats.h"
 #include "llviewerwindow.h"
 
@@ -50,13 +48,15 @@
 #include "lluictrlfactory.h"
 #include "llvfile.h"
 #include "message.h"
+#include "llstartup.h"              // login_alert_done
 
 
-LLFloaterTOS::LLFloaterTOS(const LLSD& message)
-:	LLModalDialog( message ),
-	mMessage(message.asString()),
+LLFloaterTOS::LLFloaterTOS(const LLSD& data)
+:	LLModalDialog( data["message"].asString() ),
+	mMessage(data["message"].asString()),
 	mWebBrowserWindowId( 0 ),
-	mLoadCompleteCount( 0 )
+	mLoadCompleteCount( 0 ),
+	mReplyPumpName(data["reply_pump"].asString())
 {
 }
 
@@ -193,25 +193,12 @@ void LLFloaterTOS::onContinue( void* userdata )
 {
 	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
 	llinfos << "User agrees with TOS." << llendl;
-	if (self->getInstanceName() == "message_tos")
-	{
-		gAcceptTOS = TRUE;
-	}
-	else
-	{
-		gAcceptCriticalMessage = TRUE;
-	}
 
-	// Testing TOS dialog
-	#if ! LL_RELEASE_FOR_DOWNLOAD		
-	if ( LLStartUp::getStartupState() == STATE_LOGIN_WAIT )
+	if(self->mReplyPumpName != "")
 	{
-		LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+		LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(true));
 	}
-	else 
-	#endif
 
-	LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT );			// Go back and finish authentication
 	self->closeFloater(); // destroys this object
 }
 
@@ -221,7 +208,12 @@ void LLFloaterTOS::onCancel( void* userdata )
 	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
 	llinfos << "User disagrees with TOS." << llendl;
 	LLNotifications::instance().add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done);
-	LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+
+	if(self->mReplyPumpName != "")
+	{
+		LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(false));
+	}
+
 	self->mLoadCompleteCount = 0;  // reset counter for next time we come to TOS
 	self->closeFloater(); // destroys this object
 }
@@ -241,3 +233,4 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
 		}
 	}
 }
+
diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h
index 49f982aa80708001712a6293806dbd0a78eca3fb..1d573e817051b5bb5d977aea5b365063a2d3750c 100644
--- a/indra/newview/llfloatertos.h
+++ b/indra/newview/llfloatertos.h
@@ -36,6 +36,7 @@
 #include "llmodaldialog.h"
 #include "llassetstorage.h"
 #include "llmediactrl.h"
+#include <boost/function.hpp>
 
 class LLButton;
 class LLRadioGroup;
@@ -48,7 +49,7 @@ class LLFloaterTOS :
 	public LLViewerMediaObserver
 {
 public:
-	LLFloaterTOS(const LLSD& message);
+	LLFloaterTOS(const LLSD& data);
 	virtual ~LLFloaterTOS();
 
 	BOOL postBuild();
@@ -68,6 +69,7 @@ class LLFloaterTOS :
 	std::string		mMessage;
 	int				mWebBrowserWindowId;
 	int				mLoadCompleteCount;
+	std::string		mReplyPumpName;
 };
 
 #endif // LL_LLFLOATERTOS_H
diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index 3591daf92d379cbdaa736ef6e8c23bc565c9656c..f83a426cdab91b6802c7f2ebc58a09e8252c4215 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -71,6 +71,10 @@ LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style)
 	{
 		LLFontDescriptor labelfontdesc("SansSerif", "Small", style);
 		rtn = LLFontGL::getFont(labelfontdesc);
+		if (!rtn)
+		{
+			rtn = LLFontGL::getFontDefault();
+		}
 		sFonts[style] = rtn;
 	}
 	return rtn;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index c6b04cbcc8a882c335aab0207b1ccd4377e3b697..9486698c89a714b3dd42d1ae9562f0bd2dd6f32b 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -40,7 +40,7 @@
 #include "llerror.h"
 #include "llbutton.h"
 #include "llhttpclient.h"
-#include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "llstring.h"
 #include "lluictrlfactory.h"
 
diff --git a/indra/newview/llinspect.h b/indra/newview/llinspect.h
index 68accca3a322ec98cbc0c5f51e29e82d23bc0751..a461c2fa169826f25e9b984485d9b4378bfe0b6d 100644
--- a/indra/newview/llinspect.h
+++ b/indra/newview/llinspect.h
@@ -58,3 +58,4 @@ class LLInspect : public LLFloater
 };
 
 #endif
+
diff --git a/indra/newview/llinventoryactions.h b/indra/newview/llinventoryactions.h
new file mode 100644
index 0000000000000000000000000000000000000000..79247e3abb61864a128fcd749ed4171e1d0060a7
--- /dev/null
+++ b/indra/newview/llinventoryactions.h
@@ -0,0 +1,47 @@
+/** 
+ * @file llinventoryactions.h
+ * @brief inventory callback functions
+ * class definition
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYACTIONS_H
+#define LL_LLINVENTORYACTIONS_H
+
+#include "lluictrl.h"
+
+class LLPanelInventory;
+class LLInventoryView;
+class LLInventoryPanel;
+
+void init_object_inventory_panel_actions(LLPanelInventory *panel, LLUICtrl::CommitCallbackRegistry::Registrar& registrar);
+void init_inventory_actions(LLInventoryView *floater, LLUICtrl::CommitCallbackRegistry::Registrar& registrar);
+void init_inventory_panel_actions(LLInventoryPanel *panel, LLUICtrl::CommitCallbackRegistry::Registrar& registrar);
+
+#endif // LL_LLINVENTORYACTIONS_H
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index bc1a3cd0af3d65fe85f95bac617c3685e4960350..83f1013889289418d9c0fc09b7ec586d9da407eb 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -3878,7 +3878,10 @@ std::string LLObjectBridge::getLabelSuffix() const
 	{
 		std::string attachment_point_name = avatar->getAttachedPointName(mUUID);
 		LLStringUtil::toLower(attachment_point_name);
-		return LLItemBridge::getLabelSuffix() + std::string(" (worn on ") + attachment_point_name + std::string(")");
+		
+		LLStringUtil::format_map_t args;
+		args["[ATTACHMENT_POINT]"] =  attachment_point_name.c_str();
+		return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args);
 	}
 	else
 	{
@@ -4294,7 +4297,7 @@ std::string LLWearableBridge::getLabelSuffix() const
 {
 	if( gAgentWearables.isWearingItem( mUUID ) )
 	{
-		return LLItemBridge::getLabelSuffix() + " (worn)";
+		return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn");
 	}
 	else
 	{
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 6009e8e61000339b387fd5b912d08b4a56e5f350..d5a527773cc04567c2b34fd7986025a96486b21e 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -2010,63 +2010,56 @@ bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const
 }
 
 bool LLInventoryModel::loadSkeleton(
-	const LLInventoryModel::options_t& options,
+	const LLSD& options,
 	const LLUUID& owner_id)
 {
 	lldebugs << "importing inventory skeleton for " << owner_id << llendl;
 
 	typedef std::set<LLPointer<LLViewerInventoryCategory>, InventoryIDPtrLess> cat_set_t;
 	cat_set_t temp_cats;
-
-	update_map_t child_counts;
-
-	LLUUID id;
-	LLAssetType::EType preferred_type;
 	bool rv = true;
-	for(options_t::const_iterator it = options.begin(); it < options.end(); ++it)
-	{
-		LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id);
-		response_t::const_iterator no_response = (*it).end();
-		response_t::const_iterator skel;
-		skel = (*it).find("name");
-		if(skel == no_response) goto clean_cat;
-		cat->rename(std::string((*skel).second));
-		skel = (*it).find("folder_id");
-		if(skel == no_response) goto clean_cat;
-		id.set((*skel).second);
-		// if an id is null, it locks the viewer.
-		if(id.isNull()) goto clean_cat;
-		cat->setUUID(id);
-		skel = (*it).find("parent_id");
-		if(skel == no_response) goto clean_cat;
-		id.set((*skel).second);
-		cat->setParent(id);
-		skel = (*it).find("type_default");
-		if(skel == no_response)
-		{
-			preferred_type = LLAssetType::AT_NONE;
+
+	for(LLSD::array_const_iterator it = options.beginArray(),
+		end = options.endArray(); it != end; ++it)
+	{
+		LLSD name = (*it)["name"];
+		LLSD folder_id = (*it)["folder_id"];
+		LLSD parent_id = (*it)["parent_id"];
+		LLSD version = (*it)["version"];
+		if(name.isDefined()
+			&& folder_id.isDefined()
+			&& parent_id.isDefined()
+			&& version.isDefined()
+			&& folder_id.asUUID().notNull() // if an id is null, it locks the viewer.
+			) 		
+		{
+			LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id);
+			cat->rename(name.asString());
+			cat->setUUID(folder_id.asUUID());
+			cat->setParent(parent_id.asUUID());
+
+			LLAssetType::EType preferred_type = LLAssetType::AT_NONE;
+			LLSD type_default = (*it)["type_default"];
+			if(type_default.isDefined())
+            {
+				preferred_type = (LLAssetType::EType)type_default.asInteger();
+            }
+            cat->setPreferredType(preferred_type);
+			cat->setVersion(version.asInteger());
+            temp_cats.insert(cat);
 		}
 		else
 		{
-			S32 t = atoi((*skel).second.c_str());
-			preferred_type = (LLAssetType::EType)t;
+			llwarns << "Unable to import near " << name.asString() << llendl;
+            rv = false;
 		}
-		cat->setPreferredType(preferred_type);
-		skel = (*it).find("version");
-		if(skel == no_response) goto clean_cat;
-		cat->setVersion(atoi((*skel).second.c_str()));
-		temp_cats.insert(cat);
-		continue;
-	clean_cat:
-		llwarns << "Unable to import near " << cat->getName() << llendl;
-		rv = false;
-		//delete cat; // automatic when cat is reasigned or destroyed
 	}
 
 	S32 cached_category_count = 0;
 	S32 cached_item_count = 0;
 	if(!temp_cats.empty())
 	{
+		update_map_t child_counts;
 		cat_array_t categories;
 		item_array_t items;
 		cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded.
@@ -2241,85 +2234,84 @@ bool LLInventoryModel::loadSkeleton(
 	return rv;
 }
 
-bool LLInventoryModel::loadMeat(
-	const LLInventoryModel::options_t& options, const LLUUID& owner_id)
+bool LLInventoryModel::loadMeat(const LLSD& options, const LLUUID& owner_id)
 {
 	llinfos << "importing inventory for " << owner_id << llendl;
-	LLPermissions default_perm;
-	default_perm.init(LLUUID::null, owner_id, LLUUID::null, LLUUID::null);
-	LLPointer<LLViewerInventoryItem> item;
-	LLUUID id;
-	LLAssetType::EType type;
-	LLInventoryType::EType inv_type;
 	bool rv = true;
-	for(options_t::const_iterator it = options.begin(); it < options.end(); ++it)
-	{
-		item = new LLViewerInventoryItem;
-		response_t::const_iterator no_response = (*it).end();
-		response_t::const_iterator meat;
-		meat = (*it).find("name");
-		if(meat == no_response) goto clean_item;
-		item->rename(std::string((*meat).second));
-		meat = (*it).find("item_id");
-		if(meat == no_response) goto clean_item;
-		id.set((*meat).second);
-		item->setUUID(id);
-		meat = (*it).find("parent_id");
-		if(meat == no_response) goto clean_item;
-		id.set((*meat).second);
-		item->setParent(id);
-		meat = (*it).find("type");
-		if(meat == no_response) goto clean_item;
-		type = (LLAssetType::EType)atoi((*meat).second.c_str());
-		item->setType(type);
-		meat = (*it).find("inv_type");
-		if(meat != no_response)
-		{
-			inv_type = (LLInventoryType::EType)atoi((*meat).second.c_str());
-			item->setInventoryType(inv_type);
-		}
-		meat = (*it).find("data_id");
-		if(meat == no_response) goto clean_item;
-		id.set((*meat).second);
-		if(LLAssetType::AT_CALLINGCARD == type)
-		{
-			LLPermissions perm;
-			perm.init(id, owner_id, LLUUID::null, LLUUID::null);
-			item->setPermissions(perm);
+	for(LLSD::array_const_iterator it = options.beginArray(),
+		end = options.endArray(); it != end; ++it)
+	{
+		LLSD name = (*it)["name"];
+		LLSD item_id = (*it)["item_id"];
+		LLSD parent_id = (*it)["parent_id"];
+		LLSD asset_type = (*it)["type"];
+		LLSD data_id = (*it)["data_id"];
+		if(name.isDefined() 
+			&& item_id.isDefined()
+			&& parent_id.isDefined()
+			&& asset_type.isDefined()
+			&& data_id.isDefined())
+		{
+			LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem;
+			item->rename(name.asString());
+			item->setUUID(item_id.asUUID());
+			item->setParent(parent_id.asUUID());
+			LLAssetType::EType type = (LLAssetType::EType)asset_type.asInteger();
+            item->setType(type);
+
+			LLSD llsd_inv_type = (*it)["inv_type"];
+			if(llsd_inv_type.isDefined())
+            {
+				LLInventoryType::EType inv_type = (LLInventoryType::EType)llsd_inv_type.asInteger();
+                item->setInventoryType(inv_type);
+            }
+
+            if(LLAssetType::AT_CALLINGCARD == type)
+            {
+                LLPermissions perm;
+				perm.init(data_id.asUUID(), owner_id, LLUUID::null, LLUUID::null);
+                item->setPermissions(perm);
+            }
+            else
+            {
+				LLPermissions default_perm;
+				default_perm.init(LLUUID::null, owner_id, LLUUID::null, LLUUID::null);
+				LLSD llsd_perm_mask = (*it)["perm_mask"];
+				if(llsd_perm_mask.isDefined())
+                {
+					PermissionMask perm_mask = llsd_perm_mask.asInteger();
+					default_perm.initMasks(
+						perm_mask, perm_mask, perm_mask, perm_mask, perm_mask);
+				}
+				else
+				{
+					default_perm.initMasks(
+						PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
+				}
+				item->setPermissions(default_perm);
+				item->setAssetUUID(data_id.asUUID());
+            }
+
+			LLSD flags = (*it)["flags"];
+			if(flags.isDefined())
+            {
+				// Not sure how well LLSD.asInteger() maps to 
+				// unsigned long - using strtoul()
+				item->setFlags(strtoul(flags.asString().c_str(), NULL, 0));
+            }
+
+			LLSD time = (*it)["time"];
+			if(time.isDefined())
+            {
+				item->setCreationDate(time.asInteger());
+            }
+            addItem(item);
 		}
 		else
 		{
-			meat = (*it).find("perm_mask");
-			if(meat != no_response)
-			{
-				PermissionMask perm_mask = atoi((*meat).second.c_str());
-				default_perm.initMasks(
-					perm_mask, perm_mask, perm_mask, perm_mask, perm_mask);
-			}
-			else
-			{
-				default_perm.initMasks(
-					PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
-			}
-			item->setPermissions(default_perm);
-			item->setAssetUUID(id);
-		}
-		meat = (*it).find("flags");
-		if(meat != no_response)
-		{
-			item->setFlags(strtoul((*meat).second.c_str(), NULL, 0));
-		}
-		meat = (*it).find("time");
-		if(meat != no_response)
-		{
-			item->setCreationDate(atoi((*meat).second.c_str()));
+			llwarns << "Unable to import near " << name.asString() << llendl;
+            rv = false;
 		}
-		addItem(item);
-		continue;
-	clean_item:
-		llwarns << "Unable to import near " << item->getName() << llendl;
-		rv = false;
-		//delete item; // automatic when item is reassigned or destroyed
 	}
 	return rv;
 }
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index c2d8717b709f4e310566e0b212a17172236ab5f7..7d4f3372e979e5ea8b4998f736a197d05aa0ce45 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -332,10 +332,8 @@ class LLInventoryModel
 
 	// methods to load up inventory skeleton & meat. These are used
 	// during authentication. return true if everything parsed.
-	typedef std::map<std::string, std::string> response_t;
-	typedef std::vector<response_t> options_t;
-	bool loadSkeleton(const options_t& options, const LLUUID& owner_id);
-	bool loadMeat(const options_t& options, const LLUUID& owner_id);
+	bool loadSkeleton(const LLSD& options, const LLUUID& owner_id);
+	bool loadMeat(const LLSD& options, const LLUUID& owner_id);
 
 	// This is a brute force method to rebuild the entire parent-child
 	// relations.
diff --git a/indra/newview/lllocaltextureobject.cpp b/indra/newview/lllocaltextureobject.cpp
index 0bd3e425567b005c7cb036676f1a4d9396d894c7..6bcbe6f58ca1304797dcb7e2c3cbe010e2926633 100644
--- a/indra/newview/lllocaltextureobject.cpp
+++ b/indra/newview/lllocaltextureobject.cpp
@@ -47,7 +47,7 @@ LLLocalTextureObject::LLLocalTextureObject() :
 	mImage = NULL;
 }
 
-LLLocalTextureObject::LLLocalTextureObject(LLViewerFetchedTexture* image, LLUUID& id)
+LLLocalTextureObject::LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id)
 {
 	mImage = image;
 	gGL.getTexUnit(0)->bind(mImage);
diff --git a/indra/newview/lllocaltextureobject.h b/indra/newview/lllocaltextureobject.h
index 461756ee461f0a8fe8a344574ea68c93ce5fae23..c8b8aa924be730320fd1376d7c619c2a8c3ab945 100644
--- a/indra/newview/lllocaltextureobject.h
+++ b/indra/newview/lllocaltextureobject.h
@@ -35,7 +35,8 @@
 
 #include <boost/shared_ptr.hpp>
 
-class LLViewerFetchedTexture;
+#include "llviewertexture.h"
+
 class LLUUID;
 class LLTexLayer;
 class LLTextureEntry;
@@ -49,7 +50,7 @@ class LLLocalTextureObject
 {
 public:
 	LLLocalTextureObject();
-	LLLocalTextureObject(LLViewerFetchedTexture* image, LLUUID& id);
+	LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id);
 	LLLocalTextureObject(const LLLocalTextureObject& lto);
 	~LLLocalTextureObject();
 
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5f347ddc404696933b6ccc7e78840d67268670d
--- /dev/null
+++ b/indra/newview/lllogininstance.cpp
@@ -0,0 +1,475 @@
+/** 
+ * @file lllogininstance.cpp
+ * @brief Viewer's host for a login connection.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lllogininstance.h"
+
+// llcommon
+#include "llevents.h"
+#include "llmd5.h"
+#include "stringize.h"
+
+// llmessage (!)
+#include "llfiltersd2xmlrpc.h" // for xml_escape_string()
+
+// login
+#include "lllogin.h"
+
+// newview
+#include "llviewernetwork.h"
+#include "llviewercontrol.h"
+#include "llurlsimstring.h"
+#include "llfloaterreg.h"
+#include "llnotifications.h"
+#include "llwindow.h"
+#if LL_LINUX || LL_SOLARIS
+#include "lltrans.h"
+#endif
+
+static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
+static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
+
+std::string construct_start_string();
+
+LLLoginInstance::LLLoginInstance() :
+	mLoginModule(new LLLogin()),
+	mNotifications(NULL),
+	mLoginState("offline"),
+	mUserInteraction(true),
+	mSkipOptionalUpdate(false),
+	mAttemptComplete(false),
+	mTransferRate(0.0f),
+	mDispatcher("LLLoginInstance", "change")
+{
+	mLoginModule->getEventPump().listen("lllogininstance", 
+		boost::bind(&LLLoginInstance::handleLoginEvent, this, _1));
+	mDispatcher.add("fail.login", boost::bind(&LLLoginInstance::handleLoginFailure, this, _1));
+	mDispatcher.add("connect",    boost::bind(&LLLoginInstance::handleLoginSuccess, this, _1));
+	mDispatcher.add("disconnect", boost::bind(&LLLoginInstance::handleDisconnect, this, _1));
+}
+
+LLLoginInstance::~LLLoginInstance()
+{
+}
+
+void LLLoginInstance::connect(const LLSD& credentials)
+{
+	std::vector<std::string> uris;
+	LLViewerLogin::getInstance()->getLoginURIs(uris);
+	connect(uris.front(), credentials);
+}
+
+void LLLoginInstance::connect(const std::string& uri, const LLSD& credentials)
+{
+	mAttemptComplete = false; // Reset attempt complete at this point!
+	constructAuthParams(credentials);
+	mLoginModule->connect(uri, mRequestData);
+}
+
+void LLLoginInstance::reconnect()
+{
+	// Sort of like connect, only using the pre-existing
+	// request params.
+	std::vector<std::string> uris;
+	LLViewerLogin::getInstance()->getLoginURIs(uris);
+	mLoginModule->connect(uris.front(), mRequestData);
+}
+
+void LLLoginInstance::disconnect()
+{
+	mAttemptComplete = false; // Reset attempt complete at this point!
+	mRequestData.clear();
+	mLoginModule->disconnect();
+}
+
+LLSD LLLoginInstance::getResponse() 
+{
+	return mResponseData; 
+}
+
+void LLLoginInstance::constructAuthParams(const LLSD& credentials)
+{
+	// Set up auth request options.
+//#define LL_MINIMIAL_REQUESTED_OPTIONS
+	LLSD requested_options;
+	// *Note: this is where gUserAuth used to be created.
+	requested_options.append("inventory-root");
+	requested_options.append("inventory-skeleton");
+	//requested_options.append("inventory-meat");
+	//requested_options.append("inventory-skel-targets");
+#if (!defined LL_MINIMIAL_REQUESTED_OPTIONS)
+	if(FALSE == gSavedSettings.getBOOL("NoInventoryLibrary"))
+	{
+		requested_options.append("inventory-lib-root");
+		requested_options.append("inventory-lib-owner");
+		requested_options.append("inventory-skel-lib");
+	//	requested_options.append("inventory-meat-lib");
+	}
+
+	requested_options.append("initial-outfit");
+	requested_options.append("gestures");
+	requested_options.append("event_categories");
+	requested_options.append("event_notifications");
+	requested_options.append("classified_categories");
+	requested_options.append("adult_compliant"); 
+	//requested_options.append("inventory-targets");
+	requested_options.append("buddy-list");
+	requested_options.append("ui-config");
+#endif
+	requested_options.append("tutorial_setting");
+	requested_options.append("login-flags");
+	requested_options.append("global-textures");
+	if(gSavedSettings.getBOOL("ConnectAsGod"))
+	{
+		gSavedSettings.setBOOL("UseDebugMenus", TRUE);
+		requested_options.append("god-connect");
+	}
+
+	char hashed_mac_string[MD5HEX_STR_SIZE];		/* Flawfinder: ignore */
+	LLMD5 hashed_mac;
+	hashed_mac.update( gMACAddress, MAC_ADDRESS_BYTES );
+	hashed_mac.finalize();
+	hashed_mac.hex_digest(hashed_mac_string);
+
+	// prepend "$1$" to the password to indicate its the md5'd version.
+	std::string dpasswd("$1$");
+	dpasswd.append(credentials["passwd"].asString());
+
+	// (re)initialize the request params with creds.
+	LLSD request_params(credentials);
+	request_params["passwd"] = dpasswd;
+	request_params["start"] = construct_start_string();
+	request_params["skipoptional"] = mSkipOptionalUpdate;
+	request_params["agree_to_tos"] = false; // Always false here. Set true in 
+	request_params["read_critical"] = false; // handleTOSResponse
+	request_params["last_exec_event"] = mLastExecEvent;
+	request_params["mac"] = hashed_mac_string;
+	request_params["version"] = gCurrentVersion; // Includes channel name
+	request_params["channel"] = gSavedSettings.getString("VersionChannelName");
+	request_params["id0"] = mSerialNumber;
+
+	mRequestData.clear();
+	mRequestData["method"] = "login_to_simulator";
+	mRequestData["params"] = request_params;
+	mRequestData["options"] = requested_options;
+}
+
+bool LLLoginInstance::handleLoginEvent(const LLSD& event)
+{
+	std::cout << "LoginListener called!: \n";
+	std::cout << event << "\n";
+
+	if(!(event.has("state") && event.has("change") && event.has("progress")))
+	{
+		llerrs << "Unknown message from LLLogin: " << event << llendl;
+	}
+
+	mLoginState = event["state"].asString();
+	mResponseData = event["data"];
+	
+	if(event.has("transfer_rate"))
+	{
+		mTransferRate = event["transfer_rate"].asReal();
+	}
+
+	// Call the method registered in constructor, if any, for more specific
+	// handling
+	LLEventDispatcher::Callable method(mDispatcher.get(event["change"]));
+	if (! method.empty())
+	{
+		method(event);
+	}
+	return false;
+}
+
+void LLLoginInstance::handleLoginFailure(const LLSD& event)
+{
+	// Login has failed. 
+	// Figure out why and respond...
+	LLSD response = event["data"];
+	std::string reason_response = response["reason"].asString();
+	std::string message_response = response["message"].asString();
+	if(mUserInteraction)
+	{
+		// For the cases of critical message or TOS agreement,
+		// start the TOS dialog. The dialog response will be handled
+		// by the LLLoginInstance::handleTOSResponse() callback.
+		// The callback intiates the login attempt next step, either 
+		// to reconnect or to end the attempt in failure.
+		if(reason_response == "tos")
+		{
+			LLSD data(LLSD::emptyMap());
+			data["message"] = message_response;
+			data["reply_pump"] = TOS_REPLY_PUMP;
+			LLFloaterReg::showInstance("message_tos", data);
+			LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
+				.listen(TOS_LISTENER_NAME,
+						boost::bind(&LLLoginInstance::handleTOSResponse, 
+									this, _1, "agree_to_tos"));
+		}
+		else if(reason_response == "critical")
+		{
+			LLSD data(LLSD::emptyMap());
+			data["message"] = message_response;
+			data["reply_pump"] = TOS_REPLY_PUMP;
+			LLFloaterReg::showInstance("message_critical", data);
+			LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
+				.listen(TOS_LISTENER_NAME,
+						boost::bind(&LLLoginInstance::handleTOSResponse, 
+									this, _1, "read_critical"));
+		}
+		else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate"))
+		{
+			gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
+			updateApp(true, message_response);
+		}
+		else if(reason_response == "optional")
+		{
+			updateApp(false, message_response);
+		}
+		else
+		{	
+			attemptComplete();
+		}	
+	}
+	else // no user interaction
+	{
+		attemptComplete();
+	}
+}
+
+void LLLoginInstance::handleLoginSuccess(const LLSD& event)
+{
+	if(gSavedSettings.getBOOL("ForceMandatoryUpdate"))
+	{
+		LLSD response = event["data"];
+		std::string message_response = response["message"].asString();
+
+		// Testing update...
+		gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
+
+		// Don't confuse startup by leaving login "online".
+		mLoginModule->disconnect(); 
+		updateApp(true, message_response);
+	}
+	else
+	{
+		attemptComplete();
+	}
+}
+
+void LLLoginInstance::handleDisconnect(const LLSD& event)
+{
+    // placeholder
+}
+
+bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
+{
+	if(accepted)
+	{	
+		// Set the request data to true and retry login.
+		mRequestData["params"][key] = true; 
+		reconnect();
+	}
+	else
+	{
+		attemptComplete();
+	}
+
+	LLEventPumps::instance().obtain(TOS_REPLY_PUMP).stopListening(TOS_LISTENER_NAME);
+	return true;
+}
+
+
+void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)
+{
+	// store off config state, as we might quit soon
+	gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);	
+	LLUIColorTable::instance().saveUserSettings();
+
+	std::ostringstream message;
+	std::string msg;
+	if (!auth_msg.empty())
+	{
+		msg = "(" + auth_msg + ") \n";
+	}
+
+	LLSD args;
+	args["MESSAGE"] = msg;
+	
+	LLSD payload;
+	payload["mandatory"] = mandatory;
+
+/*
+ We're constructing one of the following 6 strings here:
+	 "DownloadWindowsMandatory"
+	 "DownloadWindowsReleaseForDownload"
+	 "DownloadWindows"
+	 "DownloadMacMandatory"
+	 "DownloadMacReleaseForDownload"
+	 "DownloadMac"
+ 
+ I've called them out explicitly in this comment so that they can be grepped for.
+ 
+ Also, we assume that if we're not Windows we're Mac. If we ever intend to support 
+ Linux with autoupdate, this should be an explicit #elif LL_DARWIN, but 
+ we'd rather deliver the wrong message than no message, so until Linux is supported
+ we'll leave it alone.
+ */
+	std::string notification_name = "Download";
+	
+#if LL_WINDOWS
+	notification_name += "Windows";
+#elif LL_DARWIN
+	notification_name += "Mac";
+#else
+	notification_name += "Linux";
+#endif
+	
+	if (mandatory)
+	{
+		notification_name += "Mandatory";
+	}
+	else
+	{
+#if LL_RELEASE_FOR_DOWNLOAD
+		notification_name += "ReleaseForDownload";
+#endif
+	}
+
+	if(mNotifications)
+	{
+		mNotifications->add(notification_name, args, payload, 
+			boost::bind(&LLLoginInstance::updateDialogCallback, this, _1, _2));
+	}
+
+	/* *NOTE:Mani Experiment with Event API interface.
+	if(!mUpdateAppResponse)
+	{
+		bool make_unique = true;
+		mUpdateAppResponse.reset(new LLEventStream("logininstance_updateapp", make_unique));
+		mUpdateAppResponse->listen("diaupdateDialogCallback", 
+								   boost::bind(&LLLoginInstance::updateDialogCallback,
+								 			   this, _1
+											   )
+								   );
+	}
+
+	LLSD event;
+	event["op"] = "requestAdd";
+	event["name"] = notification_name;
+	event["substitutions"] = args;
+	event["payload"] = payload;
+	event["reply"] = mUpdateAppResponse->getName();
+
+	LLEventPumps::getInstance()->obtain("LLNotifications").post(event);
+	*/
+}
+
+bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD& response)
+{
+	S32 option = LLNotification::getSelectedOption(notification, response);
+	std::string update_exe_path;
+	bool mandatory = notification["payload"]["mandatory"].asBoolean();
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+	if (option == 2)
+	{
+		// This condition attempts to skip the 
+		// update if using a dev build.
+		// The relog probably won't work if the 
+		// update is mandatory. :)
+
+	    // *REMOVE:Mani - Saving for reference...
+		//LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); 
+		mSkipOptionalUpdate = true;
+		reconnect();
+		return false;
+	}
+#endif
+
+	if (option == 1)
+	{
+		// ...user doesn't want to do it
+		if (mandatory)
+		{
+			// Mandatory update, user chose to not to update...
+			// The login attemp is complete, startup should 
+			// quit when detecting this.
+			attemptComplete();
+
+			// *REMOVE:Mani - Saving for reference...
+			//LLAppViewer::instance()->forceQuit();
+			// // Bump them back to the login screen.
+			// //reset_login();
+		}
+		else
+		{
+			// Optional update, user chose to skip
+			mSkipOptionalUpdate = true;
+			reconnect();
+		}
+		return false;
+	}
+	
+ 	if(mUpdaterLauncher)
+  	{
+ 		mUpdaterLauncher();
+  	}
+  
+ 	attemptComplete();
+
+	return false;
+}
+
+std::string construct_start_string()
+{
+	std::string start;
+	if (LLURLSimString::parse())
+	{
+		// a startup URL was specified
+		std::string unescaped_start = 
+			STRINGIZE(  "uri:" 
+						<< LLURLSimString::sInstance.mSimName << "&" 
+						<< LLURLSimString::sInstance.mX << "&" 
+						<< LLURLSimString::sInstance.mY << "&" 
+						<< LLURLSimString::sInstance.mZ);
+		start = xml_escape_string(unescaped_start);
+	}
+	else
+	{
+		start = gSavedSettings.getString("LoginLocation");
+	}
+	return start;
+}
+
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
new file mode 100644
index 0000000000000000000000000000000000000000..19d7449bc15bfc7eef3af996c3e7667e014ecbde
--- /dev/null
+++ b/indra/newview/lllogininstance.h
@@ -0,0 +1,114 @@
+/** 
+ * @file lllogininstance.h
+ * @brief A host for the viewer's login connection.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLOGININSTANCE_H
+#define LL_LLLOGININSTANCE_H
+
+#include "lleventdispatcher.h"
+#include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
+class LLLogin;
+class LLEventStream;
+class LLNotificationsInterface;
+
+// This class hosts the login module and is used to 
+// negotiate user authentication attempts.
+class LLLoginInstance : public LLSingleton<LLLoginInstance>
+{
+public:
+	LLLoginInstance();
+	~LLLoginInstance();
+
+	void connect(const LLSD& credential); // Connect to the current grid choice.
+	void connect(const std::string& uri, const LLSD& credential);	// Connect to the given uri.
+	void reconnect(); // reconnect using the current credentials.
+	void disconnect();
+
+	bool authFailure() { return mAttemptComplete && mLoginState == "offline"; }
+	bool authSuccess() { return mAttemptComplete && mLoginState == "online"; }
+
+	const std::string& getLoginState() { return mLoginState; }
+	LLSD getResponse(const std::string& key) { return getResponse()[key]; }
+	LLSD getResponse();
+
+	// Only valid when authSuccess == true.
+	const F64 getLastTransferRateBPS() { return mTransferRate; }
+
+		// Set whether this class will drive user interaction.
+	// If not, login failures like 'need tos agreement' will 
+	// end the login attempt.
+	void setUserInteraction(bool state) { mUserInteraction = state; } 
+	bool getUserInteraction() { return mUserInteraction; }
+
+	// Whether to tell login to skip optional update request.
+	// False by default.
+	void setSkipOptionalUpdate(bool state) { mSkipOptionalUpdate = state; }
+	void setSerialNumber(const std::string& sn) { mSerialNumber = sn; }
+	void setLastExecEvent(int lee) { mLastExecEvent = lee; }
+
+	void setNotificationsInterface(LLNotificationsInterface* ni) { mNotifications = ni; }
+
+	typedef boost::function<void()> UpdaterLauncherCallback;
+	void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }
+
+private:
+	void constructAuthParams(const LLSD& credentials); 
+	void updateApp(bool mandatory, const std::string& message);
+	bool updateDialogCallback(const LLSD& notification, const LLSD& response);
+
+	bool handleLoginEvent(const LLSD& event);
+	void handleLoginFailure(const LLSD& event);
+	void handleLoginSuccess(const LLSD& event);
+	void handleDisconnect(const LLSD& event);
+
+	bool handleTOSResponse(bool v, const std::string& key);
+
+	void attemptComplete() { mAttemptComplete = true; } // In the future an event?
+
+	boost::scoped_ptr<LLLogin> mLoginModule;
+	LLNotificationsInterface* mNotifications;
+
+	std::string mLoginState;
+	LLSD mRequestData;
+	LLSD mResponseData;
+	bool mUserInteraction; 
+	bool mSkipOptionalUpdate;
+	bool mAttemptComplete;
+	F64 mTransferRate;
+	std::string mSerialNumber;
+	int mLastExecEvent;
+	UpdaterLauncherCallback mUpdaterLauncher;
+	boost::scoped_ptr<LLEventStream> mUpdateAppResponse;
+	LLEventDispatcher mDispatcher;
+};
+
+#endif
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 4fa7f62c68070f9020414da96d24b905179b0621..15efd0100a853c27beec2c64789bcebea8d18cb0 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -321,36 +321,9 @@ BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
 {
 	BOOL result = FALSE;
 	
-	// FIXME: THIS IS SO WRONG.
-	// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
-	
 	if (mMediaSource)
 	{
-		if( MASK_CONTROL & mask )
-		{
-			if( 'C' == key )
-			{
-				mMediaSource->copy();
-				result = TRUE;
-			}
-			else
-			if( 'V' == key )
-			{
-				mMediaSource->paste();
-				result = TRUE;
-			}
-			else
-			if( 'X' == key )
-			{
-				mMediaSource->cut();
-				result = TRUE;
-			}
-		}
-		
-		if(!result)
-		{
-			result = mMediaSource->handleKeyHere(key, mask);
-		}
+		result = mMediaSource->handleKeyHere(key, mask);
 	}
 		
 	return result;
@@ -373,12 +346,9 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
 {
 	BOOL result = FALSE;
 	
-	// only accept 'printable' characters, sigh...
-	if (uni_char >= 32 // discard 'control' characters
-	    && uni_char != 127) // SDL thinks this is 'delete' - yuck.
+	if (mMediaSource)
 	{
-		if (mMediaSource)
-			result = mMediaSource->handleUnicodeCharHere(uni_char);
+		result = mMediaSource->handleUnicodeCharHere(uni_char);
 	}
 
 	return result;
@@ -905,6 +875,18 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL;
 		};
 		break;
+
+		case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL;
+		};
+		break;
+		
+		case MEDIA_EVENT_NAME_CHANGED:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAME_CHANGED" << LL_ENDL;
+		};
+		break;
 	};
 
 	// chain all events to any potential observers of this object.
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index 6a932d76bfd3645b88dfa6cfe1482a0cea7ac9c8..6ae42d23d32a002e72fff41b88510f1ce490f714 100755
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -34,15 +34,18 @@
 
 #include "llmediadataclient.h"
 
+#if LL_MSVC
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
 #include <boost/lexical_cast.hpp>
 
 #include "llhttpstatuscodes.h"
-#include "llnotifications.h"
 #include "llsdutil.h"
 #include "llmediaentry.h"
 #include "lltextureentry.h"
 #include "llviewerregion.h"
-#include "llvovolume.h"
 
 //
 // When making a request
@@ -55,7 +58,9 @@
 // - Any request that gets a 503 still goes through the retry logic
 //
 
-// Some helpful logging macros
+const F32 LLMediaDataClient::QUEUE_TIMER_DELAY = 1.0; // seconds(s)
+const F32 LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY = 5.0; // secs
+const U32 LLMediaDataClient::MAX_RETRIES = 4;
 
 //////////////////////////////////////////////////////////////////////////////////////
 //
@@ -66,7 +71,7 @@
 
 LLMediaDataClient::Request::Request(const std::string &cap_name, 
 									const LLSD& sd_payload,
-									LLVOVolume *obj, 
+									LLMediaDataClientObject *obj, 
 									LLMediaDataClient *mdc)
 	: mCapName(cap_name), 
 	  mPayload(sd_payload), 
@@ -79,38 +84,39 @@ LLMediaDataClient::Request::Request(const std::string &cap_name,
 
 LLMediaDataClient::Request::~Request()
 {
+	LL_DEBUGS("LLMediaDataClient") << "~Request" << (*this) << LL_ENDL;
 	mMDC = NULL;
-    mObject = NULL;
+	mObject = NULL;
 }
 
 													  
 std::string LLMediaDataClient::Request::getCapability() const
 {
-	return getObject()->getRegion()->getCapability(getCapName());
+	return getObject()->getCapabilityUrl(getCapName());
 }
 
 // Helper function to get the "type" of request, which just pokes around to
 // discover it.
 LLMediaDataClient::Request::Type LLMediaDataClient::Request::getType() const
 {
-    if (mCapName == "ObjectMediaNavigate")
-    {
-        return NAVIGATE;
-    }
-    else if (mCapName == "ObjectMedia")
-    {
-        const std::string &verb = mPayload["verb"];
-        if (verb == "GET")
-        {
-            return GET;
-        }
-        else if (verb == "UPDATE")
-        {
-            return UPDATE;
-        }
-    }
-    llassert(false);
-    return GET;
+	if (mCapName == "ObjectMediaNavigate")
+	{
+		return NAVIGATE;
+	}
+	else if (mCapName == "ObjectMedia")
+	{
+		const std::string &verb = mPayload["verb"];
+		if (verb == "GET")
+		{
+			return GET;
+		}
+		else if (verb == "UPDATE")
+		{
+			return UPDATE;
+		}
+	}
+	llassert(false);
+	return GET;
 }
 
 const char *LLMediaDataClient::Request::getTypeAsString() const
@@ -138,6 +144,17 @@ void LLMediaDataClient::Request::reEnqueue() const
 	mMDC->enqueue(this);
 }
 
+F32 LLMediaDataClient::Request::getRetryTimerDelay() const
+{
+	return (mMDC == NULL) ? LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY :
+		mMDC->mRetryTimerDelay; 
+}
+
+U32 LLMediaDataClient::Request::getMaxNumRetries() const
+{
+	return (mMDC == NULL) ? LLMediaDataClient::MAX_RETRIES : mMDC->mMaxNumRetries;
+}
+
 std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)
 {
 	s << "<request>" 
@@ -164,15 +181,21 @@ LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
 // virtual 
 LLMediaDataClient::Responder::RetryTimer::~RetryTimer() 
 {
+	LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL;
+
+	// XXX This is weird: Instead of doing the work in tick()  (which re-schedules
+	// a timer, which might be risky), do it here, in the destructor.  Yes, it is very odd.
+	// Instead of retrying, we just put the request back onto the queue
+	LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << "retrying" << LL_ENDL;
+	mResponder->getRequest()->reEnqueue();
+
+	// Release the ref to the responder.
 	mResponder = NULL;
 }
 
 // virtual
 BOOL LLMediaDataClient::Responder::RetryTimer::tick()
 {
-	// Instead of retrying, we just put the request back onto the queue
-	LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << "retrying" << LL_ENDL;
-	mResponder->getRequest()->reEnqueue();
 	// Don't fire again
 	return TRUE;
 }
@@ -191,35 +214,35 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
 
 LLMediaDataClient::Responder::~Responder()
 {
-    mRequest = NULL;
+	LL_DEBUGS("LLMediaDataClient") << "~Responder" << *(getRequest()) << LL_ENDL;
+	mRequest = NULL;
 }
 
 /*virtual*/
 void LLMediaDataClient::Responder::error(U32 status, const std::string& reason)
 {
-	extern LLControlGroup gSavedSettings;
-
 	if (status == HTTP_SERVICE_UNAVAILABLE)
 	{
-		F32 retry_timeout = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
-		if (retry_timeout <= 0.0)
-		{
-			retry_timeout = (F32)UNAVAILABLE_RETRY_TIMER_DELAY;
-		}
-		LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
+		F32 retry_timeout = mRequest->getRetryTimerDelay();
 
 		mRequest->incRetryCount();
 		
-		// Start timer (instances are automagically tracked by
-		// InstanceTracker<> and LLEventTimer)
-		new RetryTimer(F32(retry_timeout/*secs*/), this);
+		if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) 
+		{
+			LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
+
+			// Start timer (instances are automagically tracked by
+			// InstanceTracker<> and LLEventTimer)
+			new RetryTimer(F32(retry_timeout/*secs*/), this);
+		}
+		else {
+			LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retry count " << 
+				mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
+		}
 	}
 	else {
 		std::string msg = boost::lexical_cast<std::string>(status) + ": " + reason;
-		LL_INFOS("LLMediaDataClient") << *mRequest << " error(" << msg << ")" << LL_ENDL;
-		LLSD args;
-		args["ERROR"] = msg;
-		LLNotifications::instance().add("ObjectMediaFailure", args);
+		LL_WARNS("LLMediaDataClient") << *mRequest << " http error(" << msg << ")" << LL_ENDL;
 	}
 }
 
@@ -227,7 +250,7 @@ void LLMediaDataClient::Responder::error(U32 status, const std::string& reason)
 /*virtual*/
 void LLMediaDataClient::Responder::result(const LLSD& content)
 {
-	LL_INFOS("LLMediaDataClient") << *mRequest << "result : " << ll_pretty_print_sd(content) << LL_ENDL;
+	LL_INFOS("LLMediaDataClient") << *mRequest << "result : " << ll_print_sd(content) << LL_ENDL;
 }
 
 
@@ -256,29 +279,25 @@ bool LLMediaDataClient::Comparator::operator() (const request_ptr_t &o1, const r
 	// Calculate the scores for each.  
 	F64 o1_score = Comparator::getObjectScore(o1->getObject());
 	F64 o2_score = Comparator::getObjectScore(o2->getObject());
-		
-	return ( o1_score > o2_score );
+
+    // XXX Weird: a higher score should go earlier, but by observation I notice
+    // that this causes further-away objects load first.  This is counterintuitive
+    // to the priority_queue Comparator, which states that this function should
+    // return 'true' if o1 should be *before* o2.
+    // In other words, I'd have expected that the following should return
+    // ( o1_score > o2_score).
+	return ( o1_score < o2_score );
 }
 	
 // static
-F64 LLMediaDataClient::Comparator::getObjectScore(const ll_vo_volume_ptr_t &obj)
+F64 LLMediaDataClient::Comparator::getObjectScore(const LLMediaDataClientObject::ptr_t &obj)
 {
 	// *TODO: make this less expensive?
-	F32 dist = obj->getRenderPosition().length() + 0.1;	 // avoids div by 0
+	F64 dist = obj->getDistanceFromAvatar() + 0.1;	 // avoids div by 0
 	// square the distance so that they are in the same "unit magnitude" as
 	// the interest (which is an area) 
 	dist *= dist;
-	F64 interest = (F64)1;
-	int i = 0;
-	int end = obj->getNumTEs();
-	for ( ; i < end; ++i)
-	{
-		const viewer_media_t &impl = obj->getMediaImpl(i);
-		if (!impl.isNull())
-		{
-			interest += impl->getInterest();
-		}
-	}
+	F64 interest = obj->getTotalMediaInterest() + 1.0;
 		
 	return interest/dist;	   
 }
@@ -286,7 +305,7 @@ F64 LLMediaDataClient::Comparator::getObjectScore(const ll_vo_volume_ptr_t &obj)
 //////////////////////////////////////////////////////////////////////////////////////
 //
 // LLMediaDataClient::PriorityQueue
-// Queue of LLVOVolume smart pointers to request media for.
+// Queue of LLMediaDataClientObject smart pointers to request media for.
 //
 //////////////////////////////////////////////////////////////////////////////////////
 
@@ -308,7 +327,7 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::PriorityQueue
 //////////////////////////////////////////////////////////////////////////////////////
 //
 // LLMediaDataClient::QueueTimer
-// Queue of LLVOVolume smart pointers to request media for.
+// Queue of LLMediaDataClientObject smart pointers to request media for.
 //
 //////////////////////////////////////////////////////////////////////////////////////
 
@@ -320,6 +339,7 @@ LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc)
 
 LLMediaDataClient::QueueTimer::~QueueTimer()
 {
+	LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL;
 	mMDC->setIsRunning(false);
 	mMDC = NULL;
 }
@@ -342,15 +362,15 @@ BOOL LLMediaDataClient::QueueTimer::tick()
 		return TRUE;
 	}
 
-	LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue is:	  " << queue << LL_ENDL;
+	LL_INFOS("LLMediaDataClient") << "QueueTimer::tick() started, queue is:	  " << queue << LL_ENDL;
 
 	// Peel one off of the items from the queue, and execute request
 	request_ptr_t request = queue.top();
 	llassert(!request.isNull());
-	const ll_vo_volume_ptr_t &object = request->getObject();
+	const LLMediaDataClientObject *object = request->getObject();
 	bool performed_request = false;
-	llassert(!object.isNull());
-	if (!object.isNull() && object->hasMedia())
+	llassert(NULL != object);
+	if (NULL != object && object->hasMedia())
 	{
 		std::string url = request->getCapability();
 		if (!url.empty())
@@ -367,17 +387,22 @@ BOOL LLMediaDataClient::QueueTimer::tick()
 		}
 	}
 	else {
-		if (!object->hasMedia())
+		if (NULL == object) 
 		{
-			LL_INFOS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
+			LL_WARNS("LLMediaDataClient") << "Not Sending request for " << *request << " NULL object!" << LL_ENDL;
+		}
+		else if (!object->hasMedia())
+		{
+			LL_WARNS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
 		}
 	}
-	bool exceeded_retries = request->getRetryCount() > LLMediaDataClient::MAX_RETRIES;
+	bool exceeded_retries = request->getRetryCount() > mMDC->mMaxNumRetries;
 	if (performed_request || exceeded_retries) // Try N times before giving up 
 	{
 		if (exceeded_retries)
 		{
-			LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << LLMediaDataClient::MAX_RETRIES << " tries...popping object id " << object->getID() << LL_ENDL; 
+			LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " 
+										  << mMDC->mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL; 
 			// XXX Should we bring up a warning dialog??
 		}
 		queue.pop();
@@ -394,15 +419,12 @@ void LLMediaDataClient::startQueueTimer()
 {
 	if (! mQueueTimerIsRunning)
 	{
-		extern LLControlGroup gSavedSettings;
-		F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
-		if (queue_timer_delay <= 0.0f)
-		{
-			queue_timer_delay = (F32)LLMediaDataClient::QUEUE_TIMER_DELAY;
-		}
-		LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << queue_timer_delay << " seconds)" << LL_ENDL;
+		LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL;
 		// LLEventTimer automagically takes care of the lifetime of this object
-		new QueueTimer(queue_timer_delay, this);
+		new QueueTimer(mQueueTimerDelay, this);
+	}
+	else { 
+		LL_DEBUGS("LLMediaDataClient") << "not starting queue timer (it's already running, right???)" << LL_ENDL;
 	}
 }
 	
@@ -411,9 +433,9 @@ void LLMediaDataClient::stopQueueTimer()
 	mQueueTimerIsRunning = false;
 }
 	
-void LLMediaDataClient::request(LLVOVolume *object, const LLSD &payload)
+void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload)
 {
-	if (NULL == object || ! object->hasMedia()) return; 
+	if (object.isNull() || ! object->hasMedia()) return; 
 
 	// Push the object on the priority queue
 	enqueue(new Request(getCapabilityName(), payload, object, this));
@@ -422,8 +444,8 @@ void LLMediaDataClient::request(LLVOVolume *object, const LLSD &payload)
 void LLMediaDataClient::enqueue(const Request *request)
 {
 	LL_INFOS("LLMediaDataClient") << "Queuing request for " << *request << LL_ENDL;
-    // Push the request on the priority queue
-    // Sadly, we have to const-cast because items put into the queue are not const
+	// Push the request on the priority queue
+	// Sadly, we have to const-cast because items put into the queue are not const
 	pRequestQueue->push(const_cast<LLMediaDataClient::Request*>(request));
 	LL_DEBUGS("LLMediaDataClient") << "Queue:" << (*pRequestQueue) << LL_ENDL;
 	// Start the timer if not already running
@@ -436,21 +458,31 @@ void LLMediaDataClient::enqueue(const Request *request)
 //
 //////////////////////////////////////////////////////////////////////////////////////
 
-LLMediaDataClient::LLMediaDataClient()
+LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay,
+									 F32 retry_timer_delay,
+									 U32 max_retries)
+	: mQueueTimerDelay(queue_timer_delay),
+	  mRetryTimerDelay(retry_timer_delay),
+	  mMaxNumRetries(max_retries),
+	  mQueueTimerIsRunning(false)
 {
 	pRequestQueue = new PriorityQueue();
 }
 
-
 LLMediaDataClient::~LLMediaDataClient()
 {
 	stopQueueTimer();
-	
+
 	// This should clear the queue, and hopefully call all the destructors.
-    while (! pRequestQueue->empty()) pRequestQueue->pop();
-	
+	LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClient destructor: queue: " << 
+		(pRequestQueue->empty() ? "<empty> " : "<not empty> ") << (*pRequestQueue) << LL_ENDL;
 	delete pRequestQueue;
-    pRequestQueue = NULL;
+	pRequestQueue = NULL;
+}
+
+bool LLMediaDataClient::isEmpty() const
+{
+	return (NULL == pRequestQueue) ? true : pRequestQueue->empty();
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -462,79 +494,78 @@ LLMediaDataClient::~LLMediaDataClient()
 
 LLMediaDataClient::Responder *LLObjectMediaDataClient::createResponder(const request_ptr_t &request) const
 {
-    return new LLObjectMediaDataClient::Responder(request);
+	return new LLObjectMediaDataClient::Responder(request);
 }
 
 const char *LLObjectMediaDataClient::getCapabilityName() const 
 {
-    return "ObjectMedia";
+	return "ObjectMedia";
 }
 
-void LLObjectMediaDataClient::fetchMedia(LLVOVolume *object)
+void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object)
 {
-    LLSD sd_payload;
-    sd_payload["verb"] = "GET";
-    sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
-    request(object, sd_payload);
+	LLSD sd_payload;
+	sd_payload["verb"] = "GET";
+	sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
+	request(object, sd_payload);
 }
 
-void LLObjectMediaDataClient::updateMedia(LLVOVolume *object)
+void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object)
 {
-    LLSD sd_payload;
-    sd_payload["verb"] = "UPDATE";
-    sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
-    LLSD object_media_data;
-    for (int i=0; i < object->getNumTEs(); i++) {
-        LLTextureEntry *texture_entry = object->getTE(i);
-        llassert((texture_entry->getMediaData() != NULL) == texture_entry->hasMedia());
-        const LLSD &media_data =  
-            (texture_entry->getMediaData() == NULL) ? LLSD() : texture_entry->getMediaData()->asLLSD();
-        object_media_data.append(media_data);
-    }
-    sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
-        
-	LL_INFOS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_pretty_print_sd(sd_payload) << LL_ENDL;
-    
-    request(object, sd_payload);
+	LLSD sd_payload;
+	sd_payload["verb"] = "UPDATE";
+	sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
+	LLSD object_media_data;
+	int i = 0;
+	int end = object->getMediaDataCount();
+	for ( ; i < end ; ++i) 
+	{
+		object_media_data.append(object->getMediaDataLLSD(i));
+	}
+	sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
+		
+	LL_INFOS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_print_sd(sd_payload) << LL_ENDL;
+	
+	request(object, sd_payload);
 }
 
 /*virtual*/
 void LLObjectMediaDataClient::Responder::result(const LLSD& content)
 {
-    const LLMediaDataClient::Request::Type type = getRequest()->getType();
-    llassert(type == LLMediaDataClient::Request::GET || type == LLMediaDataClient::Request::UPDATE)
-    if (type == LLMediaDataClient::Request::GET)
-    {
-        LL_INFOS("LLMediaDataClient") << *(getRequest()) << "GET returned: " << ll_pretty_print_sd(content) << LL_ENDL;
-        
-        // Look for an error
-        if (content.has("error"))
-        {
-            const LLSD &error = content["error"];
-            LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << 
+	const LLMediaDataClient::Request::Type type = getRequest()->getType();
+	llassert(type == LLMediaDataClient::Request::GET || type == LLMediaDataClient::Request::UPDATE)
+	if (type == LLMediaDataClient::Request::GET)
+	{
+		LL_INFOS("LLMediaDataClient") << *(getRequest()) << "GET returned: " << ll_print_sd(content) << LL_ENDL;
+		
+		// Look for an error
+		if (content.has("error"))
+		{
+			const LLSD &error = content["error"];
+			LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << 
 				error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
-            
-            // XXX Warn user?
-        }
-        else {
-            // Check the data
-            const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY];
-            if (object_id != getRequest()->getObject()->getID()) 
-            {
-                // NOT good, wrong object id!!
-                LL_WARNS("LLMediaDataClient") << *(getRequest()) << "DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL;
-                return;
-            }
-            
-            // Otherwise, update with object media data
-            getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY]);
-        }
-    }
-    else if (type == LLMediaDataClient::Request::UPDATE)
-    {
-        // just do what our superclass does
-        LLMediaDataClient::Responder::result(content);
-    }
+			
+			// XXX Warn user?
+		}
+		else {
+			// Check the data
+			const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY];
+			if (object_id != getRequest()->getObject()->getID()) 
+			{
+				// NOT good, wrong object id!!
+				LL_WARNS("LLMediaDataClient") << *(getRequest()) << "DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL;
+				return;
+			}
+			
+			// Otherwise, update with object media data
+			getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY]);
+		}
+	}
+	else if (type == LLMediaDataClient::Request::UPDATE)
+	{
+		// just do what our superclass does
+		LLMediaDataClient::Responder::result(content);
+	}
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -545,21 +576,21 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content)
 //////////////////////////////////////////////////////////////////////////////////////
 LLMediaDataClient::Responder *LLObjectMediaNavigateClient::createResponder(const request_ptr_t &request) const
 {
-    return new LLObjectMediaNavigateClient::Responder(request);
+	return new LLObjectMediaNavigateClient::Responder(request);
 }
 
 const char *LLObjectMediaNavigateClient::getCapabilityName() const 
 {
-    return "ObjectMediaNavigate";
+	return "ObjectMediaNavigate";
 }
 
-void LLObjectMediaNavigateClient::navigate(LLVOVolume *object, U8 texture_index, const std::string &url)
+void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url)
 {
-    LLSD sd_payload;
-    sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
+	LLSD sd_payload;
+	sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
 	sd_payload[LLMediaEntry::CURRENT_URL_KEY] = url;
 	sd_payload[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)texture_index;
-    request(object, sd_payload);
+	request(object, sd_payload);
 }
 
 /*virtual*/
@@ -573,16 +604,18 @@ void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string
 	}
 	else {
 		// bounce the face back
-		bounceBack();
 		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL;
+		const LLSD &payload = getRequest()->getPayload();
+		// bounce the face back
+		getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
 	}
 }
 
 /*virtual*/
 void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
 {
-    LL_DEBUGS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_pretty_print_sd(content) << LL_ENDL;
-    
+	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL;
+	
 	if (content.has("error"))
 	{
 		const LLSD &error = content["error"];
@@ -590,38 +623,19 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
 		
 		if (ERROR_PERMISSION_DENIED_CODE == error_code)
 		{
-            LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL;
+			LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL;
+			const LLSD &payload = getRequest()->getPayload();
 			// bounce the face back
-			bounceBack();
+			getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
 		}
 		else {
-            LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << 
+			LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << 
 				error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
-		}            
+		}			 
 		// XXX Warn user?
 	}
-    else {
-        // just do what our superclass does
-        LLMediaDataClient::Responder::result(content);
-    }
-}
-
-
-void LLObjectMediaNavigateClient::Responder::bounceBack()
-{
-	const LLSD &payload = getRequest()->getPayload();
-	U8 texture_index = (U8)(LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY];
-    viewer_media_t impl = getRequest()->getObject()->getMediaImpl(texture_index);
-    // Find the media entry for this navigate
-    LLMediaEntry* mep = NULL;
-    LLTextureEntry *te = getRequest()->getObject()->getTE(texture_index);
-    if(te)
-    {
-        mep = te->getMediaData();
-    }
-    
-    if (mep && impl)
-    {
-//        impl->navigateTo(mep->getCurrentURL());
-    }
+	else {
+		// just do what our superclass does
+		LLMediaDataClient::Responder::result(content);
+	}
 }
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index 59c4334251fd3087b17b5d379bb4f906feb2a334..9d0aa0981e77cb9a651f2fbf259467374dd838ab 100755
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -36,12 +36,36 @@
 #include "llhttpclient.h"
 #include <queue>
 #include "llrefcount.h"
+#include "llpointer.h"
 #include "lltimer.h"
 
-// Forward decls
-class LLVOVolume;
 
-typedef LLPointer<LLVOVolume> ll_vo_volume_ptr_t;
+// Link seam for LLVOVolume
+class LLMediaDataClientObject : public LLRefCount
+{
+public:
+	// Get the number of media data items
+	virtual U8 getMediaDataCount() const = 0;
+	// Get the media data at index, as an LLSD
+	virtual LLSD getMediaDataLLSD(U8 index) const = 0;
+	// Get this object's UUID
+	virtual LLUUID getID() const = 0;
+	// Navigate back to previous URL
+	virtual void mediaNavigateBounceBack(U8 index) = 0;
+	// Does this object have media?
+	virtual bool hasMedia() const = 0;
+	// Update the object's media data to the given array
+	virtual void updateObjectMediaData(LLSD const &media_data_array) = 0;
+	// Return the distance from the object to the avatar
+	virtual F64 getDistanceFromAvatar() const = 0;
+	// Return the total "interest" of the media (on-screen area)
+	virtual F64 getTotalMediaInterest() const = 0;
+	// Return the given cap url
+	virtual std::string getCapabilityUrl(const std::string &name) const = 0;
+
+	// smart pointer
+	typedef LLPointer<LLMediaDataClientObject> ptr_t;
+};
 
 // This object creates a priority queue for requests.
 // Abstracts the Cap URL, the request, and the responder
@@ -50,15 +74,23 @@ class LLMediaDataClient : public LLRefCount
 public:
     LOG_CLASS(LLMediaDataClient);
     
-    const static int QUEUE_TIMER_DELAY = 1; // seconds(s)
-	const static int MAX_RETRIES = 4;
+    const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s)
+	const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs
+	const static U32 MAX_RETRIES;// = 4;
 
 	// Constructor
-	LLMediaDataClient();
+	LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+					  F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+		              U32 max_retries = MAX_RETRIES);
 	
 	// Make the request
-	void request(LLVOVolume *object, const LLSD &payload);
-    
+	void request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload);
+
+	F32 getRetryTimerDelay() const { return mRetryTimerDelay; }
+	
+	// Returns true iff the queue is empty
+	bool isEmpty() const; 
+	
 protected:
 	// Destructor
 	virtual ~LLMediaDataClient(); // use unref
@@ -73,10 +105,10 @@ class LLMediaDataClient : public LLRefCount
             NAVIGATE
         };
         
-		Request(const std::string &cap_name, const LLSD& sd_payload, LLVOVolume *obj, LLMediaDataClient *mdc);
+		Request(const std::string &cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
 		const std::string &getCapName() const { return mCapName; }
 		const LLSD &getPayload() const { return mPayload; }
-		LLVOVolume *getObject() const { return mObject; }
+		LLMediaDataClientObject *getObject() const { return mObject; }
 
         U32 getNum() const { return mNum; }
 
@@ -92,6 +124,9 @@ class LLMediaDataClient : public LLRefCount
 		// Re-enqueue thyself
 		void reEnqueue() const;
 		
+		F32 getRetryTimerDelay() const;
+		U32 getMaxNumRetries() const;
+		
 	public:
 		friend std::ostream& operator<<(std::ostream &s, const Request &q);
 		
@@ -101,7 +136,7 @@ class LLMediaDataClient : public LLRefCount
 	private:
 		std::string mCapName;
 		LLSD mPayload;
-		ll_vo_volume_ptr_t mObject;
+		LLMediaDataClientObject::ptr_t mObject;
 		// Simple tracking
 		const U32 mNum;
 		static U32 sNum;
@@ -115,8 +150,6 @@ class LLMediaDataClient : public LLRefCount
 	// Responder
 	class Responder : public LLHTTPClient::Responder
 	{
-		static const int UNAVAILABLE_RETRY_TIMER_DELAY = 5; // secs
-
 	public:
 		Responder(const request_ptr_t &request);
 		//If we get back an error (not found, etc...), handle it here
@@ -163,9 +196,10 @@ class LLMediaDataClient : public LLRefCount
 	public:
 		bool operator() (const request_ptr_t &o1, const request_ptr_t &o2) const;
 	private:
-		static F64 getObjectScore(const ll_vo_volume_ptr_t &obj);
+		static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj);
 	};
 	
+    // PriorityQueue
 	class PriorityQueue : public std::priority_queue<
 		request_ptr_t, 
 		std::vector<request_ptr_t>, 
@@ -193,6 +227,10 @@ class LLMediaDataClient : public LLRefCount
 	void startQueueTimer();
 	void stopQueueTimer();
 	void setIsRunning(bool val) { mQueueTimerIsRunning = val; }
+
+	const F32 mQueueTimerDelay;
+	const F32 mRetryTimerDelay;
+	const U32 mMaxNumRetries;
 	
 	bool mQueueTimerIsRunning;
 	
@@ -204,11 +242,15 @@ class LLMediaDataClient : public LLRefCount
 class LLObjectMediaDataClient : public LLMediaDataClient
 {
 public:
-    LLObjectMediaDataClient() {}
+    LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+							F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+							U32 max_retries = MAX_RETRIES)
+		: LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
+		{}
     ~LLObjectMediaDataClient() {}
     
-	void fetchMedia(LLVOVolume *object); 
-    void updateMedia(LLVOVolume *object);
+	void fetchMedia(LLMediaDataClientObject *object); 
+    void updateMedia(LLMediaDataClientObject *object);
     
 protected:
 	// Subclasses must override this factory method to return a new responder
@@ -230,14 +272,18 @@ class LLObjectMediaDataClient : public LLMediaDataClient
 // MediaDataResponder specific for the ObjectMediaNavigate cap
 class LLObjectMediaNavigateClient : public LLMediaDataClient
 {
+public:
 	// NOTE: from llmediaservice.h
 	static const int ERROR_PERMISSION_DENIED_CODE = 8002;
 	
-public:
-    LLObjectMediaNavigateClient() {}
+    LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+								F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+								U32 max_retries = MAX_RETRIES)
+		: LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
+		{}
     ~LLObjectMediaNavigateClient() {}
     
-    void navigate(LLVOVolume *object, U8 texture_index, const std::string &url);
+    void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url);
     
 protected:
 	// Subclasses must override this factory method to return a new responder
@@ -254,7 +300,7 @@ class LLObjectMediaNavigateClient : public LLMediaDataClient
 		virtual void error(U32 status, const std::string& reason);
         virtual void result(const LLSD &content);
     private:
-        void bounceBack();
+        void mediaNavigateBounceBack();
     };
 
 };
diff --git a/indra/newview/llmenucommands.cpp b/indra/newview/llmenucommands.cpp
index 8dd09d5ec72f8a0904b6da70f6aec922182cfc3c..28ddaa61c4c811aba63f35168ad0a2b55d4c170b 100644
--- a/indra/newview/llmenucommands.cpp
+++ b/indra/newview/llmenucommands.cpp
@@ -66,7 +66,6 @@
 #include "llfocusmgr.h"
 #include "llnearbychatbar.h"
 
-
 void handle_mouselook(void*)
 {
 	gAgent.changeCameraToMouselook();
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index 665ce9f59cf385dd88d39f3298983f9414f5bb20..d81cbb3e5d46d9c1ff46fe81b8de2ab5d7100f12 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -36,6 +36,7 @@
 #include "llbutton.h"
 #include "llfloaterreg.h"
 #include "llsdutil.h"
+#include "llsdutil_math.h"
 
 #include "llaccordionctrltab.h"
 #include "llagent.h"
diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp
index 3177ef9a21c434c2ee2a2d3934dd6ba138fd291b..f9dde034513b93388dcaa63b7c4ec463229ce854 100644
--- a/indra/newview/llpanelmediasettingsgeneral.cpp
+++ b/indra/newview/llpanelmediasettingsgeneral.cpp
@@ -1,440 +1,448 @@
-/**
- * @file llpanelmediasettingsgeneral.cpp
- * @brief LLPanelMediaSettingsGeneral class implementation
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * 
- * Copyright (c) 2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanelmediasettingsgeneral.h"
-#include "llcombobox.h"
-#include "llcheckboxctrl.h"
-#include "llspinctrl.h"
-#include "lluictrlfactory.h"
-#include "llviewerwindow.h"
-#include "llviewermedia.h"
-#include "llsdutil.h"
-#include "llselectmgr.h"
-#include "llbutton.h"
-#include "lltexturectrl.h"
-#include "llurl.h"
-#include "llwindow.h"
-#include "llmediaentry.h"
-#include "llmediactrl.h"
-#include "llpanelcontents.h"
-#include "llpluginclassmedia.h"
-#include "llfloatermediasettings.h"
-#include "llfloatertools.h"
-#include "lltrans.h"
-
-////////////////////////////////////////////////////////////////////////////////
-//
-LLPanelMediaSettingsGeneral::LLPanelMediaSettingsGeneral() :
-	mControls( NULL ),
-	mAutoLoop( NULL ),
-	mFirstClick( NULL ),
-	mAutoZoom( NULL ),
-	mAutoPlay( NULL ),
-	mAutoScale( NULL ),
-	mWidthPixels( NULL ),
-	mHeightPixels( NULL ),
-	mHomeURL( NULL ),
-	mCurrentURL( NULL ),
-	mAltImageEnable( NULL ),
-	mParent( NULL ),
-	mMediaEditable(false)
-{
-	// build dialog from XML
-	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_general.xml");
-//	mCommitCallbackRegistrar.add("Media.ResetCurrentUrl",		boost::bind(&LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl, this));
-//	mCommitCallbackRegistrar.add("Media.CommitHomeURL",			boost::bind(&LLPanelMediaSettingsGeneral::onCommitHomeURL, this));	
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-BOOL LLPanelMediaSettingsGeneral::postBuild()
-{
-	// connect member vars with UI widgets
-    mAltImageEnable = getChild< LLCheckBoxCtrl >( LLMediaEntry::ALT_IMAGE_ENABLE_KEY );
-	mAutoLoop = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_LOOP_KEY );
-	mAutoPlay = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_PLAY_KEY );
-	mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY );
-	mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY );
-	mControls = getChild< LLComboBox >( LLMediaEntry::CONTROLS_KEY );
-	mCurrentURL = getChild< LLLineEditor >( LLMediaEntry::CURRENT_URL_KEY );
-	mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY );
-	mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY );
-	mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY );
-	mWidthPixels = getChild< LLSpinCtrl >( LLMediaEntry::WIDTH_PIXELS_KEY );
-	mPreviewMedia = getChild<LLMediaCtrl>("preview_media");
-
-	// watch commit action for HOME URL
-	childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this);
-	childSetCommitCallback( "current_url_reset_btn",onBtnResetCurrentUrl, this);
-	// interrogates controls and updates widgets as required
-	updateMediaPreview();
-	updateCurrentURL();
-
-	return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-LLPanelMediaSettingsGeneral::~LLPanelMediaSettingsGeneral()
-{
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsGeneral::draw()
-{
-	// housekeeping
-	LLPanel::draw();
-
-	// enable/disable pixel values image entry based on auto scale checkbox 
-	if ( mAutoScale->getValue().asBoolean() == false )
-	{
-		childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, true );
-		childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, true );
-	}
-	else
-	{
-		childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, false );
-		childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, false );
-	};
-
-	// enable/disable UI based on type of media
-	bool reset_button_is_active = true;
-	if( mPreviewMedia )
-	{
-		LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin();
-		if( media_plugin )
-		{
-			// some controls are only appropriate for time or browser type plugins
-			// so we selectively enable/disable them - need to do it in draw
-			// because the information from plugins arrives assynchronously
-			bool show_time_controls = media_plugin->pluginSupportsMediaTime();
-			if ( show_time_controls )
-			{
-				childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, false );
-				reset_button_is_active = false;
-				childSetEnabled( "current_url_label", false );
-				childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, true );
-			}
-			else
-			{
-				childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, true );
-				reset_button_is_active = true;
-				childSetEnabled( "current_url_label", true );
-				childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, false );
-			};
-		};
-	};
-
-	// current URL can change over time.
-//	updateCurrentURL();
-
-	// enable/disable RESRET button depending on permissions
-	// since this is the same as a navigate action
-	bool user_can_press_reset = mMediaEditable;
-
-	// several places modify this widget so we must collect states in one place
-	if ( reset_button_is_active )
-	{
-		// user has perms to press reset button and it is active
-		if ( user_can_press_reset )
-		{
-			childSetEnabled( "current_url_reset_btn", true );
-		}
-		// user does not has perms to press reset button and it is active
-		else
-		{
-			childSetEnabled( "current_url_reset_btn", false );
-		};
-	}
-	else
-	// reset button is inactive so we just slam it to off - other states don't matter
-	{
-		childSetEnabled( "current_url_reset_btn", false );
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static 
-void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable)
-{	
-	LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata;
-	self->mAltImageEnable ->clear();
-	self->mAutoLoop->clear();
-	self->mAutoPlay->clear();
-	self->mAutoScale->clear();
-	self->mAutoZoom ->clear();
-	self->mControls->clear();
-	self->mCurrentURL->clear();
-	self->mFirstClick->clear();
-	self->mHeightPixels->clear();
-	self->mHomeURL->clear();
-	self->mWidthPixels->clear();
-	self->mAltImageEnable ->setEnabled(editable);
-	self->mAutoLoop ->setEnabled(editable);
-	self->mAutoPlay ->setEnabled(editable);
-	self->mAutoScale ->setEnabled(editable);
-	self->mAutoZoom  ->setEnabled(editable);
-	self->mControls ->setEnabled(editable);
-	self->mCurrentURL ->setEnabled(editable);
-	self->mFirstClick ->setEnabled(editable);
-	self->mHeightPixels ->setEnabled(editable);
-	self->mHomeURL ->setEnabled(editable);
-	self->mWidthPixels ->setEnabled(editable);
-	self->mPreviewMedia->unloadMediaSource(); 
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static 
-void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ,bool editable)
-{
-	LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata;
-	self->mMediaEditable = editable;
-
-	//llinfos << "---------------" << llendl;
-	//llinfos << ll_pretty_print_sd(media_settings) << llendl;
-	//llinfos << "---------------" << llendl;
-
-	// IF all the faces have media (or all dont have media)
-	if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
-	{
-		if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) 
-		{
-			self->clearValues(self, self->mMediaEditable);
-			// only show multiple 
-			self->mHomeURL ->setText(LLTrans::getString("Multiple Media"));
-			return;
-		}
-		
-	}
-	else
-	{
-		if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) 
-		{
-			self->clearValues(self, self->mMediaEditable);
-			// only show multiple 
-			self->mHomeURL ->setText(LLTrans::getString("Multiple Media"));
-			return;
-		}			
-		
-	}
-	std::string base_key( "" );
-	std::string tentative_key( "" );
-
-	struct 
-	{
-		std::string key_name;
-		LLUICtrl* ctrl_ptr;
-		std::string ctrl_type;
-
-	} data_set [] = 
-	{ 
-        { LLMediaEntry::AUTO_LOOP_KEY,				self->mAutoLoop,		"LLCheckBoxCtrl" },
-		{ LLMediaEntry::AUTO_PLAY_KEY,				self->mAutoPlay,		"LLCheckBoxCtrl" },
-		{ LLMediaEntry::AUTO_SCALE_KEY,				self->mAutoScale,		"LLCheckBoxCtrl" },
-		{ LLMediaEntry::AUTO_ZOOM_KEY,				self->mAutoZoom,		"LLCheckBoxCtrl" },
-		{ LLMediaEntry::CONTROLS_KEY,				self->mControls,		"LLComboBox" },
-		{ LLMediaEntry::CURRENT_URL_KEY,			self->mCurrentURL,		"LLLineEditor" },
-		{ LLMediaEntry::HEIGHT_PIXELS_KEY,			self->mHeightPixels,	"LLSpinCtrl" },
-		{ LLMediaEntry::HOME_URL_KEY,				self->mHomeURL,			"LLLineEditor" },
-		{ LLMediaEntry::FIRST_CLICK_INTERACT_KEY,	self->mFirstClick,		"LLCheckBoxCtrl" },
-		{ LLMediaEntry::WIDTH_PIXELS_KEY,			self->mWidthPixels,		"LLSpinCtrl" },
-		{ LLMediaEntry::ALT_IMAGE_ENABLE_KEY,		self->mAltImageEnable,	"LLCheckBoxCtrl" },
-		{ "", NULL , "" }
-	};
-
-	for( int i = 0; data_set[ i ].key_name.length() > 0; ++i )
-	{
-		base_key = std::string( data_set[ i ].key_name );
-		tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX );
-		// TODO: CP - I bet there is a better way to do this using Boost
-		if ( media_settings[ base_key ].isDefined() )
-		{
-			if ( data_set[ i ].ctrl_type == "LLLineEditor" )
-			{
-				static_cast< LLLineEditor* >( data_set[ i ].ctrl_ptr )->
-					setText( media_settings[ base_key ].asString() );
-			}
-			else
-			if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" )
-				static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )->
-					setValue( media_settings[ base_key ].asBoolean() );
-			else
-			if ( data_set[ i ].ctrl_type == "LLComboBox" )
-				static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )->
-					setCurrentByIndex( media_settings[ base_key ].asInteger() );
-			else
-			if ( data_set[ i ].ctrl_type == "LLSpinCtrl" )
-				static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )->
-					setValue( media_settings[ base_key ].asInteger() );
-
-			data_set[ i ].ctrl_ptr->setEnabled(self->mMediaEditable);
-			data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
-		};
-	};
-	
-	// interrogates controls and updates widgets as required
-	self->updateMediaPreview();
-	self->updateCurrentURL();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Helper to set media control to media URL as required
-void LLPanelMediaSettingsGeneral::updateMediaPreview()
-{
-	if ( mHomeURL->getValue().asString().length() > 0 )
-	{
-		mPreviewMedia->navigateTo( mHomeURL->getValue().asString() );
-	}
-	else
-	// new home URL will be empty if media is deleted but
-	// we still need to clean out the preview.
-	{
-		mPreviewMedia->unloadMediaSource();
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Helper to set current URL
-void LLPanelMediaSettingsGeneral::updateCurrentURL()
-{
-	if( mCurrentURL->getText().empty() )
-	{
-		childSetText( "current_url", mHomeURL->getText() );
-	}
-	
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// virtual
-void LLPanelMediaSettingsGeneral::onClose(bool app_quitting)
-{
-	if(mPreviewMedia)
-	{
-		mPreviewMedia->unloadMediaSource();
-	}
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata )
-{
-	LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata;
-	self->updateMediaPreview();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl(LLUICtrl* ctrl, void *userdata)
-{
-	LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata;
-	self->navigateHomeSelectedFace();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsGeneral::apply( void* userdata )
-{
-	LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata;
-	self->mHomeURL->onCommit();
-	// build LLSD Fragment
-	LLSD media_data_general;
-	self->getValues(media_data_general);
-
-	// this merges contents of LLSD passed in with what's there so this is ok
-	LLSelectMgr::getInstance()->selectionSetMediaData( media_data_general );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in )
-{
-    fill_me_in[LLMediaEntry::ALT_IMAGE_ENABLE_KEY] = mAltImageEnable->getValue();
-    fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = mAutoLoop->getValue();
-    fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = mAutoPlay->getValue();
-    fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = mAutoScale->getValue();
-    fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = mAutoZoom->getValue();
-    fill_me_in[LLMediaEntry::CONTROLS_KEY] = mControls->getCurrentIndex();
-    // XXX Don't send current URL!
-    //fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue();
-    fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = mHeightPixels->getValue();
-    fill_me_in[LLMediaEntry::HOME_URL_KEY] = mHomeURL->getValue();
-    fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = mFirstClick->getValue();
-    fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = mWidthPixels->getValue();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent )
-{
-	mParent = parent;
-};
-
-bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace()
-{
-	// HACK: This is directly referencing an impl name.  BAD!
-	// This can be removed when we have a truly generic media browser that only 
-	// builds an impl based on the type of url it is passed.
-	struct functor_navigate_media : public LLSelectedTEGetFunctor< bool>
-	{
-		bool get( LLViewerObject* object, S32 face )
-		{
-			if ( object )
-				if ( object->getTE(face) )
-					if ( object->getTE(face)->getMediaData() )
-					{
-						if(object->permModify())
-						{
-							viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID());
-							if(media_impl)
-							{
-								media_impl->navigateHome();
-								return true;
-							}
-						}	
-					}
-		   return false;
-		 };
-				
-	} functor_navigate_media;
-	
-	bool all_face_media_navigated = false;
-	LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection();
-	selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated );
-	
-	return all_face_media_navigated;
-}
-
+/**
+ * @file llpanelmediasettingsgeneral.cpp
+ * @brief LLPanelMediaSettingsGeneral class implementation
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llagent.h"
+#include "llpanelmediasettingsgeneral.h"
+#include "llcombobox.h"
+#include "llcheckboxctrl.h"
+#include "llspinctrl.h"
+#include "lluictrlfactory.h"
+#include "llviewerwindow.h"
+#include "llviewermedia.h"
+#include "llsdutil.h"
+#include "llselectmgr.h"
+#include "llbutton.h"
+#include "lltexturectrl.h"
+#include "llurl.h"
+#include "llwindow.h"
+#include "llmediaentry.h"
+#include "llmediactrl.h"
+#include "llpanelcontents.h"
+#include "llpermissions.h"
+#include "llpluginclassmedia.h"
+#include "llfloatermediasettings.h"
+#include "llfloatertools.h"
+#include "lltrans.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+LLPanelMediaSettingsGeneral::LLPanelMediaSettingsGeneral() :
+	mControls( NULL ),
+	mAutoLoop( NULL ),
+	mFirstClick( NULL ),
+	mAutoZoom( NULL ),
+	mAutoPlay( NULL ),
+	mAutoScale( NULL ),
+	mWidthPixels( NULL ),
+	mHeightPixels( NULL ),
+	mHomeURL( NULL ),
+	mCurrentURL( NULL ),
+	mParent( NULL ),
+	mMediaEditable(false)
+{
+	// build dialog from XML
+	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_general.xml");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLPanelMediaSettingsGeneral::postBuild()
+{
+	// connect member vars with UI widgets
+	mAutoLoop = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_LOOP_KEY );
+	mAutoPlay = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_PLAY_KEY );
+	mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY );
+	mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY );
+	mControls = getChild< LLComboBox >( LLMediaEntry::CONTROLS_KEY );
+	mCurrentURL = getChild< LLLineEditor >( LLMediaEntry::CURRENT_URL_KEY );
+	mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY );
+	mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY );
+	mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY );
+	mWidthPixels = getChild< LLSpinCtrl >( LLMediaEntry::WIDTH_PIXELS_KEY );
+	mPreviewMedia = getChild<LLMediaCtrl>("preview_media");
+
+	// watch commit action for HOME URL
+	childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this);
+	childSetCommitCallback( "current_url_reset_btn",onBtnResetCurrentUrl, this);
+	// interrogates controls and updates widgets as required
+	updateMediaPreview();
+	updateCurrentURL();
+
+	return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// virtual
+LLPanelMediaSettingsGeneral::~LLPanelMediaSettingsGeneral()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsGeneral::draw()
+{
+	// housekeeping
+	LLPanel::draw();
+
+	// enable/disable pixel values image entry based on auto scale checkbox 
+	if ( mAutoScale->getValue().asBoolean() == false )
+	{
+		childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, true );
+		childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, true );
+	}
+	else
+	{
+		childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, false );
+		childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, false );
+	};
+
+	// enable/disable UI based on type of media
+	bool reset_button_is_active = true;
+	if( mPreviewMedia )
+	{
+		LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin();
+		if( media_plugin )
+		{
+			// some controls are only appropriate for time or browser type plugins
+			// so we selectively enable/disable them - need to do it in draw
+			// because the information from plugins arrives assynchronously
+			bool show_time_controls = media_plugin->pluginSupportsMediaTime();
+			if ( show_time_controls )
+			{
+				childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, false );
+				reset_button_is_active = false;
+				childSetEnabled( "current_url_label", false );
+				childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, true );
+			}
+			else
+			{
+				childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, true );
+				reset_button_is_active = true;
+				childSetEnabled( "current_url_label", true );
+				childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, false );
+			};
+		};
+	};
+
+	// current URL can change over time.
+//	updateCurrentURL();
+
+	LLPermissions perm;
+	bool user_can_press_reset = mMediaEditable;
+
+	// several places modify this widget so we must collect states in one place
+	if ( reset_button_is_active )
+	{
+		// user has perms to press reset button and it is active
+		if ( user_can_press_reset )
+		{
+			childSetEnabled( "current_url_reset_btn", true );
+		}
+		// user does not has perms to press reset button and it is active
+		else
+		{
+			childSetEnabled( "current_url_reset_btn", false );
+		};
+	}
+	else
+	// reset button is inactive so we just slam it to off - other states don't matter
+	{
+		childSetEnabled( "current_url_reset_btn", false );
+	};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static 
+void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable)
+{	
+	LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata;
+	self->mAutoLoop->clear();
+	self->mAutoPlay->clear();
+	self->mAutoScale->clear();
+	self->mAutoZoom ->clear();
+	self->mControls->clear();
+	self->mCurrentURL->clear();
+	self->mFirstClick->clear();
+	self->mHeightPixels->clear();
+	self->mHomeURL->clear();
+	self->mWidthPixels->clear();
+	self->mAutoLoop ->setEnabled(editable);
+	self->mAutoPlay ->setEnabled(editable);
+	self->mAutoScale ->setEnabled(editable);
+	self->mAutoZoom  ->setEnabled(editable);
+	self->mControls ->setEnabled(editable);
+	self->mCurrentURL ->setEnabled(editable);
+	self->mFirstClick ->setEnabled(editable);
+	self->mHeightPixels ->setEnabled(editable);
+	self->mHomeURL ->setEnabled(editable);
+	self->mWidthPixels ->setEnabled(editable);
+	self->mPreviewMedia->unloadMediaSource(); 
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static 
+void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ,bool editable)
+{
+	LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata;
+	self->mMediaEditable = editable;
+
+	//llinfos << "---------------" << llendl;
+	//llinfos << ll_pretty_print_sd(media_settings) << llendl;
+	//llinfos << "---------------" << llendl;
+
+	// IF all the faces have media (or all dont have media)
+	if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
+	{
+		if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) 
+		{
+			self->clearValues(self, self->mMediaEditable);
+			// only show multiple 
+			self->mHomeURL ->setText(LLTrans::getString("Multiple Media"));
+			return;
+		}
+		
+	}
+	else
+	{
+		if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) 
+		{
+			self->clearValues(self, self->mMediaEditable);
+			// only show multiple 
+			self->mHomeURL ->setText(LLTrans::getString("Multiple Media"));
+			return;
+		}			
+		
+	}
+	std::string base_key( "" );
+	std::string tentative_key( "" );
+
+	struct 
+	{
+		std::string key_name;
+		LLUICtrl* ctrl_ptr;
+		std::string ctrl_type;
+
+	} data_set [] = 
+	{ 
+        { LLMediaEntry::AUTO_LOOP_KEY,				self->mAutoLoop,		"LLCheckBoxCtrl" },
+		{ LLMediaEntry::AUTO_PLAY_KEY,				self->mAutoPlay,		"LLCheckBoxCtrl" },
+		{ LLMediaEntry::AUTO_SCALE_KEY,				self->mAutoScale,		"LLCheckBoxCtrl" },
+		{ LLMediaEntry::AUTO_ZOOM_KEY,				self->mAutoZoom,		"LLCheckBoxCtrl" },
+		{ LLMediaEntry::CONTROLS_KEY,				self->mControls,		"LLComboBox" },
+		{ LLMediaEntry::CURRENT_URL_KEY,			self->mCurrentURL,		"LLLineEditor" },
+		{ LLMediaEntry::HEIGHT_PIXELS_KEY,			self->mHeightPixels,	"LLSpinCtrl" },
+		{ LLMediaEntry::HOME_URL_KEY,				self->mHomeURL,			"LLLineEditor" },
+		{ LLMediaEntry::FIRST_CLICK_INTERACT_KEY,	self->mFirstClick,		"LLCheckBoxCtrl" },
+		{ LLMediaEntry::WIDTH_PIXELS_KEY,			self->mWidthPixels,		"LLSpinCtrl" },
+		{ "", NULL , "" }
+	};
+
+	for( int i = 0; data_set[ i ].key_name.length() > 0; ++i )
+	{
+		base_key = std::string( data_set[ i ].key_name );
+		tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX );
+		// TODO: CP - I bet there is a better way to do this using Boost
+		if ( media_settings[ base_key ].isDefined() )
+		{
+			if ( data_set[ i ].ctrl_type == "LLLineEditor" )
+			{
+				static_cast< LLLineEditor* >( data_set[ i ].ctrl_ptr )->
+					setText( media_settings[ base_key ].asString() );
+			}
+			else
+			if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" )
+				static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )->
+					setValue( media_settings[ base_key ].asBoolean() );
+			else
+			if ( data_set[ i ].ctrl_type == "LLComboBox" )
+				static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )->
+					setCurrentByIndex( media_settings[ base_key ].asInteger() );
+			else
+			if ( data_set[ i ].ctrl_type == "LLSpinCtrl" )
+				static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )->
+					setValue( media_settings[ base_key ].asInteger() );
+
+			data_set[ i ].ctrl_ptr->setEnabled(self->mMediaEditable);
+			data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
+		};
+	};
+	
+	// interrogates controls and updates widgets as required
+	self->updateMediaPreview();
+	self->updateCurrentURL();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Helper to set media control to media URL as required
+void LLPanelMediaSettingsGeneral::updateMediaPreview()
+{
+	if ( mHomeURL->getValue().asString().length() > 0 )
+	{
+		mPreviewMedia->navigateTo( mHomeURL->getValue().asString() );
+	}
+	else
+	// new home URL will be empty if media is deleted but
+	// we still need to clean out the preview.
+	{
+		mPreviewMedia->unloadMediaSource();
+	};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Helper to set current URL
+void LLPanelMediaSettingsGeneral::updateCurrentURL()
+{
+	if( mCurrentURL->getText().empty() )
+	{
+		childSetText( "current_url", mHomeURL->getText() );
+	}
+	
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// virtual
+void LLPanelMediaSettingsGeneral::onClose(bool app_quitting)
+{
+	if(mPreviewMedia)
+	{
+		mPreviewMedia->unloadMediaSource();
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata )
+{
+	LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata;
+
+	// check url user is trying to enter for home URL will pass whitelist 
+	// and decline to accept it if it doesn't.
+	std::string home_url = self->mHomeURL->getValue().asString();
+	if ( ! self->mParent->passesWhiteList( home_url ) )
+	{
+		LLNotifications::instance().add("WhiteListInvalidatesHomeUrl");		
+		return;
+	};
+	
+	self->updateMediaPreview();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl(LLUICtrl* ctrl, void *userdata)
+{
+	LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata;
+	self->navigateHomeSelectedFace();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsGeneral::apply( void* userdata )
+{
+	LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata;
+	self->mHomeURL->onCommit();
+	// build LLSD Fragment
+	LLSD media_data_general;
+	self->getValues(media_data_general);
+
+	// this merges contents of LLSD passed in with what's there so this is ok
+	LLSelectMgr::getInstance()->selectionSetMediaData( media_data_general );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in )
+{
+    fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = mAutoLoop->getValue();
+    fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = mAutoPlay->getValue();
+    fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = mAutoScale->getValue();
+    fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = mAutoZoom->getValue();
+    fill_me_in[LLMediaEntry::CONTROLS_KEY] = mControls->getCurrentIndex();
+    fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue();
+    fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = mHeightPixels->getValue();
+    fill_me_in[LLMediaEntry::HOME_URL_KEY] = mHomeURL->getValue();
+    fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = mFirstClick->getValue();
+    fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = mWidthPixels->getValue();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent )
+{
+	mParent = parent;
+};
+
+bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace()
+{
+	// HACK: This is directly referencing an impl name.  BAD!
+	// This can be removed when we have a truly generic media browser that only 
+	// builds an impl based on the type of url it is passed.
+	struct functor_navigate_media : public LLSelectedTEGetFunctor< bool>
+	{
+		bool get( LLViewerObject* object, S32 face )
+		{
+			if ( object )
+				if ( object->getTE(face) )
+					if ( object->getTE(face)->getMediaData() )
+					{
+						if(object->permModify())
+						{
+							viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID());
+							if(media_impl)
+							{
+								media_impl->navigateHome();
+								return true;
+							}
+						}	
+					}
+		   return false;
+		 };
+				
+	} functor_navigate_media;
+	
+	bool all_face_media_navigated = false;
+	LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection();
+	selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated );
+	
+	return all_face_media_navigated;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+const std::string LLPanelMediaSettingsGeneral::getHomeUrl()
+{
+	return mHomeURL->getValue().asString(); 
+}
+
diff --git a/indra/newview/llpanelmediasettingsgeneral.h b/indra/newview/llpanelmediasettingsgeneral.h
index 1b60909786aee182d2baf2e775df37301a202f51..e82a31382ef6226e23da4513fe0b09d5a1959877 100644
--- a/indra/newview/llpanelmediasettingsgeneral.h
+++ b/indra/newview/llpanelmediasettingsgeneral.h
@@ -64,6 +64,8 @@ class LLPanelMediaSettingsGeneral : public LLPanel
 	bool navigateHomeSelectedFace();
 	void updateMediaPreview();
 	void updateCurrentURL();
+
+	const std::string getHomeUrl();
 	
 protected:
 	LLFloaterMediaSettings* mParent;
@@ -76,7 +78,6 @@ class LLPanelMediaSettingsGeneral : public LLPanel
 	LLComboBox* mControls;
 	LLCheckBoxCtrl* mAutoLoop;
 	LLCheckBoxCtrl* mFirstClick;
-//	LLTextureCtrl* mMediaPreview;
 	LLCheckBoxCtrl* mAutoZoom;
 	LLCheckBoxCtrl* mAutoPlay;
 	LLCheckBoxCtrl* mAutoScale;
@@ -84,7 +85,6 @@ class LLPanelMediaSettingsGeneral : public LLPanel
 	LLSpinCtrl* mHeightPixels;
 	LLLineEditor* mHomeURL;
 	LLLineEditor* mCurrentURL;
-	LLCheckBoxCtrl* mAltImageEnable;
 	LLMediaCtrl* mPreviewMedia;
 };
 
diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp
index cea105d7de3f5a8b35a2486f4439cf420cda9d47..f5607aa2874e03a6e21e62f84dfedfd907262792 100644
--- a/indra/newview/llpanelmediasettingssecurity.cpp
+++ b/indra/newview/llpanelmediasettingssecurity.cpp
@@ -1,255 +1,343 @@
-/**
- * @file llpanelmediasettingssecurity.cpp
- * @brief LLPanelMediaSettingsSecurity class implementation
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * 
- * Copyright (c) 2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llfloaterreg.h"
-#include "llpanelmediasettingssecurity.h"
-#include "llpanelcontents.h"
-#include "llcheckboxctrl.h"
-#include "llscrolllistctrl.h"
-#include "llscrolllistitem.h"
-#include "lluictrlfactory.h"
-#include "llwindow.h"
-#include "llviewerwindow.h"
-#include "llsdutil.h"
-#include "llselectmgr.h"
-#include "llmediaentry.h"
-#include "llfloaterwhitelistentry.h"
-#include "llfloatermediasettings.h"
-////////////////////////////////////////////////////////////////////////////////
-//
-LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity()
-{
-	// build dialog from XML
-	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml");
-	mCommitCallbackRegistrar.add("Media.whitelistAdd",		boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this));
-	mCommitCallbackRegistrar.add("Media.whitelistDelete",	boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this));	
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-BOOL LLPanelMediaSettingsSecurity::postBuild()
-{
-	mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY );
-	mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY );
-
-	childSetAction("whitelist_add", onBtnAdd, this);
-	childSetAction("whitelist_del", onBtnDel, this);
-
-	setDefaultBtn("whitelist_add");
-
-	return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity()
-{
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// 
-void LLPanelMediaSettingsSecurity::draw()
-{
-	// housekeeping
-	LLPanel::draw();
-
-	// if list is empty, disable DEL button and checkbox to enable use of list
-	if ( mWhiteListList->isEmpty() )
-	{
-		childSetEnabled( "whitelist_del", false );
-		childSetEnabled( LLMediaEntry::WHITELIST_KEY, false );
-		childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false );
-	}
-	else
-	{
-		childSetEnabled( "whitelist_del", true );
-		childSetEnabled( LLMediaEntry::WHITELIST_KEY, true );
-		childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true );
-	};
-
-	// if nothing is selected, disable DEL button
-	if ( mWhiteListList->getSelectedValue().asString().empty() )
-	{
-		childSetEnabled( "whitelist_del", false );
-	}
-	else
-	{
-		childSetEnabled( "whitelist_del", true );
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static 
-void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable)
-{
-	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
-
-	if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
-	{
-		if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) 
-		{
-			self->clearValues(self, editable);
-			// only show multiple 
-			return;
-		}
-		
-	}
-	else
-	{
-		if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) 
-		{
-			self->clearValues(self, editable);
-			// only show multiple 
-			return;
-		}			
-		
-	}
-	std::string base_key( "" );
-	std::string tentative_key( "" );
-
-	struct 
-	{
-		std::string key_name;
-		LLUICtrl* ctrl_ptr;
-		std::string ctrl_type;
-
-	} data_set [] = 
+/**
+ * @file llpanelmediasettingssecurity.cpp
+ * @brief LLPanelMediaSettingsSecurity class implementation
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloaterreg.h"
+#include "llpanelmediasettingssecurity.h"
+#include "llpanelcontents.h"
+#include "llcheckboxctrl.h"
+#include "llscrolllistctrl.h"
+#include "llscrolllistitem.h"
+#include "lluictrlfactory.h"
+#include "llwindow.h"
+#include "llviewerwindow.h"
+#include "llsdutil.h"
+#include "llselectmgr.h"
+#include "llmediaentry.h"
+#include "llfloaterwhitelistentry.h"
+#include "llfloatermediasettings.h"
+////////////////////////////////////////////////////////////////////////////////
+//
+LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() :
+	mParent( NULL )
+{
+	// build dialog from XML
+	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml");
+	mCommitCallbackRegistrar.add("Media.whitelistAdd",		boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this));
+	mCommitCallbackRegistrar.add("Media.whitelistDelete",	boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this));	
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLPanelMediaSettingsSecurity::postBuild()
+{
+	mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY );
+	mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY );
+
+	childSetAction("whitelist_add", onBtnAdd, this);
+	childSetAction("whitelist_del", onBtnDel, this);
+
+	setDefaultBtn("whitelist_add");
+
+	return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// virtual
+LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// 
+void LLPanelMediaSettingsSecurity::draw()
+{
+	// housekeeping
+	LLPanel::draw();
+
+	// if list is empty, disable DEL button and checkbox to enable use of list
+	if ( mWhiteListList->isEmpty() )
+	{
+		childSetEnabled( "whitelist_del", false );
+		childSetEnabled( LLMediaEntry::WHITELIST_KEY, false );
+		childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false );
+	}
+	else
+	{
+		childSetEnabled( "whitelist_del", true );
+		childSetEnabled( LLMediaEntry::WHITELIST_KEY, true );
+		childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true );
+	};
+
+	// if nothing is selected, disable DEL button
+	if ( mWhiteListList->getSelectedValue().asString().empty() )
+	{
+		childSetEnabled( "whitelist_del", false );
+	}
+	else
+	{
+		childSetEnabled( "whitelist_del", true );
+	};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static 
+void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable)
+{
+	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+
+	if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
+	{
+		if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) 
+		{
+			self->clearValues(self, editable);
+			// only show multiple 
+			return;
+		}
+		
+	}
+	else
+	{
+		if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) 
+		{
+			self->clearValues(self, editable);
+			// only show multiple 
+			return;
+		}			
+		
+	}
+	std::string base_key( "" );
+	std::string tentative_key( "" );
+
+	struct 
+	{
+		std::string key_name;
+		LLUICtrl* ctrl_ptr;
+		std::string ctrl_type;
+
+	} data_set [] = 
+	{
+		{ LLMediaEntry::WHITELIST_ENABLE_KEY,	self->mEnableWhiteList,		"LLCheckBoxCtrl" },
+		{ LLMediaEntry::WHITELIST_KEY,			self->mWhiteListList,		"LLScrollListCtrl" },
+		{ "", NULL , "" }
+	};
+
+	for( int i = 0; data_set[ i ].key_name.length() > 0; ++i )
+	{
+		base_key = std::string( data_set[ i ].key_name );
+        tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX );
+
+		// TODO: CP - I bet there is a better way to do this using Boost
+		if ( media_settings[ base_key ].isDefined() )
+		{
+			if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" )
+			{
+				static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )->
+					setValue( media_settings[ base_key ].asBoolean() );
+			}
+			else
+			if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" )
+			{
+				// get control 
+				LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr );
+				list->deleteAllItems();
+
+				// points to list of white list URLs
+				LLSD url_list = media_settings[ base_key ];
+
+				// iterate over them and add to scroll list
+				LLSD::array_iterator iter = url_list.beginArray();
+				while( iter != url_list.endArray() )
+				{
+					// TODO: is iter guaranteed to be valid here?
+					std::string url = *iter;
+					list->addSimpleElement( url );
+					++iter;
+				};
+			};
+			data_set[ i ].ctrl_ptr->setEnabled(editable);
+			data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
+		};
+	};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static 
+void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable)
+{
+	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+	self->mEnableWhiteList->clear();
+	self->mWhiteListList->deleteAllItems();
+	self->mEnableWhiteList->setEnabled(editable);
+	self->mWhiteListList->setEnabled(editable);
+}
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::apply( void* userdata )
+{
+	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+
+	// build LLSD Fragment
+	LLSD media_data_security;
+	self->getValues(media_data_security);
+	// this merges contents of LLSD passed in with what's there so this is ok
+	LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in )
+{
+    fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue();
+
+    // iterate over white list and extract items
+    std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData();
+    std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin();
+    fill_me_in[LLMediaEntry::WHITELIST_KEY].clear();
+    while( iter != white_list_items.end() )
+    {
+        std::string white_list_url = (*iter)->getValue().asString();
+        fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url );
+        ++iter;
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Try to make a valid URL if a fragment (
+// white list list box widget and build a list to test against. Can also
+const std::string LLPanelMediaSettingsSecurity::makeValidUrl( const std::string& src_url )
+{
+	// use LLURI to determine if we have a valid scheme
+	LLURI candidate_url( src_url );
+	if ( candidate_url.scheme().empty() )
 	{
-		{ LLMediaEntry::WHITELIST_ENABLE_KEY,	self->mEnableWhiteList,		"LLCheckBoxCtrl" },
-		{ LLMediaEntry::WHITELIST_KEY,			self->mWhiteListList,		"LLScrollListCtrl" },
-		{ "", NULL , "" }
+		// build a URL comprised of default scheme and the original fragment 
+		const std::string default_scheme( "http://" );
+		return default_scheme + src_url;
 	};
 
-	for( int i = 0; data_set[ i ].key_name.length() > 0; ++i )
-	{
-		base_key = std::string( data_set[ i ].key_name );
-        tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX );
-
-		// TODO: CP - I bet there is a better way to do this using Boost
-		if ( media_settings[ base_key ].isDefined() )
-		{
-			if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" )
-			{
-				static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )->
-					setValue( media_settings[ base_key ].asBoolean() );
-			}
-			else
-			if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" )
-			{
-				// get control 
-				LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr );
-				list->deleteAllItems();
-
-				// points to list of white list URLs
-				LLSD url_list = media_settings[ base_key ];
-
-				// iterate over them and add to scroll list
-				LLSD::array_iterator iter = url_list.beginArray();
-				while( iter != url_list.endArray() )
-				{
-					// TODO: is iter guaranteed to be valid here?
-					std::string url = *iter;
-					list->addSimpleElement( url );
-					++iter;
-				};
-			};
-			data_set[ i ].ctrl_ptr->setEnabled(editable);
-			data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static 
-void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable)
-{
-	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
-	self->mEnableWhiteList->clear();
-	self->mWhiteListList->deleteAllItems();
-	self->mEnableWhiteList->setEnabled(editable);
-	self->mWhiteListList->setEnabled(editable);
-}
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::apply( void* userdata )
-{
-	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
-
-	// build LLSD Fragment
-	LLSD media_data_security;
-	self->getValues(media_data_security);
-	// this merges contents of LLSD passed in with what's there so this is ok
-	LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security );
-}
-
+	// we *could* test the "default scheme" + "original fragment" URL again
+	// using LLURI to see if it's valid but I think the outcome is the same
+	// in either case - our only option is to return the original URL
+
+	// we *think* the original url passed in was valid
+	return src_url;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// wrapper for testing a URL against the whitelist. We grab entries from
+// white list list box widget and build a list to test against. Can also
+// optionally pass the URL that you are trying to add to the widget since
+// it won't be added until this call returns.
+bool LLPanelMediaSettingsSecurity::passesWhiteList( const std::string& added_url,
+													const std::string& test_url )
+{
+	// the checkUrlAgainstWhitelist(..) function works on a vector
+	// of strings for the white list entries - in this panel, the white list
+	// is stored in the widgets themselves so we need to build something compatible.
+	std::vector< std::string > whitelist_strings;
+	whitelist_strings.clear();	// may not be required - I forget what the spec says.
+
+	// step through whitelist widget entries and grab them as strings
+    std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData();
+    std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); 
+	while( iter != white_list_items.end()  )
+    {
+        const std::string whitelist_url = (*iter)->getValue().asString();
+		whitelist_strings.push_back( whitelist_url );
+
+		++iter;
+    };
+
+	// add in the URL that might be added to the whitelist so we can test that too
+	if ( added_url.length() )
+		whitelist_strings.push_back( added_url );
+
+	// possible the URL is just a fragment so we validize it
+	const std::string valid_url = makeValidUrl( test_url );
+
+	// indicate if the URL passes whitelist
+	return LLMediaEntry::checkUrlAgainstWhitelist( valid_url, whitelist_strings );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url)
+{
+	// grab home URL from the general panel (via the parent floater)
+	std::string home_url( "" );
+	if ( mParent )
+		home_url = mParent->getHomeUrl();
+
+	// if the home URL is blank (user hasn't entered it yet) then
+	// don't bother to check if it passes the white list
+	if ( home_url.empty() )
+	{
+		mWhiteListList->addSimpleElement( url );
+		return;
+	};
+
+	// if the URL passes the white list, add it
+	if ( passesWhiteList( url, home_url ) )
+	{
+		mWhiteListList->addSimpleElement( url );
+	}
+	else
+	// display a message indicating you can't do that
+	{
+		LLNotifications::instance().add("WhiteListInvalidatesHomeUrl");
+	};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata )
+{
+	LLFloaterReg::showInstance("whitelist_entry");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata )
+{
+	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+
+	self->mWhiteListList->deleteSelectedItems();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 //
-void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in )
-{
-    fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue();
-
-    // iterate over white list and extract items
-    std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData();
-    std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin();
-    fill_me_in[LLMediaEntry::WHITELIST_KEY].clear();
-    while( iter != white_list_items.end() )
-    {
-        std::string white_list_url = (*iter)->getValue().asString();
-        fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url );
-        ++iter;
-    };
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url)
-{
-	mWhiteListList->addSimpleElement( url );
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata )
-{
-	LLFloaterReg::showInstance("whitelist_entry");
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata )
+void LLPanelMediaSettingsSecurity::setParent( LLFloaterMediaSettings* parent )
 {
-	LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+	mParent = parent;
+};
 
-	self->mWhiteListList->deleteSelectedItems();
-}
diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h
index b7cf67c0391813749188108e4720b08573725496..b78ee921937e9829eb4ded4a7a62c1bda0be8ba4 100644
--- a/indra/newview/llpanelmediasettingssecurity.h
+++ b/indra/newview/llpanelmediasettingssecurity.h
@@ -37,6 +37,7 @@
 
 class LLCheckBoxCtrl;
 class LLScrollListCtrl;
+class LLFloaterMediaSettings;
 
 class LLPanelMediaSettingsSecurity : public LLPanel
 {
@@ -52,6 +53,12 @@ class LLPanelMediaSettingsSecurity : public LLPanel
 		static void initValues( void* userdata, const LLSD& media_settings,bool editable );
 		static void clearValues( void* userdata, bool editable);
 		void addWhiteListItem(const std::string& url);
+		void setParent( LLFloaterMediaSettings* parent );
+		const std::string makeValidUrl( const std::string& src_url );
+		bool passesWhiteList( const std::string& added_url, const std::string& test_url );
+
+	protected:
+		LLFloaterMediaSettings* mParent;
 
 	private:
 		LLCheckBoxCtrl* mEnableWhiteList;
diff --git a/indra/newview/llpanelplace.cpp b/indra/newview/llpanelplace.cpp
index c6840721a31ba65d3748009196f798e8c70ce783..61e18195b83e700d0feeece8ddc9d3ea32b62b75 100644
--- a/indra/newview/llpanelplace.cpp
+++ b/indra/newview/llpanelplace.cpp
@@ -58,6 +58,7 @@
 //#include "llviewermenu.h"	// create_landmark()
 #include "llweb.h"
 #include "llsdutil.h"
+#include "llsdutil_math.h"
 
 LLPanelPlace::LLPanelPlace()
 :	LLPanel(),
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index 609b2059209f635a0b3fd4cf4c0ed7aaf91b5aab..cb9f7184f01dfad38ec6cd321249b96c2d4b53e6 100644
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -67,6 +67,7 @@
 #include "llviewerregion.h"
 #include "llviewertexteditor.h"
 #include "llworldmap.h"
+#include "llsdutil_math.h"
 
 //----------------------------------------------------------------------------
 // Aux types and methods
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index a7f0ce16d38611ff8146e20d73bf9b6172b4bbcc..d68897b64f6a79465af1d0a8048a5fdc920d1fa9 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -4905,7 +4905,6 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud)
 		{
 			inspect_item_id = inspect_instance->getSelectedUUID();
 		}
-		LLUUID focus_item_id = LLViewerMediaFocus::getInstance()->getSelectedUUID();
 		for (S32 pass = 0; pass < 2; pass++)
 		{
 			for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
@@ -4919,11 +4918,7 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud)
 				{
 					continue;
 				}
-				if (objectp->getID() == focus_item_id)
-				{
-					node->renderOneSilhouette(gFocusMgr.getFocusColor());
-				}
-				else if(objectp->getID() == inspect_item_id)
+				if(objectp->getID() == inspect_item_id)
 				{
 					node->renderOneSilhouette(sHighlightInspectColor);
 				}
@@ -4977,6 +4972,19 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud)
 		}
 	}
 
+#if 0	
+	// Hilight focused media object
+	{
+		LLViewerObject* objectp = LLViewerMediaFocus::getInstance()->getFocusedObject();
+		if(objectp)
+		{
+			// FIXME: how do I construct a silhouette for an object that's not selected?
+			// Would we need to add another LLObjectSelectionHandle for this purpose?
+			node->renderOneSilhouette(gFocusMgr.getFocusColor());
+		}
+	}
+#endif
+
 	if (for_hud && avatar)
 	{
 		glMatrixMode(GL_PROJECTION);
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 329d7d26ee0aadc33fb30fdd9fc15ac244d3a46e..22c3779050aff5f0549784cf9090bb28a7c1c5d9 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -111,12 +111,72 @@ bool	LLSideTray::instanceCreated	()
 	return sInstance!=0;
 }
 
-LLSideTrayTab::LLSideTrayTab(const Params& params):mMainPanel(0)
+//////////////////////////////////////////////////////////////////////////////
+// LLSideTrayTab
+// Represents a single tab in the side tray, only used by LLSideTray
+//////////////////////////////////////////////////////////////////////////////
+
+class LLSideTrayTab: public LLPanel
 {
-	mImagePath = params.image_path;
-	mTabTitle = params.tab_title;
-	mDescription = params.description;
+	friend class LLUICtrlFactory;
+	friend class LLSideTray;
+public:
+	
+	struct Params 
+	:	public LLInitParam::Block<Params, LLPanel::Params>
+	{
+		// image name
+		Optional<std::string>		image;
+		Optional<std::string>		image_selected;
+		Optional<std::string>		tab_title;
+		Optional<std::string>		description;
+		Params()
+		:	image("image"),
+			image_selected("image_selected"),
+			tab_title("tab_title","no title"),
+			description("description","no description")
+		{};
+	};
+protected:
+	LLSideTrayTab(const Params& params);
+	
+	
+public:
+	virtual ~LLSideTrayTab();
+	
+    /*virtual*/ BOOL	postBuild	();
+	/*virtual*/ bool	addChild	(LLView* view, S32 tab_group);
+	
+	
+	void			arrange		(S32 width, S32 height);
+	void			reshape		(S32 width, S32 height, BOOL called_from_parent = TRUE);
+	
+	static LLSideTrayTab*  createInstance	();
+	
+	const std::string& getDescription () const { return mDescription;}
+	const std::string& getTabTitle() const { return mTabTitle;}
+	
+	void draw();
+	
+	void			onOpen		(const LLSD& key);
+	
+private:
+	std::string mTabTitle;
+	std::string mImage;
+	std::string mImageSelected;
+	std::string	mDescription;
+	
+	LLView*	mMainPanel;
+};
 
+LLSideTrayTab::LLSideTrayTab(const Params& p)
+:	LLPanel(),
+	mTabTitle(p.tab_title),
+	mImage(p.image),
+	mImageSelected(p.image_selected),
+	mDescription(p.description),
+	mMainPanel(NULL)
+{
 	// Necessary for focus movement among child controls
 	setFocusRoot(TRUE);
 }
@@ -221,6 +281,18 @@ LLSideTrayTab*  LLSideTrayTab::createInstance	()
 	return tab;
 }
 
+//////////////////////////////////////////////////////////////////////////////
+// LLSideTray
+//////////////////////////////////////////////////////////////////////////////
+
+LLSideTray::Params::Params()
+:	collapsed("collapsed",false),
+	tab_btn_image_normal("tab_btn_image","sidebar_tab_left.tga"),
+	tab_btn_image_selected("tab_btn_image_selected","button_enabled_selected_32x128.tga"),
+	default_button_width("tab_btn_width",32),
+	default_button_height("tab_btn_height",32),
+	default_button_margin("tab_btn_margin",0)
+{}
 
 //virtual 
 LLSideTray::LLSideTray(Params& params)
@@ -255,35 +327,6 @@ BOOL LLSideTray::postBuild()
 	setMouseOpaque(false);
 	return true;
 }
-    
-/**
- * add new panel to tab with tab_name name
- * @param tab_name - name of sidebar tab to add new panel
- * @param panel - pointer to panel 
- */
-bool        LLSideTray::addPanel        ( const std::string& tab_name
-										,LLPanel* panel )
-{
-	return false;
-}
-/**
- * Add new tab to side bar
- * @param tab_name - name of the new tab
- * @param image - image for new sidebar button
- * @param title -  title for new tab
- */
-bool        LLSideTray::addTab          ( const std::string& tab_name
-										,const std::string& image
-										,const std::string& title)
-{
-	LLSideTrayTab::Params params;
-	params.image_path = image;
-	params.tab_title = title;
-	LLSideTrayTab* tab = LLUICtrlFactory::create<LLSideTrayTab> (params);
-	addChild(tab,1);
-	return true;
-}
-
 
 LLSideTrayTab* LLSideTray::getTab(const std::string& name)
 {
@@ -291,7 +334,6 @@ LLSideTrayTab* LLSideTray::getTab(const std::string& name)
 }
 
 
-
 void LLSideTray::toggleTabButton	(LLSideTrayTab* tab)
 {
 	if(tab == NULL)
@@ -393,25 +435,30 @@ bool LLSideTray::addChild(LLView* view, S32 tab_group)
 
 void	LLSideTray::createButtons	()
 {
-	//create show/hide button
-	mCollapseButton = createButton(EXPANDED_NAME,"",boost::bind(&LLSideTray::onToggleCollapse, this));
-
 	//create buttons for tabs
 	child_vector_const_iter_t child_it = mTabs.begin();
-	++child_it;
-
 	for ( ; child_it != mTabs.end(); ++child_it)
 	{
 		LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it);
 		if(sidebar_tab == NULL)
 			continue;
 
-		string name = sidebar_tab->getName();
+		std::string name = sidebar_tab->getName();
 		
-		LLButton* button = createButton("",sidebar_tab->mImagePath,boost::bind(&LLSideTray::onTabButtonClick, this, sidebar_tab->getName()));
-		mTabButtons[sidebar_tab->getName()] = button;
+		// The "home" button will open/close the whole panel, this will need to
+		// change if the home screen becomes its own tab.
+		if (name == "sidebar_home")
+		{
+			mCollapseButton = createButton("",sidebar_tab->mImage,
+				boost::bind(&LLSideTray::onToggleCollapse, this));
+		}
+		else
+		{
+			LLButton* button = createButton("",sidebar_tab->mImage,
+				boost::bind(&LLSideTray::onTabButtonClick, this, name));
+			mTabButtons[name] = button;
+		}
 	}
-	
 }
 
 void		LLSideTray::onTabButtonClick(string name)
@@ -514,25 +561,33 @@ void LLSideTray::arrange			()
 	}
 }
 
-void LLSideTray::collapseSideBar	()
+void LLSideTray::collapseSideBar()
 {
 	mCollapsed = true;
-	mCollapseButton->setLabel(COLLAPSED_NAME);
+	LLSideTrayTab* home_tab = getTab("sidebar_home");
+	if (home_tab)
+	{
+		mCollapseButton->setImageOverlay( home_tab->mImage );
+	}
 	mActiveTab->setVisible(FALSE);
 	reflectCollapseChange();
 	setFocus( FALSE );
 
 }
-void LLSideTray::expandSideBar	()
+
+void LLSideTray::expandSideBar()
 {
 	mCollapsed = false;
-	mCollapseButton->setLabel(EXPANDED_NAME);
+	LLSideTrayTab* home_tab = getTab("sidebar_home");
+	if (home_tab)
+	{
+		mCollapseButton->setImageOverlay( home_tab->mImageSelected );
+	}
 	LLSD key;//empty
 	mActiveTab->onOpen(key);
 	mActiveTab->setVisible(TRUE);
 
 	reflectCollapseChange();
-
 }
 
 void LLSideTray::highlightFocused()
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 6ea6bafac95b40af2ca27a2db7e9d847377317af..845eb86bc13ce6f7b80f81f05cf19774522be0e5 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -36,59 +36,9 @@
 #include "llpanel.h"
 #include "string"
 
-class LLSideTray;
+class LLSideTrayTab;
 class LLAccordionCtrl;
 
-class LLSideTrayTab: public LLPanel
-{
-	friend class LLUICtrlFactory;
-	friend class LLSideTray;
-public:
-
-	struct Params 
-	:	public LLInitParam::Block<Params, LLPanel::Params>
-	{
-		// image name
-		Optional<std::string>		image_path;
-		Optional<std::string>		tab_title;
-		Optional<std::string>		description;
-		Params()
-		:	image_path("image"),
-			tab_title("tab_title","no title"),
-			description("description","no description")
-		{};
-	};
-protected:
-	LLSideTrayTab(const Params& params);
-	
-
-public:
-	virtual ~LLSideTrayTab();
-
-    /*virtual*/ BOOL	postBuild	();
-	/*virtual*/ bool	addChild	(LLView* view, S32 tab_group);
-
-
-	void			arrange		(S32 width, S32 height);
-	void			reshape		(S32 width, S32 height, BOOL called_from_parent = TRUE);
-	
-	static LLSideTrayTab*  createInstance	();
-
-	const std::string& getDescription () const { return mDescription;}
-	const std::string& getTabTitle() const { return mTabTitle;}
-
-	void draw();
-
-	void			onOpen		(const LLSD& key);
-
-private:
-	std::string mTabTitle;
-	std::string mImagePath;
-	std::string	mDescription;
-
-	LLView*	mMainPanel;
-};
-
 // added inheritance from LLDestroyClass<LLSideTray> to enable Side Tray perform necessary actions 
 // while disconnecting viewer in LLAppViewer::disconnectViewer().
 // LLDestroyClassList::instance().fireCallbacks() calls destroyClass method. See EXT-245.
@@ -112,14 +62,7 @@ class LLSideTray : public LLPanel, private LLDestroyClass<LLSideTray>
 		Optional<S32>				default_button_height;
 		Optional<S32>				default_button_margin;
 		
-		Params()
-		:	collapsed("collapsed",false),
-			tab_btn_image_normal("tab_btn_image","sidebar_tab_left.tga"),
-			tab_btn_image_selected("tab_btn_image_selected","button_enabled_selected_32x128.tga"),
-			default_button_width("tab_btn_width",32),
-			default_button_height("tab_btn_height",32),
-			default_button_margin("tab_btn_margin",0)
-		{};
+		Params();
 	};
 
 	static LLSideTray*	getInstance		();
@@ -146,23 +89,6 @@ class LLSideTray : public LLPanel, private LLDestroyClass<LLSideTray>
      */
 	bool		selectTabByIndex(size_t index);
 
-    /**
-     * add new panel to tab with tab_name name
-     * @param tab_name - name of sidebar tab to add new panel
-     * @param panel - pointer to panel 
-     */
-    bool        addPanel        ( const std::string& tab_name
-                                 ,LLPanel* panel );
-    /**
-     * Add new tab to side bar
-     * @param tab_name - name of the new tab
-     * @param image - image for new sidebar button
-     * @param title -  title for new tab
-     */
-    bool        addTab          ( const std::string& tab_name
-                                 ,const std::string& image
-                                 ,const std::string& title);
-
 	/**
 	 * Activate tab with "panel_name" panel
 	 * if no such tab - return NULL, otherwise a pointer to the panel
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8793d226464cfe4a344c03aa2ce97ccdfda57a37..43b039f94ec06f18ba56a1b5de14a008b9f1872a 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -56,7 +56,6 @@
 #include "llcachename.h"
 #include "lldir.h"
 #include "llerrorcontrol.h"
-#include "llfiltersd2xmlrpc.h"
 #include "llfloaterreg.h"
 #include "llfocusmgr.h"
 #include "llhttpsender.h"
@@ -66,10 +65,11 @@
 #include "llmemorystream.h"
 #include "llmessageconfig.h"
 #include "llmoveview.h"
+#include "llteleporthistory.h"
 #include "llregionhandle.h"
 #include "llsd.h"
 #include "llsdserialize.h"
-#include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "llsecondlifeurls.h"
 #include "llstring.h"
 #include "lluserrelations.h"
@@ -103,7 +103,6 @@
 #include "llfloaterland.h"
 #include "llfloaterpreference.h"
 #include "llfloatertopobjects.h"
-#include "llfloatertos.h"
 #include "llfloaterworldmap.h"
 #include "llgesturemgr.h"
 #include "llgroupmgr.h"
@@ -116,6 +115,7 @@
 #include "llfriendcard.h"
 #include "llkeyboard.h"
 #include "llloginhandler.h"			// gLoginHandler, SLURL support
+#include "lllogininstance.h" // Host the login module.
 #include "llpanellogin.h"
 #include "llmutelist.h"
 #include "llnotify.h"
@@ -133,7 +133,6 @@
 #include "llsecondlifeurls.h"
 #include "llselectmgr.h"
 #include "llsky.h"
-#include "llsrv.h"
 #include "llstatview.h"
 #include "lltrans.h"
 #include "llstatusbar.h"		// sendMoneyBalanceRequest(), owns L$ balance
@@ -146,7 +145,6 @@
 #include "llurlsimstring.h"
 #include "llurlhistory.h"
 #include "llurlwhitelist.h"
-#include "lluserauth.h"
 #include "llvieweraudio.h"
 #include "llviewerassetstorage.h"
 #include "llviewercamera.h"
@@ -190,6 +188,9 @@
 #include "llappearancemgr.h"
 #include "llavatariconctrl.h"
 
+#include "lllogin.h"
+#include "llevents.h"
+
 #if LL_WINDOWS
 #include "llwindebug.h"
 #include "lldxhardware.h"
@@ -203,12 +204,12 @@
 // exported globals
 //
 bool gAgentMovementCompleted = false;
-std::string gInitialOutfit;
-std::string gInitialOutfitGender;
 
 std::string SCREEN_HOME_FILENAME = "screen_home.bmp";
 std::string SCREEN_LAST_FILENAME = "screen_last.bmp";
 
+LLPointer<LLViewerTexture> gStartTexture;
+
 //
 // Imported globals
 //
@@ -218,12 +219,6 @@ extern S32 gStartImageHeight;
 //
 // local globals
 //
-
-LLPointer<LLViewerTexture> gStartTexture;
-
-static LLHost gAgentSimHost;
-static BOOL gSkipOptionalUpdate = FALSE;
-
 static bool gGotUseCircuitCodeAck = false;
 static std::string sInitialOutfit;
 static std::string sInitialOutfitGender;	// "male" or "female"
@@ -232,6 +227,18 @@ static bool gUseCircuitCallbackCalled = false;
 
 EStartupState LLStartUp::gStartupState = STATE_FIRST;
 
+// *NOTE:Mani - to reconcile with giab changes...
+static std::string gFirstname;
+static std::string gLastname;
+static std::string gPassword;
+
+static U64 gFirstSimHandle = 0;
+static LLHost gFirstSim;
+static std::string gFirstSimSeedCap;
+static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f);
+static std::string gAgentStartLocation = "safe";
+
+static LLEventStream sStartupStateWatcher("StartupState");
 
 //
 // local function declaration
@@ -244,8 +251,6 @@ void show_first_run_dialog();
 bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);
 void set_startup_status(const F32 frac, const std::string& string, const std::string& msg);
 bool login_alert_status(const LLSD& notification, const LLSD& response);
-void update_app(BOOL mandatory, const std::string& message);
-bool update_dialog_callback(const LLSD& notification, const LLSD& response);
 void login_packet_failed(void**, S32 result);
 void use_circuit_callback(void**, S32 result);
 void register_viewer_callbacks(LLMessageSystem* msg);
@@ -255,6 +260,8 @@ void init_start_screen(S32 location_id);
 void release_start_screen();
 void reset_login();
 void apply_udp_blacklist(const std::string& csv);
+bool process_login_success_response();
+void transition_back_to_login_panel(const std::string& emsg);
 
 void callback_cache_name(const LLUUID& id, const std::string& firstname, const std::string& lastname, BOOL is_group)
 {
@@ -314,9 +321,6 @@ void update_texture_fetch()
 	gTextureList.updateImages(0.10f);
 }
 
-static std::vector<std::string> sAuthUris;
-static S32 sAuthUriNum = -1;
-
 //Copies landmarks from the "Library" to "My Favorites"
 void populate_favorites_bar()
 {
@@ -388,23 +392,11 @@ bool idle_startup()
 	// auth/transform loop will do.
 	static F32 progress = 0.10f;
 
-	static std::string auth_method;
 	static std::string auth_desc;
 	static std::string auth_message;
-	static std::string firstname;
-	static std::string lastname;
-	static LLUUID web_login_key;
-	static std::string password;
-	static std::vector<const char*> requested_options;
-
-	static U64 first_sim_handle = 0;
-	static LLHost first_sim;
-	static std::string first_sim_seed_cap;
 
 	static LLVector3 initial_sun_direction(1.f, 0.f, 0.f);
 	static LLVector3 agent_start_position_region(10.f, 10.f, 10.f);		// default for when no space server
-	static LLVector3 agent_start_look_at(1.0f, 0.f, 0.f);
-	static std::string agent_start_location = "safe";
 
 	// last location by default
 	static S32  agent_location_id = START_LOCATION_ID_LAST;
@@ -412,7 +404,7 @@ bool idle_startup()
 
 	static bool show_connect_box = true;
 
-	static bool stipend_since_login = false;
+	//static bool stipend_since_login = false;
 
 	// HACK: These are things from the main loop that usually aren't done
 	// until initialization is complete, but need to be done here for things
@@ -433,12 +425,7 @@ bool idle_startup()
 
 	LLStringUtil::setLocale (LLTrans::getString(system));
 
-	if (gNoRender)
-	{
-		// HACK, skip optional updates if you're running drones
-		gSkipOptionalUpdate = TRUE;
-	}
-	else
+	if (!gNoRender)
 	{
 		//note: Removing this line will cause incorrect button size in the login screen. -- bao.
 		gTextureList.updateImages(0.01f) ;
@@ -754,24 +741,23 @@ bool idle_startup()
 			|| !gLoginHandler.getWebLoginKey().isNull() )
 		{
 			// We have at least some login information on a SLURL
-			firstname = gLoginHandler.getFirstName();
-			lastname = gLoginHandler.getLastName();
-			web_login_key = gLoginHandler.getWebLoginKey();
+			gFirstname = gLoginHandler.getFirstName();
+			gLastname = gLoginHandler.getLastName();
 
 			// Show the login screen if we don't have everything
 			show_connect_box = 
-				firstname.empty() || lastname.empty() || web_login_key.isNull();
+				gFirstname.empty() || gLastname.empty();
 		}
         else if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
         {
             LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
-			firstname = cmd_line_login[0].asString();
-			lastname = cmd_line_login[1].asString();
+			gFirstname = cmd_line_login[0].asString();
+			gLastname = cmd_line_login[1].asString();
 
 			LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
 			char md5pass[33];               /* Flawfinder: ignore */
 			pass.hex_digest(md5pass);
-			password = md5pass;
+			gPassword = md5pass;
 			
 #ifdef USE_VIEWER_AUTH
 			show_connect_box = true;
@@ -782,9 +768,9 @@ bool idle_startup()
         }
 		else if (gSavedSettings.getBOOL("AutoLogin"))
 		{
-			firstname = gSavedSettings.getString("FirstName");
-			lastname = gSavedSettings.getString("LastName");
-			password = LLStartUp::loadPasswordFromDisk();
+			gFirstname = gSavedSettings.getString("FirstName");
+			gLastname = gSavedSettings.getString("LastName");
+			gPassword = LLStartUp::loadPasswordFromDisk();
 			gSavedSettings.setBOOL("RememberPassword", TRUE);
 			
 #ifdef USE_VIEWER_AUTH
@@ -797,9 +783,9 @@ bool idle_startup()
 		{
 			// if not automatically logging in, display login dialog
 			// a valid grid is selected
-			firstname = gSavedSettings.getString("FirstName");
-			lastname = gSavedSettings.getString("LastName");
-			password = LLStartUp::loadPasswordFromDisk();
+			gFirstname = gSavedSettings.getString("FirstName");
+			gLastname = gSavedSettings.getString("LastName");
+			gPassword = LLStartUp::loadPasswordFromDisk();
 			show_connect_box = true;
 		}
 
@@ -835,7 +821,7 @@ bool idle_startup()
 			// Load all the name information out of the login view
 			// NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't
 			// show the login view until login_show() is called below.  
-			// LLPanelLogin::getFields(firstname, lastname, password);
+			// LLPanelLogin::getFields(gFirstname, gLastname, gPassword);
 
 			if (gNoRender)
 			{
@@ -847,7 +833,7 @@ bool idle_startup()
 			// Show the login dialog
 			login_show();
 			// connect dialog is already shown, so fill in the names
-			LLPanelLogin::setFields( firstname, lastname, password);
+			LLPanelLogin::setFields( gFirstname, gLastname, gPassword);
 
 			LLPanelLogin::giveFocus();
 
@@ -911,34 +897,34 @@ bool idle_startup()
 		//reset the values that could have come in from a slurl
 		if (!gLoginHandler.getWebLoginKey().isNull())
 		{
-			firstname = gLoginHandler.getFirstName();
-			lastname = gLoginHandler.getLastName();
-			web_login_key = gLoginHandler.getWebLoginKey();
+			gFirstname = gLoginHandler.getFirstName();
+			gLastname = gLoginHandler.getLastName();
+//			gWebLoginKey = gLoginHandler.getWebLoginKey();
 		}
 				
 		if (show_connect_box)
 		{
 			// TODO if not use viewer auth
 			// Load all the name information out of the login view
-			LLPanelLogin::getFields(&firstname, &lastname, &password);
+			LLPanelLogin::getFields(&gFirstname, &gLastname, &gPassword);
 			// end TODO
 	 
 			// HACK: Try to make not jump on login
 			gKeyboard->resetKeys();
 		}
 
-		if (!firstname.empty() && !lastname.empty())
+		if (!gFirstname.empty() && !gLastname.empty())
 		{
-			gSavedSettings.setString("FirstName", firstname);
-			gSavedSettings.setString("LastName", lastname);
+			gSavedSettings.setString("FirstName", gFirstname);
+			gSavedSettings.setString("LastName", gLastname);
 
-			LL_INFOS("AppInit") << "Attempting login as: " << firstname << " " << lastname << LL_ENDL;
-			gDebugInfo["LoginName"] = firstname + " " + lastname;	
+			LL_INFOS("AppInit") << "Attempting login as: " << gFirstname << " " << gLastname << LL_ENDL;
+			gDebugInfo["LoginName"] = gFirstname + " " + gLastname;	
 		}
 
 		// create necessary directories
 		// *FIX: these mkdir's should error check
-		gDirUtilp->setLindenUserDir(firstname, lastname);
+		gDirUtilp->setLindenUserDir(gFirstname, gLastname);
     	LLFile::mkdir(gDirUtilp->getLindenUserDir());
 
         // Set PerAccountSettingsFile to the default value.
@@ -972,7 +958,7 @@ bool idle_startup()
 			gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));		
 		}
 		
-		gDirUtilp->setPerAccountChatLogsDir(firstname, lastname);
+		gDirUtilp->setPerAccountChatLogsDir(gFirstname, gLastname);
 
 		LLFile::mkdir(gDirUtilp->getChatLogsDir());
 		LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
@@ -1000,13 +986,6 @@ bool idle_startup()
 
 		if (show_connect_box)
 		{
-			if ( LLPanelLogin::isGridComboDirty() )
-			{
-				// User picked a grid from the popup, so clear the 
-				// stored uris and they will be reacquired from the grid choice.
-				sAuthUris.clear();
-			}
-			
 			std::string location;
 			LLPanelLogin::getLocation( location );
 			LLURLSimString::setString( location );
@@ -1038,7 +1017,7 @@ bool idle_startup()
 			agent_location_id = START_LOCATION_ID_URL;
 
 			// doesn't really matter what location_which is, since
-			// agent_start_look_at will be overwritten when the
+			// gAgentStartLookAt will be overwritten when the
 			// UserLoginLocationReply arrives
 			location_which = START_LOCATION_ID_LAST;
 		}
@@ -1071,616 +1050,138 @@ bool idle_startup()
 
 		gVFS->pokeFiles();
 
-		// skipping over STATE_UPDATE_CHECK because that just waits for input
 		LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT );
 
 		return FALSE;
 	}
 
-	if (STATE_UPDATE_CHECK == LLStartUp::getStartupState())
-	{
-		// wait for user to give input via dialog box
-		return FALSE;
-	}
-
 	if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())
 	{
-//#define LL_MINIMIAL_REQUESTED_OPTIONS
 		gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
 
-		// *Note: this is where gUserAuth used to be created.
-		requested_options.clear();
-		requested_options.push_back("inventory-root");
-		requested_options.push_back("inventory-skeleton");
-		//requested_options.push_back("inventory-meat");
-		//requested_options.push_back("inventory-skel-targets");
-#if (!defined LL_MINIMIAL_REQUESTED_OPTIONS)
-		if(FALSE == gSavedSettings.getBOOL("NoInventoryLibrary"))
-		{
-			requested_options.push_back("inventory-lib-root");
-			requested_options.push_back("inventory-lib-owner");
-			requested_options.push_back("inventory-skel-lib");
-		//	requested_options.push_back("inventory-meat-lib");
-		}
-
-		requested_options.push_back("initial-outfit");
-		requested_options.push_back("gestures");
-		requested_options.push_back("event_categories");
-		requested_options.push_back("event_notifications");
-		requested_options.push_back("classified_categories");
-		requested_options.push_back("adult_compliant"); 
-		//requested_options.push_back("inventory-targets");
-		requested_options.push_back("buddy-list");
-		requested_options.push_back("ui-config");
-#endif
-		requested_options.push_back("tutorial_setting");
-		requested_options.push_back("login-flags");
-		requested_options.push_back("global-textures");
-		if(gSavedSettings.getBOOL("ConnectAsGod"))
-		{
-			gSavedSettings.setBOOL("UseDebugMenus", TRUE);
-			requested_options.push_back("god-connect");
-		}
-		std::vector<std::string> uris;
-		LLViewerLogin::getInstance()->getLoginURIs(uris);
-		std::vector<std::string>::const_iterator iter, end;
-		for (iter = uris.begin(), end = uris.end(); iter != end; ++iter)
-		{
-			std::vector<std::string> rewritten;
-			rewritten = LLSRV::rewriteURI(*iter);
-			sAuthUris.insert(sAuthUris.end(),
-							 rewritten.begin(), rewritten.end());
-		}
-		sAuthUriNum = 0;
-		auth_method = "login_to_simulator";
-		
+		// Update progress status and the display loop.
 		auth_desc = LLTrans::getString("LoginInProgress");
-		LLStartUp::setStartupState( STATE_LOGIN_AUTHENTICATE );
-	}
-
-	if (STATE_LOGIN_AUTHENTICATE == LLStartUp::getStartupState())
-	{
-		LL_DEBUGS("AppInit") << "STATE_LOGIN_AUTHENTICATE" << LL_ENDL;
 		set_startup_status(progress, auth_desc, auth_message);
 		progress += 0.02f;
 		display_startup();
-		
-		std::stringstream start;
-		if (LLURLSimString::parse())
-		{
-			// a startup URL was specified
-			std::stringstream unescaped_start;
-			unescaped_start << "uri:" 
-							<< LLURLSimString::sInstance.mSimName << "&" 
-							<< LLURLSimString::sInstance.mX << "&" 
-							<< LLURLSimString::sInstance.mY << "&" 
-							<< LLURLSimString::sInstance.mZ;
-			start << xml_escape_string(unescaped_start.str());
-			
-		}
-		else
-		{
-			start << gSavedSettings.getString("LoginLocation");
-		}
-
-		char hashed_mac_string[MD5HEX_STR_SIZE];		/* Flawfinder: ignore */
-		LLMD5 hashed_mac;
-		hashed_mac.update( gMACAddress, MAC_ADDRESS_BYTES );
-		hashed_mac.finalize();
-		hashed_mac.hex_digest(hashed_mac_string);
-
-		// TODO if statement here to use web_login_key
-		sAuthUriNum = llclamp(sAuthUriNum, 0, (S32)sAuthUris.size()-1);
-		LLUserAuth::getInstance()->authenticate(
-			sAuthUris[sAuthUriNum],
-			auth_method,
-			firstname,
-			lastname,			
-			password, // web_login_key,
-			start.str(),
-			gSkipOptionalUpdate,
-			gAcceptTOS,
-			gAcceptCriticalMessage,
-			gLastExecEvent,
-			requested_options,
-			hashed_mac_string,
-			LLAppViewer::instance()->getSerialNumber());
-
-		// reset globals
-		gAcceptTOS = FALSE;
-		gAcceptCriticalMessage = FALSE;
-		LLStartUp::setStartupState( STATE_LOGIN_NO_DATA_YET );
-		return FALSE;
-	}
 
-	if(STATE_LOGIN_NO_DATA_YET == LLStartUp::getStartupState())
-	{
-		LL_DEBUGS("AppInit") << "STATE_LOGIN_NO_DATA_YET" << LL_ENDL;
-		// If we get here we have gotten past the potential stall
-		// in curl, so take "may appear frozen" out of progress bar. JC
-		auth_desc = LLTrans::getString("LoginInProgressNoFrozen");
-		set_startup_status(progress, auth_desc, auth_message);
-		// Process messages to keep from dropping circuit.
-		LLMessageSystem* msg = gMessageSystem;
-		while (msg->checkAllMessages(gFrameCount, gServicePump))
-		{
-		}
-		msg->processAcks();
-		LLUserAuth::UserAuthcode error = LLUserAuth::getInstance()->authResponse();
-		if(LLUserAuth::E_NO_RESPONSE_YET == error)
+		// Setting initial values...
+		LLLoginInstance* login = LLLoginInstance::getInstance();
+		login->setNotificationsInterface(LLNotifications::getInstance());
+		if(gNoRender)
 		{
-			LL_DEBUGS("AppInit") << "waiting..." << LL_ENDL;
-			return FALSE;
+			// HACK, skip optional updates if you're running drones
+			login->setSkipOptionalUpdate(true);
 		}
-		LLStartUp::setStartupState( STATE_LOGIN_DOWNLOADING );
-		progress += 0.01f;
-		set_startup_status(progress, auth_desc, auth_message);
-		return FALSE;
-	}
 
-	if(STATE_LOGIN_DOWNLOADING == LLStartUp::getStartupState())
-	{
-		LL_DEBUGS("AppInit") << "STATE_LOGIN_DOWNLOADING" << LL_ENDL;
-		// Process messages to keep from dropping circuit.
-		LLMessageSystem* msg = gMessageSystem;
-		while (msg->checkAllMessages(gFrameCount, gServicePump))
-		{
-		}
-		msg->processAcks();
-		LLUserAuth::UserAuthcode error = LLUserAuth::getInstance()->authResponse();
-		if(LLUserAuth::E_DOWNLOADING == error)
-		{
-			LL_DEBUGS("AppInit") << "downloading..." << LL_ENDL;
-			return FALSE;
-		}
+		login->setUserInteraction(show_connect_box);
+		login->setSerialNumber(LLAppViewer::instance()->getSerialNumber());
+		login->setLastExecEvent(gLastExecEvent);
+		login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance()));
+
+		// This call to LLLoginInstance::connect() starts the 
+		// authentication process.
+		LLSD credentials;
+		credentials["first"] = gFirstname;
+		credentials["last"] = gLastname;
+		credentials["passwd"] = gPassword;
+		login->connect(credentials);
+
 		LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE );
-		progress += 0.01f;
-		set_startup_status(progress, LLTrans::getString("LoginProcessingResponse"), auth_message);
 		return FALSE;
 	}
 
-	if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState())
+	if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) 
 	{
-		LL_DEBUGS("AppInit") << "STATE_LOGIN_PROCESS_RESPONSE" << LL_ENDL;
 		std::ostringstream emsg;
-		bool quit = false;
-		bool update = false;
-		std::string login_response;
-		std::string reason_response;
-		std::string message_response;
-		bool successful_login = false;
-		LLUserAuth::UserAuthcode error = LLUserAuth::getInstance()->authResponse();
-		// reset globals
-		gAcceptTOS = FALSE;
-		gAcceptCriticalMessage = FALSE;
-		switch(error)
-		{
-		case LLUserAuth::E_OK:
-			login_response = LLUserAuth::getInstance()->getResponse("login");
-			if(login_response == "true")
-			{
-				// Yay, login!
-				successful_login = true;
-			}
-			else if(login_response == "indeterminate")
+		emsg << "Login failed.\n";
+		if(LLLoginInstance::getInstance()->authFailure())
+		{
+			LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "
+			                      << LLLoginInstance::getInstance()->getResponse() << LL_ENDL;
+			// Still have error conditions that may need some 
+			// sort of handling.
+			std::string reason_response = LLLoginInstance::getInstance()->getResponse("reason");
+			std::string message_response = LLLoginInstance::getInstance()->getResponse("message");
+	
+			if(!message_response.empty())
 			{
-				LL_INFOS("AppInit") << "Indeterminate login..." << LL_ENDL;
-				sAuthUris = LLSRV::rewriteURI(LLUserAuth::getInstance()->getResponse("next_url"));
-				sAuthUriNum = 0;
-				auth_method = LLUserAuth::getInstance()->getResponse("next_method");
-				auth_message = LLUserAuth::getInstance()->getResponse("message");
-				if(auth_method.substr(0, 5) == "login")
+				// XUI: fix translation for strings returned during login
+				// We need a generic table for translations
+				std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ];
+				if ( big_reason.size() == 0 )
 				{
-					auth_desc.assign(LLTrans::getString("LoginAuthenticating"));
+					emsg << message_response;
 				}
 				else
 				{
-					auth_desc.assign(LLTrans::getString("LoginMaintenance"));
+					emsg << big_reason;
 				}
-				// ignoring the duration & options array for now.
-				// Go back to authenticate.
-				LLStartUp::setStartupState( STATE_LOGIN_AUTHENTICATE );
-				return FALSE;
-			}
-			else
-			{
-				emsg << "Login failed.\n";
-				reason_response = LLUserAuth::getInstance()->getResponse("reason");
-				message_response = LLUserAuth::getInstance()->getResponse("message");
-
-				if (!message_response.empty())
-				{
-					// XUI: fix translation for strings returned during login
-					// We need a generic table for translations
-					std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ];
-					if ( big_reason.size() == 0 )
-					{
-						emsg << message_response;
-					}
-					else
-					{
-						emsg << big_reason;
-					}
-				}
-
-				if(reason_response == "tos")
-				{
-					if (show_connect_box)
-					{
-						LL_DEBUGS("AppInit") << "Need tos agreement" << LL_ENDL;
-						LLStartUp::setStartupState( STATE_UPDATE_CHECK );
-						LLFloaterReg::showInstance("message_tos", LLSD(message_response));
-						// LLFloaterTOS deletes itself.
-						return false;
-					}
-					else
-					{
-						quit = true;
-					}
-				}
-				if(reason_response == "critical")
-				{
-					if (show_connect_box)
-					{
-						LL_DEBUGS("AppInit") << "Need critical message" << LL_ENDL;
-						LLStartUp::setStartupState( STATE_UPDATE_CHECK );
-						LLFloaterReg::showInstance("message_critical", LLSD(message_response));
-						// LLFloaterTOS deletes itself.
-						return false;
-					}
-					else
-					{
-						quit = true;
-					}
-				}
-				if(reason_response == "key")
-				{
-					// Couldn't login because user/password is wrong
-					// Clear the password
-					password = "";
-				}
-				if(reason_response == "update")
-				{
-					auth_message = LLUserAuth::getInstance()->getResponse("message");
-					update = true;
-				}
-				if(reason_response == "optional")
-				{
-					LL_DEBUGS("AppInit") << "Login got optional update" << LL_ENDL;
-					auth_message = LLUserAuth::getInstance()->getResponse("message");
-					if (show_connect_box)
-					{
-						update_app(FALSE, auth_message);
-						LLStartUp::setStartupState( STATE_UPDATE_CHECK );
-						gSkipOptionalUpdate = TRUE;
-						return false;
-					}
-				}
-			}
-			break;
-		case LLUserAuth::E_COULDNT_RESOLVE_HOST:
-		case LLUserAuth::E_SSL_PEER_CERTIFICATE:
-		case LLUserAuth::E_UNHANDLED_ERROR:
-		case LLUserAuth::E_SSL_CACERT:
-		case LLUserAuth::E_SSL_CONNECT_ERROR:
-		default:
-			if (sAuthUriNum >= (int) sAuthUris.size() - 1)
-			{
-				emsg << "Unable to connect to " << LLAppViewer::instance()->getSecondLifeTitle() << ".\n";
-				emsg << LLUserAuth::getInstance()->errorMessage();
-			} else {
-				sAuthUriNum++;
-				std::ostringstream s;
-				LLStringUtil::format_map_t args;
-				args["[NUMBER]"] = llformat("%d", sAuthUriNum + 1);
-				auth_desc = LLTrans::getString("LoginAttempt", args);
-				LLStartUp::setStartupState( STATE_LOGIN_AUTHENTICATE );
-				return FALSE;
-			}
-			break;
-		}
-
-		if (update || gSavedSettings.getBOOL("ForceMandatoryUpdate"))
-		{
-			gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
-			update_app(TRUE, auth_message);
-			LLStartUp::setStartupState( STATE_UPDATE_CHECK );
-			return false;
-		}
-
-		// Version update and we're not showing the dialog
-		if(quit)
-		{
-			LLUserAuth::getInstance()->reset();
-			LLAppViewer::instance()->forceQuit();
-			return false;
-		}
-
-		if(successful_login)
-		{
-			std::string text;
-			text = LLUserAuth::getInstance()->getResponse("udp_blacklist");
-			if(!text.empty())
-			{
-				apply_udp_blacklist(text);
 			}
 
-			// unpack login data needed by the application
-			text = LLUserAuth::getInstance()->getResponse("agent_id");
-			if(!text.empty()) gAgentID.set(text);
-			gDebugInfo["AgentID"] = text;
-			
-			text = LLUserAuth::getInstance()->getResponse("session_id");
-			if(!text.empty()) gAgentSessionID.set(text);
-			gDebugInfo["SessionID"] = text;
-			
-			text = LLUserAuth::getInstance()->getResponse("secure_session_id");
-			if(!text.empty()) gAgent.mSecureSessionID.set(text);
-
-			text = LLUserAuth::getInstance()->getResponse("first_name");
-			if(!text.empty()) 
+			if(reason_response == "key")
 			{
-				// Remove quotes from string.  Login.cgi sends these to force
-				// names that look like numbers into strings.
-				firstname.assign(text);
-				LLStringUtil::replaceChar(firstname, '"', ' ');
-				LLStringUtil::trim(firstname);
+				// Couldn't login because user/password is wrong
+				// Clear the password
+				gPassword = "";
 			}
-			text = LLUserAuth::getInstance()->getResponse("last_name");
-			if(!text.empty()) lastname.assign(text);
-			gSavedSettings.setString("FirstName", firstname);
-			gSavedSettings.setString("LastName", lastname);
 
-			if (gSavedSettings.getBOOL("RememberPassword"))
+			if(reason_response == "update" 
+				|| reason_response == "optional")
 			{
-				// Successful login means the password is valid, so save it.
-				LLStartUp::savePasswordToDisk(password);
+				// In the case of a needed update, quit.
+				// Its either downloading or declined.
+				// If optional was skipped this case shouldn't 
+				// be reached.
+				LLLoginInstance::getInstance()->disconnect();
+				LLAppViewer::instance()->forceQuit();
 			}
 			else
 			{
-				// Don't leave password from previous session sitting around
-				// during this login session.
-				LLStartUp::deletePasswordFromDisk();
-			}
-
-			// this is the base used to construct help URLs
-			text = LLUserAuth::getInstance()->getResponse("help_url_format");
-			if (!text.empty())
-			{
-				// replace the default help URL format
-				gSavedSettings.setString("HelpURLFormat",text);
-				
-				// don't fall back to Nebraska's pre-connection static help
-				gSavedSettings.setBOOL("HelpUseLocal", false);
-			}
-			
-			// this is their actual ability to access content
-			text = LLUserAuth::getInstance()->getResponse("agent_access_max");
-			if (!text.empty())
-			{
-				// agent_access can be 'A', 'M', and 'PG'.
-				gAgent.setMaturity(text[0]);
-			}
-			
-			// this is the value of their preference setting for that content
-			// which will always be <= agent_access_max
-			text = LLUserAuth::getInstance()->getResponse("agent_region_access");
-			if (!text.empty())
-			{
-				int preferredMaturity = LLAgent::convertTextToMaturity(text[0]);
-				gSavedSettings.setU32("PreferredMaturity", preferredMaturity);
-			}
-			// During the AO transition, this flag will be true. Then the flag will
-			// go away. After the AO transition, this code and all the code that
-			// uses it can be deleted.
-			text = LLUserAuth::getInstance()->getResponse("ao_transition");
-			if (!text.empty())
-			{
-				if (text == "1")
-				{
-					gAgent.setAOTransition();
-				}
-			}
-
-			text = LLUserAuth::getInstance()->getResponse("start_location");
-			if(!text.empty()) agent_start_location.assign(text);
-			text = LLUserAuth::getInstance()->getResponse("circuit_code");
-			if(!text.empty())
-			{
-				gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10);
-			}
-			std::string sim_ip_str = LLUserAuth::getInstance()->getResponse("sim_ip");
-			std::string sim_port_str = LLUserAuth::getInstance()->getResponse("sim_port");
-			if(!sim_ip_str.empty() && !sim_port_str.empty())
-			{
-				U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10);
-				first_sim.set(sim_ip_str, sim_port);
-				if (first_sim.isOk())
-				{
-					gMessageSystem->enableCircuit(first_sim, TRUE);
-				}
-			}
-			std::string region_x_str = LLUserAuth::getInstance()->getResponse("region_x");
-			std::string region_y_str = LLUserAuth::getInstance()->getResponse("region_y");
-			if(!region_x_str.empty() && !region_y_str.empty())
-			{
-				U32 region_x = strtoul(region_x_str.c_str(), NULL, 10);
-				U32 region_y = strtoul(region_y_str.c_str(), NULL, 10);
-				first_sim_handle = to_region_handle(region_x, region_y);
-			}
-			
-			const std::string look_at_str = LLUserAuth::getInstance()->getResponse("look_at");
-			if (!look_at_str.empty())
-			{
-				size_t len = look_at_str.size();
-				LLMemoryStream mstr((U8*)look_at_str.c_str(), len);
-				LLSD sd = LLSDSerialize::fromNotation(mstr, len);
-				agent_start_look_at = ll_vector3_from_sd(sd);
-			}
-
-			text = LLUserAuth::getInstance()->getResponse("seed_capability");
-			if (!text.empty()) first_sim_seed_cap = text;
-						
-			text = LLUserAuth::getInstance()->getResponse("seconds_since_epoch");
-			if(!text.empty())
-			{
-				U32 server_utc_time = strtoul(text.c_str(), NULL, 10);
-				if(server_utc_time)
+				// Don't pop up a notification in the TOS case because
+				// LLFloaterTOS::onCancel() already scolded the user.
+				if (reason_response != "tos")
 				{
-					time_t now = time(NULL);
-					gUTCOffset = (server_utc_time - now);
-				}
-			}
-
-			std::string home_location = LLUserAuth::getInstance()->getResponse("home");
-			if(!home_location.empty())
-			{
-				size_t len = home_location.size();
-				LLMemoryStream mstr((U8*)home_location.c_str(), len);
-				LLSD sd = LLSDSerialize::fromNotation(mstr, len);
-				S32 region_x = sd["region_handle"][0].asInteger();
-				S32 region_y = sd["region_handle"][1].asInteger();
-				U64 region_handle = to_region_handle(region_x, region_y);
-				LLVector3 position = ll_vector3_from_sd(sd["position"]);
-				gAgent.setHomePosRegion(region_handle, position);
-			}
-
-			gAgent.mMOTD.assign(LLUserAuth::getInstance()->getResponse("message"));
-			LLUserAuth::options_t options;
-			if(LLUserAuth::getInstance()->getOptions("inventory-root", options))
-			{
-				LLUserAuth::response_t::iterator it;
-				it = options[0].find("folder_id");
-				if(it != options[0].end())
-				{
-					gInventory.setRootFolderID( LLUUID( (*it).second ) );
-				}
-			}
-
-			options.clear();
-			if(LLUserAuth::getInstance()->getOptions("login-flags", options))
-			{
-				LLUserAuth::response_t::iterator it;
-				LLUserAuth::response_t::iterator no_flag = options[0].end();
-				it = options[0].find("ever_logged_in");
-				if(it != no_flag)
-				{
-					if((*it).second == "N") gAgent.setFirstLogin(TRUE);
-					else gAgent.setFirstLogin(FALSE);
-				}
-				it = options[0].find("stipend_since_login");
-				if(it != no_flag)
-				{
-					if((*it).second == "Y") stipend_since_login = true;
-				}
-				it = options[0].find("gendered");
-				if(it != no_flag)
-				{
-					if((*it).second == "Y") gAgent.setGenderChosen(TRUE);
-				}
-				it = options[0].find("daylight_savings");
-				if(it != no_flag)
-				{
-					if((*it).second == "Y")  gPacificDaylightTime = TRUE;
-					else gPacificDaylightTime = FALSE;
+					LLSD args;
+					args["ERROR_MESSAGE"] = emsg.str();
+					LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
+					LLNotifications::instance().add("ErrorMessage", args, LLSD(), login_alert_done);
 				}
 
 				//setup map of datetime strings to codes and slt & local time offset from utc
 				LLStringOps::setupDatetimeInfo (gPacificDaylightTime);
+				transition_back_to_login_panel(emsg.str());
+				show_connect_box = true;
 			}
-			options.clear();
-			if (LLUserAuth::getInstance()->getOptions("initial-outfit", options)
-				&& !options.empty())
-			{
-				LLUserAuth::response_t::iterator it;
-				LLUserAuth::response_t::iterator it_end = options[0].end();
-				it = options[0].find("folder_name");
-				if(it != it_end)
-				{
-					// Initial outfit is a folder in your inventory,
-					// must be an exact folder-name match.
-					sInitialOutfit = (*it).second;
-				}
-				it = options[0].find("gender");
-				if (it != it_end)
-				{
-					sInitialOutfitGender = (*it).second;
-				}
-			}
-
-			options.clear();
-			if(LLUserAuth::getInstance()->getOptions("global-textures", options))
-			{
-				// Extract sun and moon texture IDs.  These are used
-				// in the LLVOSky constructor, but I can't figure out
-				// how to pass them in.  JC
-				LLUserAuth::response_t::iterator it;
-				LLUserAuth::response_t::iterator no_texture = options[0].end();
-				it = options[0].find("sun_texture_id");
-				if(it != no_texture)
-				{
-					gSunTextureID.set((*it).second);
-				}
-				it = options[0].find("moon_texture_id");
-				if(it != no_texture)
-				{
-					gMoonTextureID.set((*it).second);
-				}
-				it = options[0].find("cloud_texture_id");
-				if(it != no_texture)
-				{
-					gCloudTextureID.set((*it).second);
-				}
-			}
-
-
-			// JC: gesture loading done below, when we have an asset system
-			// in place.  Don't delete/clear user_credentials until then.
-
-			if(gAgentID.notNull()
-			   && gAgentSessionID.notNull()
-			   && gMessageSystem->mOurCircuitCode
-			   && first_sim.isOk()
-			   && gInventory.getRootFolderID().notNull())
+		}
+		else if(LLLoginInstance::getInstance()->authSuccess())
+		{
+			if(process_login_success_response())
 			{
-				LLStartUp::setStartupState( STATE_WORLD_INIT );
+				// Pass the user information to the voice chat server interface.
+				gVoiceClient->userAuthorized(gFirstname, gLastname, gAgentID);
+				LLStartUp::setStartupState( STATE_WORLD_INIT);
 			}
 			else
 			{
-				if (gNoRender)
-				{
-					LL_WARNS("AppInit") << "Bad login - missing return values" << LL_ENDL;
-					LL_WARNS("AppInit") << emsg << LL_ENDL;
-					exit(0);
-				}
-				// Bounce back to the login screen.
 				LLSD args;
 				args["ERROR_MESSAGE"] = emsg.str();
+				LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
 				LLNotifications::instance().add("ErrorMessage", args, LLSD(), login_alert_done);
-				reset_login();
-				gSavedSettings.setBOOL("AutoLogin", FALSE);
+				transition_back_to_login_panel(emsg.str());
 				show_connect_box = true;
 			}
-			
-			// Pass the user information to the voice chat server interface.
-			gVoiceClient->userAuthorized(firstname, lastname, gAgentID);
 		}
-		else // if(successful_login)
+		else
 		{
-			if (gNoRender)
-			{
-				LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL;
-				LL_WARNS("AppInit") << emsg << LL_ENDL;
-				exit(0);
-			}
-			// Bounce back to the login screen.
-			LLSD args;
-			args["ERROR_MESSAGE"] = emsg.str();
-			LLNotifications::instance().add("ErrorMessage", args, LLSD(), login_alert_done);
-			reset_login();
-			gSavedSettings.setBOOL("AutoLogin", FALSE);
-			show_connect_box = true;
+			// Still waiting for response.
+			// *TODO:Mani - Actually check for login progress.
+			// If we get here we have gotten past the potential stall
+			// in curl, so take "may appear frozen" out of progress bar. JC
+			auth_desc = LLTrans::getString("LoginInProgressNoFrozen");
+			set_startup_status(progress, auth_desc, auth_message);
 		}
+
 		return FALSE;
 	}
 
@@ -1740,14 +1241,14 @@ bool idle_startup()
 		// This is necessary because creating objects before this is set will result in a
 		// bad mPositionAgent cache.
 
-		gAgent.initOriginGlobal(from_region_handle(first_sim_handle));
+		gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle));
 
-		LLWorld::getInstance()->addRegion(first_sim_handle, first_sim);
+		LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim);
 
-		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(first_sim_handle);
+		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
 		LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL;
 		
-		regionp->setSeedCapability(first_sim_seed_cap);
+		regionp->setSeedCapability(gFirstSimSeedCap);
 		LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;
 		
 		// Set agent's initial region to be the one we just created.
@@ -1886,7 +1387,7 @@ bool idle_startup()
 		// the coordinates handed to us to fit in the local region.
 
 		gAgent.setPositionAgent(agent_start_position_region);
-		gAgent.resetAxes(agent_start_look_at);
+		gAgent.resetAxes(gAgentStartLookAt);
 		gAgent.stopCameraAnimation();
 		gAgent.resetCamera();
 
@@ -1925,18 +1426,18 @@ bool idle_startup()
 			LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL;
 		}
 
-		gUseCircuitCallbackCalled = FALSE;
+		gUseCircuitCallbackCalled = false;
 
-		msg->enableCircuit(first_sim, TRUE);
+		msg->enableCircuit(gFirstSim, TRUE);
 		// now, use the circuit info to tell simulator about us!
-		LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << first_sim << " with code " << msg->mOurCircuitCode << LL_ENDL;
+		LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL;
 		msg->newMessageFast(_PREHASH_UseCircuitCode);
 		msg->nextBlockFast(_PREHASH_CircuitCode);
 		msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode);
 		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 		msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
 		msg->sendReliable(
-			first_sim,
+			gFirstSim,
 			MAX_TIMEOUT_COUNT,
 			FALSE,
 			TIMEOUT_SECONDS,
@@ -2047,105 +1548,99 @@ bool idle_startup()
 		LLAgentLanguage::update();
 
 		// unpack thin inventory
-		LLUserAuth::options_t options;
-		options.clear();
+		LLSD response = LLLoginInstance::getInstance()->getResponse();
 		//bool dump_buffer = false;
-		
-		if(LLUserAuth::getInstance()->getOptions("inventory-lib-root", options)
-			&& !options.empty())
+
+		LLSD inv_lib_root = response["inventory-lib-root"];
+		if(inv_lib_root.isDefined())
 		{
 			// should only be one
-			LLUserAuth::response_t::iterator it;
-			it = options[0].find("folder_id");
-			if(it != options[0].end())
+			LLSD id = inv_lib_root[0]["folder_id"];
+			if(id.isDefined())
 			{
-				gInventory.setLibraryRootFolderID( LLUUID( (*it).second ) );
+				gInventory.setLibraryRootFolderID(id.asUUID());
 			}
 		}
- 		options.clear();
-		if(LLUserAuth::getInstance()->getOptions("inventory-lib-owner", options)
-			&& !options.empty())
+ 		
+		LLSD inv_lib_owner = response["inventory-lib-owner"];
+		if(inv_lib_owner.isDefined())
 		{
 			// should only be one
-			LLUserAuth::response_t::iterator it;
-			it = options[0].find("agent_id");
-			if(it != options[0].end())
+			LLSD id = inv_lib_owner[0]["agent_id"];
+			if(id.isDefined())
 			{
-				gInventory.setLibraryOwnerID( LLUUID( (*it).second ) );
+				gInventory.setLibraryOwnerID( LLUUID(id.asUUID()));
 			}
 		}
- 		options.clear();
- 		if(LLUserAuth::getInstance()->getOptions("inventory-skel-lib", options)
-			&& gInventory.getLibraryOwnerID().notNull())
+
+		LLSD inv_skel_lib = response["inventory-skel-lib"];
+ 		if(inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull())
  		{
- 			if(!gInventory.loadSkeleton(options, gInventory.getLibraryOwnerID()))
+ 			if(!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID()))
  			{
  				LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
  			}
  		}
- 		options.clear();
- 		if(LLUserAuth::getInstance()->getOptions("inventory-skeleton", options))
+
+		LLSD inv_skeleton = response["inventory-skeleton"];
+ 		if(inv_skeleton.isDefined())
  		{
- 			if(!gInventory.loadSkeleton(options, gAgent.getID()))
+ 			if(!gInventory.loadSkeleton(inv_skeleton, gAgent.getID()))
  			{
  				LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
  			}
  		}
 
-		options.clear();
- 		if(LLUserAuth::getInstance()->getOptions("buddy-list", options))
+		LLSD buddy_list = response["buddy-list"];
+ 		if(buddy_list.isDefined())
  		{
-			LLUserAuth::options_t::iterator it = options.begin();
-			LLUserAuth::options_t::iterator end = options.end();
 			LLAvatarTracker::buddy_map_t list;
 			LLUUID agent_id;
 			S32 has_rights = 0, given_rights = 0;
-			for (; it != end; ++it)
+			for(LLSD::array_const_iterator it = buddy_list.beginArray(),
+				end = buddy_list.endArray(); it != end; ++it)
 			{
-				LLUserAuth::response_t::const_iterator option_it;
-				option_it = (*it).find("buddy_id");
-				if(option_it != (*it).end())
+				LLSD buddy_id = (*it)["buddy_id"];
+				if(buddy_id.isDefined())
 				{
-					agent_id.set((*option_it).second);
+					agent_id = buddy_id.asUUID();
 				}
-				option_it = (*it).find("buddy_rights_has");
-				if(option_it != (*it).end())
+
+				LLSD buddy_rights_has = (*it)["buddy_rights_has"];
+				if(buddy_rights_has.isDefined())
 				{
-					has_rights = atoi((*option_it).second.c_str());
+					has_rights = buddy_rights_has.asInteger();
 				}
-				option_it = (*it).find("buddy_rights_given");
-				if(option_it != (*it).end())
+
+				LLSD buddy_rights_given = (*it)["buddy_rights_given"];
+				if(buddy_rights_given.isDefined())
 				{
-					given_rights = atoi((*option_it).second.c_str());
+					given_rights = buddy_rights_given.asInteger();
 				}
+
 				list[agent_id] = new LLRelationship(given_rights, has_rights, false);
 			}
 			LLAvatarTracker::instance().addBuddyList(list);
  		}
 
-		options.clear();
-
 		bool show_hud = false;
-		if(LLUserAuth::getInstance()->getOptions("tutorial_setting", options))
+		LLSD tutorial_setting = response["tutorial_setting"];
+		if(tutorial_setting.isDefined())
 		{
-			LLUserAuth::options_t::iterator it = options.begin();
-			LLUserAuth::options_t::iterator end = options.end();
-			for (; it != end; ++it)
+			for(LLSD::array_const_iterator it = tutorial_setting.beginArray(),
+				end = tutorial_setting.endArray(); it != end; ++it)
 			{
-				LLUserAuth::response_t::const_iterator option_it;
-				option_it = (*it).find("tutorial_url");
-				if(option_it != (*it).end())
+				LLSD tutorial_url = (*it)["tutorial_url"];
+				if(tutorial_url.isDefined())
 				{
 					// Tutorial floater will append language code
-					gSavedSettings.setString("TutorialURL", option_it->second);
+					gSavedSettings.setString("TutorialURL", tutorial_url.asString());
 				}
-				option_it = (*it).find("use_tutorial");
-				if(option_it != (*it).end())
+				
+				LLSD use_tutorial = (*it)["use_tutorial"];
+				if(use_tutorial.asString() == "true")
 				{
-					if (option_it->second == "true")
-					{
-						show_hud = true;
-					}
+					show_hud = true;
 				}
 			}
 		}
@@ -2157,19 +1652,22 @@ bool idle_startup()
 			LLFloaterReg::showInstance("hud", LLSD(), FALSE);
 		}
 
-		options.clear();
-		if(LLUserAuth::getInstance()->getOptions("event_categories", options))
+		LLSD event_categories = response["event_categories"];
+		if(event_categories.isDefined())
 		{
-			LLEventInfo::loadCategories(options);
+			LLEventInfo::loadCategories(event_categories);
 		}
-		if(LLUserAuth::getInstance()->getOptions("event_notifications", options))
+
+		LLSD event_notifications = response["event_notifications"];
+		if(event_notifications.isDefined())
 		{
-			gEventNotifier.load(options);
+			gEventNotifier.load(event_notifications);
 		}
-		options.clear();
-		if(LLUserAuth::getInstance()->getOptions("classified_categories", options))
+
+		LLSD classified_categories = response["classified_categories"];
+		if(classified_categories.isDefined())
 		{
-			LLClassifiedInfo::loadCategories(options);
+			LLClassifiedInfo::loadCategories(classified_categories);
 		}
 
 
@@ -2233,7 +1731,7 @@ bool idle_startup()
 			// This is actually a pessimistic computation, because TCP may not have enough
 			// time to ramp up on the (small) default inventory file to truly measure max
 			// bandwidth. JC
-			F64 rate_bps = LLUserAuth::getInstance()->getLastTransferRateBPS();
+			F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS();
 			const F32 FAST_RATE_BPS = 600.f * 1024.f;
 			const F32 FASTER_RATE_BPS = 750.f * 1024.f;
 			F32 max_bandwidth = gViewerThrottle.getMaxBandwidth();
@@ -2281,34 +1779,20 @@ bool idle_startup()
 			// JC: Initialize "active" gestures.  This may also trigger
 			// many gesture downloads, if this is the user's first
 			// time on this machine or -purge has been run.
-			LLUserAuth::options_t gesture_options;
-			if (LLUserAuth::getInstance()->getOptions("gestures", gesture_options))
+			LLSD gesture_options 
+				= LLLoginInstance::getInstance()->getResponse("gestures");
+			if (gesture_options.isDefined())
 			{
 				LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size()
 					<< LL_ENDL;
 				std::vector<LLUUID> item_ids;
-				LLUserAuth::options_t::iterator resp_it;
-				for (resp_it = gesture_options.begin();
-					 resp_it != gesture_options.end();
-					 ++resp_it)
+				for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(),
+					end = gesture_options.endArray(); resp_it != end; ++resp_it)
 				{
-					const LLUserAuth::response_t& response = *resp_it;
-					LLUUID item_id;
-					LLUUID asset_id;
-					LLUserAuth::response_t::const_iterator option_it;
-
-					option_it = response.find("item_id");
-					if (option_it != response.end())
-					{
-						const std::string& uuid_string = (*option_it).second;
-						item_id.set(uuid_string);
-					}
-					option_it = response.find("asset_id");
-					if (option_it != response.end())
-					{
-						const std::string& uuid_string = (*option_it).second;
-						asset_id.set(uuid_string);
-					}
+					// If the id is not specifed in the LLSD,
+					// the LLSD operator[]() will return a null LLUUID. 
+					LLUUID item_id = (*resp_it)["item_id"];
+					LLUUID asset_id = (*resp_it)["asset_id"];
 
 					if (item_id.notNull() && asset_id.notNull())
 					{
@@ -2364,8 +1848,8 @@ bool idle_startup()
 		if (!gAgent.isFirstLogin())
 		{
 			bool url_ok = LLURLSimString::sInstance.parse();
-			if ((url_ok && agent_start_location == "url") ||
-				(!url_ok && ((agent_start_location == gSavedSettings.getString("LoginLocation")))))
+			if ((url_ok && gAgentStartLocation == "url") ||
+				(!url_ok && ((gAgentStartLocation == gSavedSettings.getString("LoginLocation")))))
 			{
 				// Start location is OK
 				// Disabled code to restore camera location and focus if logging in to default location
@@ -2578,8 +2062,10 @@ bool idle_startup()
 		// then the data is cached for the viewer's lifetime)
 		LLProductInfoRequestManager::instance();
 		
+		// *FIX:Mani - What do I do here?
+		// Need we really clear the Auth response data?
 		// Clean up the userauth stuff.
-		LLUserAuth::getInstance()->reset();
+		// LLUserAuth::getInstance()->reset();
 
 		LLStartUp::setStartupState( STATE_STARTED );
 
@@ -2869,230 +2355,6 @@ bool login_alert_status(const LLSD& notification, const LLSD& response)
 	return false;
 }
 
-void update_app(BOOL mandatory, const std::string& auth_msg)
-{
-	// store off config state, as we might quit soon
-	gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);	
-	LLUIColorTable::instance().saveUserSettings();
-	std::ostringstream message;
-
-	std::string msg;
-	if (!auth_msg.empty())
-	{
-		msg = "("+ auth_msg + ") \n";
-	}
-
-	LLSD args;
-	args["MESSAGE"] = msg;
-	
-	LLSD payload;
-	payload["mandatory"] = mandatory;
-
-/*
- We're constructing one of the following 6 strings here:
-	 "DownloadWindowsMandatory"
-	 "DownloadWindowsReleaseForDownload"
-	 "DownloadWindows"
-	 "DownloadMacMandatory"
-	 "DownloadMacReleaseForDownload"
-	 "DownloadMac"
- 
- I've called them out explicitly in this comment so that they can be grepped for.
- 
- Also, we assume that if we're not Windows we're Mac. If we ever intend to support 
- Linux with autoupdate, this should be an explicit #elif LL_DARWIN, but 
- we'd rather deliver the wrong message than no message, so until Linux is supported
- we'll leave it alone.
- */
-	std::string notification_name = "Download";
-	
-#if LL_WINDOWS
-	notification_name += "Windows";
-#elif LL_DARWIN
-	notification_name += "Mac";
-#else
-	notification_name += "Linux";	
-#endif
-
-	if (mandatory)
-	{
-		notification_name += "Mandatory";
-	}
-	else
-	{
-#if LL_RELEASE_FOR_DOWNLOAD
-		notification_name += "ReleaseForDownload";
-#endif
-	}
-	
-	LLNotifications::instance().add(notification_name, args, payload, update_dialog_callback);
-}
-
-bool update_dialog_callback(const LLSD& notification, const LLSD& response)
-{
-	S32 option = LLNotification::getSelectedOption(notification, response);
-	std::string update_exe_path;
-	bool mandatory = notification["payload"]["mandatory"].asBoolean();
-
-#if !LL_RELEASE_FOR_DOWNLOAD
-	if (option == 2)
-	{
-		LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); 
-		return false;
-	}
-#endif
-
-	if (option == 1)
-	{
-		// ...user doesn't want to do it
-		if (mandatory)
-		{
-			LLAppViewer::instance()->forceQuit();
-			// Bump them back to the login screen.
-			//reset_login();
-		}
-		else
-		{
-			LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT );
-		}
-		return false;
-	}
-
-	// if a sim name was passed in via command line parameter (typically through a SLURL)
-	if ( LLURLSimString::sInstance.mSimString.length() )
-	{
-		// record the location to start at next time
-		gSavedSettings.setString("NextLoginLocation", LLURLSimString::sInstance.mSimString);
-	}
-	
-	LLSD query_map = LLSD::emptyMap();
-	// *TODO place os string in a global constant
-#if LL_WINDOWS  
-	query_map["os"] = "win";
-#elif LL_DARWIN
-	query_map["os"] = "mac";
-#elif LL_LINUX
-	query_map["os"] = "lnx";
-#elif LL_SOLARIS
-	query_map["os"] = "sol";
-#endif
-	// *TODO change userserver to be grid on both viewer and sim, since
-	// userserver no longer exists.
-	query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel();
-	query_map["channel"] = gSavedSettings.getString("VersionChannelName");
-	// *TODO constantize this guy
-	// *NOTE: This URL is also used in win_setup/lldownloader.cpp
-	LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
-	
-	if(LLAppViewer::sUpdaterInfo)
-	{
-		delete LLAppViewer::sUpdaterInfo ;
-	}
-	LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
-	
-#if LL_WINDOWS
-	LLAppViewer::sUpdaterInfo->mUpdateExePath = gDirUtilp->getTempFilename();
-	if (LLAppViewer::sUpdaterInfo->mUpdateExePath.empty())
-	{
-		delete LLAppViewer::sUpdaterInfo ;
-		LLAppViewer::sUpdaterInfo = NULL ;
-
-		// We're hosed, bail
-		LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL;
-		LLAppViewer::instance()->forceQuit();
-		return false;
-	}
-
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe";
-
-	std::string updater_source = gDirUtilp->getAppRODataDir();
-	updater_source += gDirUtilp->getDirDelimiter();
-	updater_source += "updater.exe";
-
-	LL_DEBUGS("AppInit") << "Calling CopyFile source: " << updater_source
-			<< " dest: " << LLAppViewer::sUpdaterInfo->mUpdateExePath
-			<< LL_ENDL;
-
-
-	if (!CopyFileA(updater_source.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), FALSE))
-	{
-		delete LLAppViewer::sUpdaterInfo ;
-		LLAppViewer::sUpdaterInfo = NULL ;
-
-		LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL;
-		LLAppViewer::instance()->forceQuit();
-		return false;
-	}
-
-	LLAppViewer::sUpdaterInfo->mParams << "-url \"" << update_url.asString() << "\"";
-
-	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL;
-
-	//Explicitly remove the marker file, otherwise we pass the lock onto the child process and things get weird.
-	LLAppViewer::instance()->removeMarkerFile(); // In case updater fails
-	
-#elif LL_DARWIN
-	LLAppViewer::sUpdaterInfo->mUpdateExePath = "'";
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir();
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url \"";
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
-	LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
-
-	LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
-
-	// Run the auto-updater.
-	system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */
-
-#elif (LL_LINUX || LL_SOLARIS) && LL_GTK
-	// we tell the updater where to find the xml containing string
-	// translations which it can use for its own UI
-	std::string xml_strings_file = "strings.xml";
-	std::vector<std::string> xui_path_vec = LLUI::getXUIPaths();
-	std::string xml_search_paths;
-	std::vector<std::string>::const_iterator iter;
-	// build comma-delimited list of xml paths to pass to updater
-	for (iter = xui_path_vec.begin(); iter != xui_path_vec.end(); )
-	{
-		std::string this_skin_dir = gDirUtilp->getDefaultSkinDir()
-			+ gDirUtilp->getDirDelimiter()
-			+ (*iter);
-		llinfos << "Got a XUI path: " << this_skin_dir << llendl;
-		xml_search_paths.append(this_skin_dir);
-		++iter;
-		if (iter != xui_path_vec.end())
-			xml_search_paths.append(","); // comma-delimit
-	}
-	// build the overall command-line to run the updater correctly
-	update_exe_path = 
-		gDirUtilp->getExecutableDir() + "/" + "linux-updater.bin" + 
-		" --url \"" + update_url.asString() + "\"" +
-		" --name \"" + LLAppViewer::instance()->getSecondLifeTitle() + "\"" +
-		" --dest \"" + gDirUtilp->getAppRODataDir() + "\"" +
-		" --stringsdir \"" + xml_search_paths + "\"" +
-		" --stringsfile \"" + xml_strings_file + "\"";
-
-	LL_INFOS("AppInit") << "Calling updater: " 
-			    << update_exe_path << LL_ENDL;
-
-	// *TODO: we could use the gdk equivilant to ensure the updater
-	// gets started on the same screen.
-	GError *error = NULL;
-	if (!g_spawn_command_line_async(update_exe_path.c_str(), &error))
-	{
-		llerrs << "Failed to launch updater: "
-		       << error->message
-		       << llendl;
-	}
-	if (error)
-		g_error_free(error);
-#else
-	OSMessageBox(LLTrans::getString("MBNoAutoUpdate"), LLStringUtil::null, OSMB_OK);
-#endif
-	LLAppViewer::instance()->forceQuit();
-	return false;
-}
 
 void use_circuit_callback(void**, S32 result)
 {
@@ -3439,11 +2701,7 @@ std::string LLStartUp::startupStateToString(EStartupState state)
 		RTNENUM( STATE_LOGIN_SHOW );
 		RTNENUM( STATE_LOGIN_WAIT );
 		RTNENUM( STATE_LOGIN_CLEANUP );
-		RTNENUM( STATE_UPDATE_CHECK );
 		RTNENUM( STATE_LOGIN_AUTH_INIT );
-		RTNENUM( STATE_LOGIN_AUTHENTICATE );
-		RTNENUM( STATE_LOGIN_NO_DATA_YET );
-		RTNENUM( STATE_LOGIN_DOWNLOADING );
 		RTNENUM( STATE_LOGIN_PROCESS_RESPONSE );
 		RTNENUM( STATE_WORLD_INIT );
 		RTNENUM( STATE_SEED_GRANTED_WAIT );
@@ -3463,14 +2721,17 @@ std::string LLStartUp::startupStateToString(EStartupState state)
 #undef RTNENUM
 }
 
-
 // static
 void LLStartUp::setStartupState( EStartupState state )
 {
 	LL_INFOS("AppInit") << "Startup state changing from " <<  
-		startupStateToString(gStartupState) << " to " <<  
+		getStartupStateString() << " to " <<  
 		startupStateToString(state) << LL_ENDL;
 	gStartupState = state;
+	LLSD stateInfo;
+	stateInfo["str"] = getStartupStateString();
+	stateInfo["enum"] = state;
+	sStartupStateWatcher.post(stateInfo);
 }
 
 
@@ -3584,3 +2845,277 @@ void apply_udp_blacklist(const std::string& csv)
 	
 }
 
+bool process_login_success_response()
+{
+	LLSD response = LLLoginInstance::getInstance()->getResponse();
+
+	std::string text(response["udp_blacklist"]);
+	if(!text.empty())
+	{
+		apply_udp_blacklist(text);
+	}
+
+	// unpack login data needed by the application
+	text = response["agent_id"].asString();
+	if(!text.empty()) gAgentID.set(text);
+	gDebugInfo["AgentID"] = text;
+	
+	text = response["session_id"].asString();
+	if(!text.empty()) gAgentSessionID.set(text);
+	gDebugInfo["SessionID"] = text;
+	
+	text = response["secure_session_id"].asString();
+	if(!text.empty()) gAgent.mSecureSessionID.set(text);
+
+	text = response["first_name"].asString();
+	if(!text.empty()) 
+	{
+		// Remove quotes from string.  Login.cgi sends these to force
+		// names that look like numbers into strings.
+		gFirstname.assign(text);
+		LLStringUtil::replaceChar(gFirstname, '"', ' ');
+		LLStringUtil::trim(gFirstname);
+	}
+	text = response["last_name"].asString();
+	if(!text.empty()) 
+	{
+		gLastname.assign(text);
+	}
+	gSavedSettings.setString("FirstName", gFirstname);
+	gSavedSettings.setString("LastName", gLastname);
+
+	if (gSavedSettings.getBOOL("RememberPassword"))
+	{
+		// Successful login means the password is valid, so save it.
+		LLStartUp::savePasswordToDisk(gPassword);
+	}
+	else
+	{
+		// Don't leave password from previous session sitting around
+		// during this login session.
+		LLStartUp::deletePasswordFromDisk();
+	}
+
+	// this is their actual ability to access content
+	text = response["agent_access_max"].asString();
+	if (!text.empty())
+	{
+		// agent_access can be 'A', 'M', and 'PG'.
+		gAgent.setMaturity(text[0]);
+	}
+	
+	// this is the value of their preference setting for that content
+	// which will always be <= agent_access_max
+	text = response["agent_region_access"].asString();
+	if (!text.empty())
+	{
+		int preferredMaturity = LLAgent::convertTextToMaturity(text[0]);
+		gSavedSettings.setU32("PreferredMaturity", preferredMaturity);
+	}
+	// During the AO transition, this flag will be true. Then the flag will
+	// go away. After the AO transition, this code and all the code that
+	// uses it can be deleted.
+	text = response["ao_transition"].asString();
+	if (!text.empty())
+	{
+		if (text == "1")
+		{
+			gAgent.setAOTransition();
+		}
+	}
+
+	text = response["start_location"].asString();
+	if(!text.empty()) 
+	{
+		gAgentStartLocation.assign(text);
+	}
+
+	text = response["circuit_code"].asString();
+	if(!text.empty())
+	{
+		gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10);
+	}
+	std::string sim_ip_str = response["sim_ip"];
+	std::string sim_port_str = response["sim_port"];
+	if(!sim_ip_str.empty() && !sim_port_str.empty())
+	{
+		U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10);
+		gFirstSim.set(sim_ip_str, sim_port);
+		if (gFirstSim.isOk())
+		{
+			gMessageSystem->enableCircuit(gFirstSim, TRUE);
+		}
+	}
+	std::string region_x_str = response["region_x"];
+	std::string region_y_str = response["region_y"];
+	if(!region_x_str.empty() && !region_y_str.empty())
+	{
+		U32 region_x = strtoul(region_x_str.c_str(), NULL, 10);
+		U32 region_y = strtoul(region_y_str.c_str(), NULL, 10);
+		gFirstSimHandle = to_region_handle(region_x, region_y);
+	}
+	
+	const std::string look_at_str = response["look_at"];
+	if (!look_at_str.empty())
+	{
+		size_t len = look_at_str.size();
+		LLMemoryStream mstr((U8*)look_at_str.c_str(), len);
+		LLSD sd = LLSDSerialize::fromNotation(mstr, len);
+		gAgentStartLookAt = ll_vector3_from_sd(sd);
+	}
+
+	text = response["seed_capability"].asString();
+	if (!text.empty()) gFirstSimSeedCap = text;
+				
+	text = response["seconds_since_epoch"].asString();
+	if(!text.empty())
+	{
+		U32 server_utc_time = strtoul(text.c_str(), NULL, 10);
+		if(server_utc_time)
+		{
+			time_t now = time(NULL);
+			gUTCOffset = (server_utc_time - now);
+		}
+	}
+
+	// this is the base used to construct help URLs
+	text = response["help_url_format"].asString();
+	if (!text.empty())
+	{
+		// replace the default help URL format
+		gSavedSettings.setString("HelpURLFormat",text);
+		
+		// don't fall back to Nebraska's pre-connection static help
+		gSavedSettings.setBOOL("HelpUseLocal", false);
+	}
+			
+	std::string home_location = response["home"];
+	if(!home_location.empty())
+	{
+		size_t len = home_location.size();
+		LLMemoryStream mstr((U8*)home_location.c_str(), len);
+		LLSD sd = LLSDSerialize::fromNotation(mstr, len);
+		S32 region_x = sd["region_handle"][0].asInteger();
+		S32 region_y = sd["region_handle"][1].asInteger();
+		U64 region_handle = to_region_handle(region_x, region_y);
+		LLVector3 position = ll_vector3_from_sd(sd["position"]);
+		gAgent.setHomePosRegion(region_handle, position);
+	}
+
+	gAgent.mMOTD.assign(response["message"]);
+
+	// Options...
+	// Each 'option' is an array of submaps. 
+	// It appears that we only ever use the first element of the array.
+	LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"];
+	if(inv_root_folder_id.notNull())
+	{
+		gInventory.setRootFolderID(inv_root_folder_id);
+		//gInventory.mock(gAgent.getInventoryRootID());
+	}
+
+	LLSD login_flags = response["login-flags"][0];
+	if(login_flags.size())
+	{
+		std::string flag = login_flags["ever_logged_in"];
+		if(!flag.empty())
+		{
+			gAgent.setFirstLogin((flag == "N") ? TRUE : FALSE);
+		}
+
+		/*  Flag is currently ignored by the viewer.
+		flag = login_flags["stipend_since_login"];
+		if(flag == "Y") 
+		{
+			stipend_since_login = true;
+		}
+		*/
+
+		flag = login_flags["gendered"].asString();
+		if(flag == "Y")
+		{
+			gAgent.setGenderChosen(TRUE);
+		}
+		
+		flag = login_flags["daylight_savings"].asString();
+		if(flag == "Y")
+		{
+			gPacificDaylightTime  = (flag == "Y") ? TRUE : FALSE;
+		}
+
+		//setup map of datetime strings to codes and slt & local time offset from utc
+		LLStringOps::setupDatetimeInfo (gPacificDaylightTime);
+	}
+
+	LLSD initial_outfit = response["initial-outfit"][0];
+	if(initial_outfit.size())
+	{
+		std::string flag = initial_outfit["folder_name"];
+		if(!flag.empty())
+		{
+			// Initial outfit is a folder in your inventory,
+			// must be an exact folder-name match.
+			sInitialOutfit = flag;
+		}
+
+		flag = initial_outfit["gender"].asString();
+		if(!flag.empty())
+		{
+			sInitialOutfitGender = flag;
+		}
+	}
+
+	LLSD global_textures = response["global-textures"][0];
+	if(global_textures.size())
+	{
+		// Extract sun and moon texture IDs.  These are used
+		// in the LLVOSky constructor, but I can't figure out
+		// how to pass them in.  JC
+		LLUUID id = global_textures["sun_texture_id"];
+		if(id.notNull())
+		{
+			gSunTextureID = id;
+		}
+
+		id = global_textures["moon_texture_id"];
+		if(id.notNull())
+		{
+			gMoonTextureID = id;
+		}
+
+		id = global_textures["cloud_texture_id"];
+		if(id.notNull())
+		{
+			gCloudTextureID = id;
+		}
+	}
+
+
+	bool success = false;
+	// JC: gesture loading done below, when we have an asset system
+	// in place.  Don't delete/clear user_credentials until then.
+	if(gAgentID.notNull()
+	   && gAgentSessionID.notNull()
+	   && gMessageSystem->mOurCircuitCode
+	   && gFirstSim.isOk()
+	   && gInventory.getRootFolderID().notNull())
+	{
+		success = true;
+	}
+
+	return success;
+}
+
+void transition_back_to_login_panel(const std::string& emsg)
+{
+	if (gNoRender)
+	{
+		LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL;
+		LL_WARNS("AppInit") << emsg << LL_ENDL;
+		exit(0);
+	}
+
+	// Bounce back to the login screen.
+	reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+	gSavedSettings.setBOOL("AutoLogin", FALSE);
+}
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 4532c5e586c44acdbfcfe553b55e0376b37b3add..7f869d014f8d3098586255616eaebf094d5691e0 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -50,11 +50,7 @@ typedef enum {
 	STATE_LOGIN_SHOW,				// Show login screen
 	STATE_LOGIN_WAIT,				// Wait for user input at login screen
 	STATE_LOGIN_CLEANUP,			// Get rid of login screen and start login
-	STATE_UPDATE_CHECK,				// Wait for user at a dialog box (updates, term-of-service, etc)
 	STATE_LOGIN_AUTH_INIT,			// Start login to SL servers
-	STATE_LOGIN_AUTHENTICATE,		// Do authentication voodoo
-	STATE_LOGIN_NO_DATA_YET,		// Waiting for authentication replies to start
-	STATE_LOGIN_DOWNLOADING,		// Waiting for authentication replies to download
 	STATE_LOGIN_PROCESS_RESPONSE,	// Check authentication reply
 	STATE_WORLD_INIT,				// Start building the world
 	STATE_MULTIMEDIA_INIT,			// Init the rest of multimedia library
@@ -75,8 +71,6 @@ typedef enum {
 // exported symbols
 extern bool gAgentMovementCompleted;
 extern LLPointer<LLViewerTexture> gStartTexture;
-extern std::string gInitialOutfit;
-extern std::string gInitialOutfitGender;	// "male" or "female"
 
 class LLStartUp
 {
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index b015f668e4a36485a2908402d076dc13c65c812d..b035fd53fd2d47808eecdf3038bb0bb8a7807f00 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -518,11 +518,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 
 		if(!object)
 		{
-			// We need to clear media hover flag
-			if (LLViewerMediaFocus::getInstance()->getMouseOverFlag())
-			{
-				LLViewerMediaFocus::getInstance()->setMouseOverFlag(false);
-			}
+			LLViewerMediaFocus::getInstance()->clearHover();
 		}
 	}
 
@@ -1029,7 +1025,6 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
 		pick.mObjectFace < 0 || 
 		pick.mObjectFace >= objectp->getNumTEs()) 
 	{
-		LLSelectMgr::getInstance()->deselect();
 		LLViewerMediaFocus::getInstance()->clearFocus();
 
 		return false;
@@ -1037,11 +1032,7 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
 
 
 
-	// HACK: This is directly referencing an impl name.  BAD!
-	// This can be removed when we have a truly generic media browser that only 
-	// builds an impl based on the type of url it is passed.
-
-	// is media playing on this face?
+	// Does this face have media?
 	const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
 	LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL;
 	viewer_media_t media_impl = mep ? LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()) : NULL;
@@ -1051,11 +1042,9 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
 		&& gSavedSettings.getBOOL("MediaOnAPrimUI")
 		&& media_impl.notNull())
 	{
-		// LLObjectSelectionHandle selection = /*LLViewerMediaFocus::getInstance()->getSelection()*/ LLSelectMgr::getInstance()->getSelection();
-		if (/*! selection->contains(pick.getObject(), pick.mObjectFace)*/
-			! LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) )
+		if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) )
 		{
-			LLViewerMediaFocus::getInstance()->setFocusFace(TRUE, pick.getObject(), pick.mObjectFace, media_impl);
+			LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
 		}
 		else
 		{
@@ -1067,7 +1056,6 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
 		return true;
 	}
 
-	LLSelectMgr::getInstance()->deselect();
 	LLViewerMediaFocus::getInstance()->clearFocus();
 
 	return false;
@@ -1081,50 +1069,50 @@ bool LLToolPie::handleMediaHover(const LLPickInfo& pick)
 
 	LLPointer<LLViewerObject> objectp = pick.getObject();
 
-	// Early out cases.  Must clear mouse over media focus flag
+	// Early out cases.  Must clear media hover. 
 	// did not hit an object or did not hit a valid face
 	if ( objectp.isNull() ||
 		pick.mObjectFace < 0 || 
 		pick.mObjectFace >= objectp->getNumTEs() )
 	{
-		LLViewerMediaFocus::getInstance()->setMouseOverFlag(false);
+		LLViewerMediaFocus::getInstance()->clearHover();
 		return false;
 	}
 
-
-	// HACK: This is directly referencing an impl name.  BAD!
-	// This can be removed when we have a truly generic media browser that only 
-	// builds an impl based on the type of url it is passed.
-
-	// is media playing on this face?
+	// Does this face have media?
 	const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
 	const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
 	if (mep
 		&& gSavedSettings.getBOOL("MediaOnAPrimUI"))
 	{		
 		viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
-		if(LLViewerMediaFocus::getInstance()->getFocus() && media_impl.notNull())
-		{
-			media_impl->mouseMove(pick.mUVCoords);
-
-			gViewerWindow->setCursor(media_impl->getLastSetCursor());
-		}
-		else
+		
+		if(media_impl.notNull())
 		{
-			gViewerWindow->setCursor(UI_CURSOR_ARROW);
-		}
+			// Update media hover object
+			if (!LLViewerMediaFocus::getInstance()->isHoveringOverFace(objectp, pick.mObjectFace))
+			{
+				LLViewerMediaFocus::getInstance()->setHoverFace(objectp, pick.mObjectFace, media_impl, pick.mNormal);
+			}
+			
+			// If this is the focused media face, send mouse move events.
+			if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace))
+			{
+				media_impl->mouseMove(pick.mUVCoords);
+				gViewerWindow->setCursor(media_impl->getLastSetCursor());
+			}
+			else
+			{
+				// This is not the focused face -- set the default cursor.
+				gViewerWindow->setCursor(UI_CURSOR_ARROW);
+			}
 
-		// Set mouse over flag if unset
-		if (! LLViewerMediaFocus::getInstance()->getMouseOverFlag())
-		{
-			LLSelectMgr::getInstance()->setHoverObject(objectp, pick.mObjectFace);
-			LLViewerMediaFocus::getInstance()->setMouseOverFlag(true, media_impl);
-			LLViewerMediaFocus::getInstance()->setPickInfo(pick);
+			return true;
 		}
-
-		return true;
 	}
-	LLViewerMediaFocus::getInstance()->setMouseOverFlag(false);
+	
+	// In all other cases, clear media hover.
+	LLViewerMediaFocus::getInstance()->clearHover();
 
 	return false;
 }
diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c643e78dec9ee2fcd8f0833a7697ec3308a75f6
--- /dev/null
+++ b/indra/newview/lluilistener.cpp
@@ -0,0 +1,50 @@
+/**
+ * @file   lluilistener.cpp
+ * @author Nat Goodspeed
+ * @date   2009-08-18
+ * @brief  Implementation for lluilistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "llviewerprecompiledheaders.h"
+// associated header
+#include "lluilistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "lluictrl.h"
+#include "llerror.h"
+
+LLUIListener::LLUIListener(const std::string& name):
+    LLDispatchListener(name, "op")
+{
+    add("call", &LLUIListener::call, LLSD().insert("function", LLSD()));
+}
+
+void LLUIListener::call(const LLSD& event) const
+{
+    LLUICtrl::commit_callback_t* func =
+        LLUICtrl::CommitCallbackRegistry::getValue(event["function"]);
+    if (! func)
+    {
+        // This API is intended for use by a script. It's a fire-and-forget
+        // API: we provide no reply. Therefore, a typo in the script will
+        // provide no feedback whatsoever to that script. To rub the coder's
+        // nose in such an error, crump rather than quietly ignoring it.
+        LL_ERRS("LLUIListener") << "function '" << event["function"] << "' not found" << LL_ENDL;
+    }
+    else
+    {
+        // Interestingly, view_listener_t::addMenu() (addCommit(),
+        // addEnable()) constructs a commit_callback_t callable that accepts
+        // two parameters but discards the first. Only the second is passed to
+        // handleEvent(). Therefore we feel completely safe passing NULL for
+        // the first parameter.
+        (*func)(NULL, event["parameter"]);
+    }
+}
diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea904a99ff86b82bae69b85d79a920ad5d84cc9f
--- /dev/null
+++ b/indra/newview/lluilistener.h
@@ -0,0 +1,29 @@
+/**
+ * @file   lluilistener.h
+ * @author Nat Goodspeed
+ * @date   2009-08-18
+ * @brief  Engage named functions as specified by XUI
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLUILISTENER_H)
+#define LL_LLUILISTENER_H
+
+#include "lleventdispatcher.h"
+#include <string>
+
+class LLSD;
+
+class LLUIListener: public LLDispatchListener
+{
+public:
+    LLUIListener(const std::string& name);
+
+private:
+    void call(const LLSD& event) const;
+};
+
+#endif /* ! defined(LL_LLUILISTENER_H) */
diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ecba1b8eb0a3ea26dc4aa33eb24d1856f96ecf6b
--- /dev/null
+++ b/indra/newview/llviewercontrollistener.cpp
@@ -0,0 +1,102 @@
+/**
+ * @file   llviewercontrollistener.cpp
+ * @author Brad Kittenbrink
+ * @date   2009-07-09
+ * @brief  Implementation for llviewercontrollistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewercontrollistener.h"
+
+#include "llviewercontrol.h"
+
+LLViewerControlListener gSavedSettingsListener;
+
+LLViewerControlListener::LLViewerControlListener()
+	: LLDispatchListener("LLViewerControl",  "group")
+{
+	add("Global", boost::bind(&LLViewerControlListener::set, &gSavedSettings, _1));
+	add("PerAccount", boost::bind(&LLViewerControlListener::set, &gSavedPerAccountSettings, _1));
+	add("Warning", boost::bind(&LLViewerControlListener::set, &gWarningSettings, _1));
+	add("Crash", boost::bind(&LLViewerControlListener::set, &gCrashSettings, _1));
+
+#if 0
+	add(/*"toggleControl",*/ "Global", boost::bind(&LLViewerControlListener::toggleControl, &gSavedSettings, _1));
+	add(/*"toggleControl",*/ "PerAccount", boost::bind(&LLViewerControlListener::toggleControl, &gSavedPerAccountSettings, _1));
+	add(/*"toggleControl",*/ "Warning", boost::bind(&LLViewerControlListener::toggleControl, &gWarningSettings, _1));
+	add(/*"toggleControl",*/ "Crash", boost::bind(&LLViewerControlListener::toggleControl, &gCrashSettings, _1));
+
+	add(/*"setDefault",*/ "Global", boost::bind(&LLViewerControlListener::setDefault, &gSavedSettings, _1));
+	add(/*"setDefault",*/ "PerAccount", boost::bind(&LLViewerControlListener::setDefault, &gSavedPerAccountSettings, _1));
+	add(/*"setDefault",*/ "Warning", boost::bind(&LLViewerControlListener::setDefault, &gWarningSettings, _1));
+	add(/*"setDefault",*/ "Crash", boost::bind(&LLViewerControlListener::setDefault, &gCrashSettings, _1));
+#endif // 0
+}
+
+//static
+void LLViewerControlListener::set(LLControlGroup * controls, LLSD const & event_data)
+{
+	if(event_data.has("key"))
+	{
+		std::string key(event_data["key"]);
+
+		if(controls->controlExists(key))
+		{
+			controls->setUntypedValue(key, event_data["value"]);
+		}
+		else
+		{
+			llwarns << "requested unknown control: \"" << key << '\"' << llendl;
+		}
+	}
+}
+
+//static
+void LLViewerControlListener::toggleControl(LLControlGroup * controls, LLSD const & event_data)
+{
+	if(event_data.has("key"))
+	{
+		std::string key(event_data["key"]);
+
+		if(controls->controlExists(key))
+		{
+			LLControlVariable * control = controls->getControl(key);
+			if(control->isType(TYPE_BOOLEAN))
+			{
+				control->set(!control->get().asBoolean());
+			}
+			else
+			{
+				llwarns << "requested toggle of non-boolean control: \"" << key << "\", type is " << control->type() << llendl;
+			}
+		}
+		else
+		{
+			llwarns << "requested unknown control: \"" << key << '\"' << llendl;
+		}
+	}
+}
+
+//static
+void LLViewerControlListener::setDefault(LLControlGroup * controls, LLSD const & event_data)
+{
+	if(event_data.has("key"))
+	{
+		std::string key(event_data["key"]);
+
+		if(controls->controlExists(key))
+		{
+			LLControlVariable * control = controls->getControl(key);
+			control->resetToDefault();
+		}
+		else
+		{
+			llwarns << "requested unknown control: \"" << key << '\"' << llendl;
+		}
+	}
+}
diff --git a/indra/newview/llviewercontrollistener.h b/indra/newview/llviewercontrollistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..cacf97e908e8f6784339e155b20267b718acfbdf
--- /dev/null
+++ b/indra/newview/llviewercontrollistener.h
@@ -0,0 +1,33 @@
+/**
+ * @file   llviewercontrollistener.h
+ * @author Brad Kittenbrink
+ * @date   2009-07-09
+ * @brief  Event API for subset of LLViewerControl methods
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERCONTROLLISTENER_H
+#define LL_LLVIEWERCONTROLLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLControlGroup;
+class LLSD;
+
+class  LLViewerControlListener : public LLDispatchListener
+{
+public:
+	LLViewerControlListener();
+
+private:
+	static void set(LLControlGroup *controls, LLSD const & event_data);
+	static void toggleControl(LLControlGroup *controls, LLSD const & event_data);
+	static void setDefault(LLControlGroup *controls, LLSD const & event_data);
+};
+
+extern LLViewerControlListener gSavedSettingsListener;
+
+#endif // LL_LLVIEWERCONTROLLISTENER_H
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index b8e945a7b827df1e8d373b5a87469483ef3ad944..5967b68e516c14cfa3de42a7f6fd7fccb6aebe2e 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -588,7 +588,9 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
 	mHasFocus(false),
 	mPriority(LLPluginClassMedia::PRIORITY_UNLOADED),
 	mDoNavigateOnLoad(false),
+	mDoNavigateOnLoadRediscoverType(false),
 	mDoNavigateOnLoadServerRequest(false),
+	mMediaSourceFailedInit(false),
 	mIsUpdated(false)
 { 
 	
@@ -638,13 +640,18 @@ void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObser
 //////////////////////////////////////////////////////////////////////////////////////////
 bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)
 {
-	if((mMediaSource == NULL) || (mMimeType != mime_type))
+	bool mimeTypeChanged = (mMimeType != mime_type);
+	bool pluginChanged = (LLMIMETypes::implType(mMimeType) != LLMIMETypes::implType(mime_type));
+	
+	if(!mMediaSource || pluginChanged)
 	{
-		if(! initializePlugin(mime_type))
-		{
-			// This may be the case where the plugin's priority is PRIORITY_UNLOADED
-			return false;
-		}
+		// We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type.
+		(void)initializePlugin(mime_type);
+	}
+	else if(mimeTypeChanged)
+	{
+		// The same plugin should be able to handle the new media -- just update the stored mime type.
+		mMimeType = mime_type;
 	}
 
 	// play();
@@ -664,7 +671,7 @@ void LLViewerMediaImpl::createMediaSource()
 	{
 		if(! mMediaURL.empty())
 		{
-			navigateTo(mMediaURL, mMimeType, false, mDoNavigateOnLoadServerRequest);
+			navigateTo(mMediaURL, mMimeType, mDoNavigateOnLoadRediscoverType, mDoNavigateOnLoadServerRequest);
 		}
 		else if(! mMimeType.empty())
 		{
@@ -703,7 +710,7 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
 LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height)
 {
 	std::string plugin_basename = LLMIMETypes::implType(media_type);
-
+	
 	if(plugin_basename.empty())
 	{
 		LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL;
@@ -774,6 +781,9 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 		return false;
 	}
 
+	// If we got here, we want to ignore previous init failures.
+	mMediaSourceFailedInit = false;
+
 	LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight);
 	
 	if (media_source)
@@ -787,6 +797,9 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 		return true;
 	}
 
+	// Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes.
+	mMediaSourceFailedInit = true;
+
 	return false;
 }
 
@@ -828,7 +841,15 @@ void LLViewerMediaImpl::stop()
 {
 	if(mMediaSource)
 	{
-		mMediaSource->stop();
+		if(mMediaSource->pluginSupportsMediaBrowser())
+		{
+			mMediaSource->browse_stop();
+		}
+		else
+		{
+			mMediaSource->stop();
+		}
+
 		// destroyMediaSource();
 	}
 }
@@ -1002,21 +1023,69 @@ BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask)
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateHome()
+void LLViewerMediaImpl::navigateBack()
 {
-	mMediaURL = mHomeURL;
-	mDoNavigateOnLoad = !mMediaURL.empty();
-	mDoNavigateOnLoadServerRequest = false;
-	
-	if(mMediaSource)
+	if (mMediaSource)
+	{
+		if(mMediaSource->pluginSupportsMediaTime())
+		{
+			F64 step_scale = 0.02; // temp , can be changed
+			F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale);
+			if(back_step < 0.0)
+			{
+				back_step = 0.0;
+			}
+			mMediaSource->seek(back_step);
+			//mMediaSource->start(-2.0);
+		}
+		else
+		{
+			mMediaSource->browse_back();
+		}
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::navigateForward()
+{
+	if (mMediaSource)
 	{
-		mMediaSource->loadURI( mHomeURL );
+		if(mMediaSource->pluginSupportsMediaTime())
+		{
+			F64 step_scale = 0.02; // temp , can be changed
+			F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale);
+			if(forward_step > mMediaSource->getDuration())
+			{
+				forward_step = mMediaSource->getDuration();
+			}
+			mMediaSource->seek(forward_step);
+			//mMediaSource->start(2.0);
+		}
+		else
+		{
+			mMediaSource->browse_forward();
+		}
 	}
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::navigateReload()
+{
+	navigateTo(mMediaURL, "", true, false);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::navigateHome()
+{
+	navigateTo(mHomeURL, "", true, false);
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type,  bool rediscover_type, bool server_request)
 {
+	// Helpful to have media urls in log file. Shouldn't be spammy.
+	llinfos << "url=" << url << " mime_type=" << mime_type << llendl;
+	
 	if(server_request)
 	{
 		setNavState(MEDIANAVSTATE_SERVER_SENT);
@@ -1026,12 +1095,16 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
 		setNavState(MEDIANAVSTATE_NONE);
 	}
 	
-	// Always set the current URL.
+	// Always set the current URL and MIME type.
 	mMediaURL = url;
+	mMimeType = mime_type;
 	
 	// If the current URL is not null, make the instance do a navigate on load.
 	mDoNavigateOnLoad = !mMediaURL.empty();
 
+	// if mime type discovery was requested, we'll need to do it when the media loads
+	mDoNavigateOnLoadRediscoverType = rediscover_type;
+	
 	// and if this was a server request, the navigate on load will also need to be one.
 	mDoNavigateOnLoadServerRequest = server_request;
 
@@ -1042,6 +1115,21 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
 		
 		return;
 	}
+	
+	// If the caller has specified a non-empty MIME type, look that up in our MIME types list.
+	// If we have a plugin for that MIME type, use that instead of attempting auto-discovery.
+	// This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type
+	// but the parcel owner has correctly set the MIME type in the parcel media settings.
+	
+	if(!mMimeType.empty() && (mMimeType != "none/none"))
+	{
+		std::string plugin_basename = LLMIMETypes::implType(mMimeType);
+		if(!plugin_basename.empty())
+		{
+			// We have a plugin for this mime type
+			rediscover_type = false;
+		}
+	}
 
 	if(rediscover_type)
 	{
@@ -1101,10 +1189,41 @@ void LLViewerMediaImpl::navigateStop()
 bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
 {
 	bool result = false;
+	// *NOTE:Mani - if this doesn't exist llmozlib goes crashy in the debug build.
+	// LLMozlib::init wants to write some files to <exe_dir>/components
+	std::string debug_init_component_dir( gDirUtilp->getExecutableDir() );
+	debug_init_component_dir += "/components";
+	LLAPRFile::makeDir(debug_init_component_dir.c_str()); 
 	
 	if (mMediaSource)
 	{
-		result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask);
+		// FIXME: THIS IS SO WRONG.
+		// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
+		if( MASK_CONTROL & mask )
+		{
+			if( 'C' == key )
+			{
+				mMediaSource->copy();
+				result = true;
+			}
+			else
+			if( 'V' == key )
+			{
+				mMediaSource->paste();
+				result = true;
+			}
+			else
+			if( 'X' == key )
+			{
+				mMediaSource->cut();
+				result = true;
+			}
+		}
+		
+		if(!result)
+		{
+			result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask);
+		}
 	}
 	
 	return result;
@@ -1117,7 +1236,12 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
 	
 	if (mMediaSource)
 	{
-		mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)));
+		// only accept 'printable' characters, sigh...
+		if (uni_char >= 32 // discard 'control' characters
+			&& uni_char != 127) // SDL thinks this is 'delete' - yuck.
+		{
+			mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)));
+		}
 	}
 	
 	return result;
@@ -1148,7 +1272,7 @@ bool LLViewerMediaImpl::canNavigateBack()
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::update()
 {
-	if(mMediaSource == NULL)
+	if(mMediaSource == NULL && !mMediaSourceFailedInit)
 	{
 		if(mPriority != LLPluginClassMedia::PRIORITY_UNLOADED)
 		{
@@ -1375,6 +1499,18 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 {
 	switch(event)
 	{
+		case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
+		{
+			// The plugin failed to load properly.  Make sure the timer doesn't retry.
+			mMediaSourceFailedInit = true;
+			
+			// TODO: may want a different message for this case?
+			LLSD args;
+			args["PLUGIN"] = LLMIMETypes::implType(mMimeType);
+			LLNotifications::instance().add("MediaPluginFailed", args);
+		}
+		break;
+
 		case MEDIA_EVENT_PLUGIN_FAILED:
 		{
 			LLSD args;
@@ -1423,7 +1559,19 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
 		{
 			LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL;
-			setNavState(MEDIANAVSTATE_NONE);
+
+			if(getNavState() == MEDIANAVSTATE_BEGUN)
+			{
+				setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED);
+			}
+			else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN)
+			{
+				setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED);
+			}
+			else
+			{
+				// all other cases need to leave the state alone.
+			}
 		}
 		break;
 		
@@ -1536,8 +1684,7 @@ void LLViewerMediaImpl::calculateInterest()
 	}
 	else
 	{
-		// I don't think this case should ever be hit.
-		LL_WARNS("Plugin") << "no texture!" << LL_ENDL;
+		// This will be a relatively common case now, since it will always be true for unloaded media.
 		mInterest = 0.0f;
 	}
 }
@@ -1626,9 +1773,11 @@ void LLViewerMediaImpl::setNavState(EMediaNavState state)
 		case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break;
 		case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break;
 		case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break;
+		case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break;
 		case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break;
 		case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break;
 		case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break;
+		case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break;
 	}
 }
 
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index c9ba5841e9391368ce150202265b588787e75ee8..fc2776ee91eeca10e69a72e08c0a6531081b5ffa 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -141,7 +141,10 @@ class LLViewerMediaImpl
 	void mouseMove(const LLVector2& texture_coords);
 	void mouseLeftDoubleClick(S32 x,S32 y );
 	void mouseCapture();
-
+	
+	void navigateBack();
+	void navigateForward();
+	void navigateReload();
 	void navigateHome();
 	void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false);
 	void navigateStop();
@@ -240,12 +243,14 @@ class LLViewerMediaImpl
 	
 	typedef enum 
 	{
-		MEDIANAVSTATE_NONE,								// State is outside what we need to track for navigation.
-		MEDIANAVSTATE_BEGUN,							// a MEDIA_EVENT_NAVIGATE_BEGIN has been received which was not server-directed
-		MEDIANAVSTATE_FIRST_LOCATION_CHANGED,			// first LOCATION_CHANGED event after a non-server-directed BEGIN
-		MEDIANAVSTATE_SERVER_SENT,						// server-directed nav has been requested, but MEDIA_EVENT_NAVIGATE_BEGIN hasn't been received yet
-		MEDIANAVSTATE_SERVER_BEGUN,						// MEDIA_EVENT_NAVIGATE_BEGIN has been received which was server-directed
-		MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED		// first LOCATION_CHANGED event after a server-directed BEGIN
+		MEDIANAVSTATE_NONE,										// State is outside what we need to track for navigation.
+		MEDIANAVSTATE_BEGUN,									// a MEDIA_EVENT_NAVIGATE_BEGIN has been received which was not server-directed
+		MEDIANAVSTATE_FIRST_LOCATION_CHANGED,					// first LOCATION_CHANGED event after a non-server-directed BEGIN
+		MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED,			// we received a NAVIGATE_COMPLETE event before the first LOCATION_CHANGED
+		MEDIANAVSTATE_SERVER_SENT,								// server-directed nav has been requested, but MEDIA_EVENT_NAVIGATE_BEGIN hasn't been received yet
+		MEDIANAVSTATE_SERVER_BEGUN,								// MEDIA_EVENT_NAVIGATE_BEGIN has been received which was server-directed
+		MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED,			// first LOCATION_CHANGED event after a server-directed BEGIN
+		MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED	// we received a NAVIGATE_COMPLETE event before the first LOCATION_CHANGED
 		
 	}EMediaNavState;
     
@@ -278,7 +283,9 @@ class LLViewerMediaImpl
 	bool mHasFocus;
 	LLPluginClassMedia::EPriority mPriority;
 	bool mDoNavigateOnLoad;
+	bool mDoNavigateOnLoadRediscoverType;
 	bool mDoNavigateOnLoadServerRequest;
+	bool mMediaSourceFailedInit;
 
 
 private:
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index f9377ab37bb821f6e06b0d07c88cbbf3fb51d5b2..cad8b5f0ceca7d61f609d01cfda91752936784a1 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -53,7 +53,8 @@
 //
 
 LLViewerMediaFocus::LLViewerMediaFocus()
-: mMouseOverFlag(false)
+:	mFocusedObjectFace(0),
+	mHoverObjectFace(0)
 {
 }
 
@@ -63,110 +64,100 @@ LLViewerMediaFocus::~LLViewerMediaFocus()
 	// Clean up in cleanupClass() instead.
 }
 
-void LLViewerMediaFocus::cleanupClass()
-{
-	LLViewerMediaFocus *self = LLViewerMediaFocus::getInstance();
-	
-	if(self)
-	{
-		// mMediaHUD will have been deleted by this point -- don't try to delete it.
-
-		/* Richard says:
-			all widgets are supposed to be destroyed at the same time
-			you shouldn't hold on to pointer to them outside of ui code		
-			you can use the LLHandle approach
-			if you want to be type safe, you'll need to add a LLRootHandle to whatever derived class you are pointing to
-			look at llview::gethandle
-			its our version of a weak pointer			
-		*/
-		if(self->mMediaHUD.get())
-		{
-			self->mMediaHUD.get()->setMediaImpl(NULL);
-		}
-		self->mMediaImpl = NULL;
-	}
-	
-}
-
-
-void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl )
-{
+void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal)
+{	
 	LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-
-	if(mMediaImpl.notNull())
+	
+	LLViewerMediaImpl *old_media_impl = getFocusedMediaImpl();
+	if(old_media_impl)
 	{
-		mMediaImpl->focus(false);
+		old_media_impl->focus(false);
 	}
 
-	if (b && media_impl.notNull())
+	if (media_impl.notNull() && objectp.notNull())
 	{
 		bool face_auto_zoom = false;
-		mMediaImpl = media_impl;
-		mMediaImpl->focus(true);
+		media_impl->focus(true);
 
-		LLSelectMgr::getInstance()->deselectAll();
-		LLSelectMgr::getInstance()->selectObjectOnly(objectp, face);
+		mFocusedImplID = media_impl->getMediaTextureID();
+		mFocusedObjectID = objectp->getID();
+		mFocusedObjectFace = face;
+		mFocusedObjectNormal = pick_normal;
 
-		if(objectp.notNull())
+		LLTextureEntry* tep = objectp->getTE(face);
+		if(tep->hasMedia())
 		{
-			LLTextureEntry* tep = objectp->getTE(face);
-			if(! tep->hasMedia())
-			{
-				// Error condition
-			}
 			LLMediaEntry* mep = tep->getMediaData();
 			face_auto_zoom = mep->getAutoZoom();
-			if(! mep->getAutoPlay())
+			if(!media_impl->hasMedia())
 			{
 				std::string url = mep->getCurrentURL().empty() ? mep->getHomeURL() : mep->getCurrentURL();
 				media_impl->navigateTo(url, "", true);
 			}
 		}
-		mFocus = LLSelectMgr::getInstance()->getSelection();
+		else
+		{
+			// This should never happen.
+			llwarns << "Can't find media entry for focused face" << llendl;
+		}
+
+		gFocusMgr.setKeyboardFocus(this);
+		
+		// We must do this before  processing the media HUD zoom, or it may zoom to the wrong face. 
+		update();
+
 		if(mMediaHUD.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom())
 		{
 			mMediaHUD.get()->resetZoomLevel();
 			mMediaHUD.get()->nextZoomLevel();
 		}
-		if (!mFocus->isEmpty())
-		{
-			gFocusMgr.setKeyboardFocus(this);
-		}
-		mObjectID = objectp->getID();
-		mObjectFace = face;
-		// LLViewerMedia::addObserver(this, mObjectID);
-
-
 	}
 	else
 	{
-		gFocusMgr.setKeyboardFocus(NULL);
-		if(! parcel->getMediaPreventCameraZoom())
+		if(hasFocus())
 		{
-			if (!mFocus->isEmpty())
+			if(mMediaHUD.get())
 			{
-				gAgent.setFocusOnAvatar(TRUE, ANIMATE);
+				mMediaHUD.get()->resetZoomLevel();
 			}
+
+			gFocusMgr.setKeyboardFocus(NULL);
 		}
-		mFocus = NULL;
-		// LLViewerMedia::remObserver(this, mObjectID);
 		
-		// Null out the media hud media pointer
-		if(mMediaHUD.get())
-		{
-			mMediaHUD.get()->setMediaImpl(NULL);
-		}
+		mFocusedImplID = LLUUID::null;
+		mFocusedObjectID = LLUUID::null;
+		mFocusedObjectFace = 0;
+	}
+}
 
-		// and null out the media impl
-		mMediaImpl = NULL;
-		mObjectID = LLUUID::null;
-		mObjectFace = 0;
+void LLViewerMediaFocus::clearFocus()
+{
+	setFocusFace(NULL, 0, NULL);
+}
+
+void LLViewerMediaFocus::setHoverFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal)
+{
+	if (media_impl.notNull())
+	{
+		mHoverImplID = media_impl->getMediaTextureID();
+		mHoverObjectID = objectp->getID();
+		mHoverObjectFace = face;
+		mHoverObjectNormal = pick_normal;
 	}
-	if(mMediaHUD.get())
+	else
 	{
-		mMediaHUD.get()->setMediaFocus(b);
+		mHoverObjectID = LLUUID::null;
+		mHoverObjectFace = 0;
+		mHoverImplID = LLUUID::null;
 	}
 }
+
+void LLViewerMediaFocus::clearHover()
+{
+	setHoverFace(NULL, 0, NULL);
+}
+
+
 bool LLViewerMediaFocus::getFocus()
 {
 	if (gFocusMgr.getKeyboardFocus() == this)
@@ -176,22 +167,15 @@ bool LLViewerMediaFocus::getFocus()
 	return false;
 }
 
-// This function selects an ideal viewing distance given a selection bounding box, normal, and padding value
-void LLViewerMediaFocus::setCameraZoom(F32 padding_factor)
+// This function selects an ideal viewing distance based on the focused object, pick normal, and padding value
+void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 padding_factor)
 {
-	LLPickInfo& pick = LLToolPie::getInstance()->getPick();
-
-	if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
-	{
-		pick = mPickInfo;
-		setFocusFace(true, pick.getObject(), pick.mObjectFace, mMediaImpl);
-	}
-
-	if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
+	if (object)
 	{
 		gAgent.setFocusOnAvatar(FALSE, ANIMATE);
 
-		LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
+		LLBBox bbox = object->getBoundingBoxAgent();
+		LLVector3d center = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent());
 		F32 height;
 		F32 width;
 		F32 depth;
@@ -199,7 +183,7 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor)
 		F32 distance;
 
 		// We need the aspect ratio, and the 3 components of the bbox as height, width, and depth.
-		F32 aspect_ratio = getBBoxAspectRatio(selection_bbox, pick.mNormal, &height, &width, &depth);
+		F32 aspect_ratio = getBBoxAspectRatio(bbox, normal, &height, &width, &depth);
 		F32 camera_aspect = LLViewerCamera::getInstance()->getAspect();
 
 		// We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for 
@@ -227,84 +211,97 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor)
 		distance += depth * 0.5;
 
 		// Finally animate the camera to this new position and focal point
-		gAgent.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(pick.mNormal * distance), 
-			LLSelectMgr::getInstance()->getSelectionCenterGlobal(), LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID );
+		LLVector3d camera_pos, target_pos;
+		// The target lookat position is the center of the selection (in global coords)
+		target_pos = center;
+		// Target look-from (camera) position is "distance" away from the target along the normal 
+		LLVector3d pickNormal = LLVector3d(normal);
+		pickNormal.normalize();
+        camera_pos = target_pos + pickNormal * distance;
+        if (pickNormal == LLVector3d::z_axis || pickNormal == LLVector3d::z_axis_neg)
+        {
+			// If the normal points directly up, the camera will "flip" around.
+			// We try to avoid this by adjusting the target camera position a 
+			// smidge towards current camera position
+			// *NOTE: this solution is not perfect.  All it attempts to solve is the
+			// "looking down" problem where the camera flips around when it animates
+			// to that position.  You still are not guaranteed to be looking at the
+			// media in the correct orientation.  What this solution does is it will
+			// put the camera into position keeping as best it can the current 
+			// orientation with respect to the face.  In other words, if before zoom
+			// the media appears "upside down" from the camera, after zooming it will
+			// still be upside down, but at least it will not flip.
+            LLVector3d cur_camera_pos = LLVector3d(gAgent.getCameraPositionGlobal());
+            LLVector3d delta = (cur_camera_pos - camera_pos);
+            F64 len = delta.length();
+            delta.normalize();
+            // Move 1% of the distance towards original camera location
+            camera_pos += 0.01 * len * delta;
+        }
+
+		gAgent.setCameraPosAndFocusGlobal(camera_pos, target_pos, object->getID() );
+	}
+	else
+	{
+		// If we have no object, focus back on the avatar.
+		gAgent.setFocusOnAvatar(TRUE, ANIMATE);
 	}
 }
 void LLViewerMediaFocus::onFocusReceived()
 {
-	if(mMediaImpl.notNull())
-		mMediaImpl->focus(true);
+	// Don't do this here -- this doesn't change "inworld media focus", it just changes whether the viewer's input is focused on the media.
+//	LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
+//	if(media_impl.notNull())
+//		media_impl->focus(true);
 
 	LLFocusableElement::onFocusReceived();
 }
 
 void LLViewerMediaFocus::onFocusLost()
 {
-	if(mMediaImpl.notNull())
-		mMediaImpl->focus(false);
+	// Don't do this here -- this doesn't change "inworld media focus", it just changes whether the viewer's input is focused on the media.
+//	LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
+//	if(media_impl.notNull())
+//		media_impl->focus(false);
+
 	gViewerWindow->focusClient();
-	mFocus = NULL;
 	LLFocusableElement::onFocusLost();
 }
-void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl)
+
+BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 {
-	if (b && media_impl.notNull())
+	LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
+	if(media_impl)
 	{
-		if(! mMediaHUD.get())
-		{
-			LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(mMediaImpl);
-			mMediaHUD = media_hud->getHandle();
-			gHUDView->addChild(media_hud);	
-		}
-		mMediaHUD.get()->setMediaImpl(media_impl);
+		media_impl->handleKeyHere(key, mask);
 
-		if(mMediaImpl.notNull() && (mMediaImpl != media_impl))
+		if (key == KEY_ESCAPE)
 		{
-			mMediaImpl->focus(false);
+			clearFocus();
 		}
-
-		mMediaImpl = media_impl;
 	}
-	mMouseOverFlag = b;
-}
-LLUUID LLViewerMediaFocus::getSelectedUUID() 
-{ 
-	LLViewerObject* object = mFocus->getFirstObject();
-	return object ? object->getID() : LLUUID::null; 
-}
-#if 0 // Must re-implement when the new media api event system is ready
-void LLViewerMediaFocus::onNavigateComplete( const EventType& event_in )
-{
-	if (hasFocus() && mLastURL != event_in.getStringValue())
-	{
-		LLViewerMedia::focus(true, mObjectID);
-		// spoof mouse event to reassert focus
-		LLViewerMedia::mouseDown(1,1, mObjectID);
-		LLViewerMedia::mouseUp(1,1, mObjectID);
-	}
-	mLastURL = event_in.getStringValue();
-}
-#endif
-BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent)
-{
-	if(mMediaImpl.notNull())
-		mMediaImpl->handleKeyHere(key, mask);
+	
 	return true;
 }
 
 BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
-	if(mMediaImpl.notNull())
-		mMediaImpl->handleUnicodeCharHere(uni_char);
+	LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
+	if(media_impl)
+		media_impl->handleUnicodeCharHere(uni_char);
 	return true;
 }
 BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
 	BOOL retval = FALSE;
-	if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia())
+	LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
+	if(media_impl && media_impl->hasMedia())
 	{
-		mMediaImpl->getMediaPlugin()->scrollEvent(x, y, clicks);
+        // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y.
+        // The latter is the position of the mouse at the time of the event
+        // The former is the 'scroll amount' in x and y, respectively.
+        // All we have for 'scroll amount' here is 'clicks', and no mask.
+		media_impl->getMediaPlugin()->scrollEvent(0, clicks, /*mask*/0);
 		retval = TRUE;
 	}
 	return retval;
@@ -312,19 +309,45 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks)
 
 void LLViewerMediaFocus::update()
 {
-	if (mMediaHUD.get())
+	LLViewerMediaImpl *media_impl = getFocusedMediaImpl();
+	LLViewerObject *viewer_object = getFocusedObject();
+	S32 face = mFocusedObjectFace;
+	LLVector3 normal = mFocusedObjectNormal;
+	bool focus = true;
+	
+	if(!media_impl || !viewer_object)
 	{
-		if(mFocus.notNull() || mMouseOverFlag || mMediaHUD.get()->isMouseOver())
+		focus = false;
+		media_impl = getHoverMediaImpl();
+		viewer_object = getHoverObject();
+		face = mHoverObjectFace;
+		normal = mHoverObjectNormal;
+	}
+	
+	if(media_impl && viewer_object)
+	{
+		// We have an object and impl to point at.
+		
+		// Make sure the media HUD object exists.
+		if(! mMediaHUD.get())
 		{
-			// mMediaHUD.get()->setVisible(true);
-			mMediaHUD.get()->updateShape();
+			LLPanelMediaHUD* media_hud = new LLPanelMediaHUD();
+			mMediaHUD = media_hud->getHandle();
+			gHUDView->addChild(media_hud);	
 		}
-		else
+		mMediaHUD.get()->setMediaFace(viewer_object, face, media_impl, normal);
+	}
+	else
+	{
+		// The media HUD is no longer needed.
+		if(mMediaHUD.get())
 		{
-			mMediaHUD.get()->setVisible(false);
+			mMediaHUD.get()->setMediaFace(NULL, 0, NULL);
 		}
 	}
 }
+
+
 // This function calculates the aspect ratio and the world aligned components of a selection bounding box.
 F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth)
 {
@@ -393,5 +416,31 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3&
 
 bool LLViewerMediaFocus::isFocusedOnFace(LLPointer<LLViewerObject> objectp, S32 face)
 {
-	return objectp->getID() == mObjectID && face == mObjectFace;
+	return objectp->getID() == mFocusedObjectID && face == mFocusedObjectFace;
+}
+
+bool LLViewerMediaFocus::isHoveringOverFace(LLPointer<LLViewerObject> objectp, S32 face)
+{
+	return objectp->getID() == mHoverObjectID && face == mHoverObjectFace;
+}
+
+
+LLViewerMediaImpl* LLViewerMediaFocus::getFocusedMediaImpl()
+{
+	return LLViewerMedia::getMediaImplFromTextureID(mFocusedImplID);
+}
+
+LLViewerObject* LLViewerMediaFocus::getFocusedObject()
+{
+	return gObjectList.findObject(mFocusedObjectID);
+}
+
+LLViewerMediaImpl* LLViewerMediaFocus::getHoverMediaImpl()
+{
+	return LLViewerMedia::getMediaImplFromTextureID(mHoverImplID);
+}
+
+LLViewerObject* LLViewerMediaFocus::getHoverObject()
+{
+	return gObjectList.findObject(mHoverObjectID);
 }
diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h
index 2688a8b7087d6827fa70283b0ab1591ca18feaab..c77533ba5ae8ab580c47bddbb544095db4823b4c 100644
--- a/indra/newview/llviewermediafocus.h
+++ b/indra/newview/llviewermediafocus.h
@@ -50,44 +50,55 @@ class LLViewerMediaFocus :
 	LLViewerMediaFocus();
 	~LLViewerMediaFocus();
 	
-	static void cleanupClass();
-
-	void setFocusFace(BOOL b, LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl);
-	void clearFocus() { setFocusFace(false, NULL, 0, NULL); }
+	// Set/clear the face that has media focus (takes keyboard input and has the full set of controls)
+	void setFocusFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal = LLVector3::zero);
+	void clearFocus();
+	
+	// Set/clear the face that has "media hover" (has the mimimal set of controls to zoom in or pop out into a media browser).
+	// If a media face has focus, the media hover will be ignored.
+	void setHoverFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal = LLVector3::zero);
+	void clearHover();
+	
 	/*virtual*/ bool	getFocus();
-	/*virtual*/ // void onNavigateComplete( const EventType& event_in );
-
 	/*virtual*/ BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
 	/*virtual*/ BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
 
-	LLUUID getSelectedUUID();
-	LLObjectSelectionHandle getSelection() { return mFocus; }
-
 	void update();
+	
+	static void setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 padding_factor);
+	static F32 getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth);
 
-	void setCameraZoom(F32 padding_factor);
-	void setMouseOverFlag(bool b, viewer_media_t media_impl = NULL);
-	bool getMouseOverFlag() { return mMouseOverFlag; }
-	void setPickInfo(LLPickInfo pick_info) { mPickInfo = pick_info; }
-	F32 getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth);
-
-	// TODO: figure out why selection mgr hates me
 	bool isFocusedOnFace(LLPointer<LLViewerObject> objectp, S32 face);
+	bool isHoveringOverFace(LLPointer<LLViewerObject> objectp, S32 face);
+	
+	// These look up (by uuid) and return the values that were set with setFocusFace.  They will return null if the objects have been destroyed.
+	LLViewerMediaImpl* getFocusedMediaImpl();
+	LLViewerObject* getFocusedObject();
+	S32 getFocusedFace() { return mFocusedObjectFace; }
+	
+	// These look up (by uuid) and return the values that were set with setHoverFace.  They will return null if the objects have been destroyed.
+	LLViewerMediaImpl* getHoverMediaImpl();
+	LLViewerObject* getHoverObject();
+	S32 getHoverFace() { return mHoverObjectFace; }
 
 protected:
 	/*virtual*/ void	onFocusReceived();
 	/*virtual*/ void	onFocusLost();
 
 private:
-	LLObjectSelectionHandle mFocus;
-	std::string mLastURL;
-	bool mMouseOverFlag;
-	LLPickInfo mPickInfo;
+	
 	LLHandle<LLPanelMediaHUD> mMediaHUD;
-	LLUUID mObjectID;
-	S32 mObjectFace;
-	viewer_media_t mMediaImpl;
+	
+	LLUUID mFocusedObjectID;
+	S32 mFocusedObjectFace;
+	LLUUID mFocusedImplID;
+	LLVector3 mFocusedObjectNormal;
+	
+	LLUUID mHoverObjectID;
+	S32 mHoverObjectFace;
+	LLUUID mHoverImplID;
+	LLVector3 mHoverObjectNormal;
 };
 
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index dc291d6c34cf14bf883f07844677d944e55ed9bf..a1c15d9d0f3bad2d39321e4f20bd5d4d748a6d42 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -206,6 +206,7 @@
 #include "llwaterparammanager.h"
 #include "llfloaternotificationsconsole.h"
 #include "llfloatercamera.h"
+#include "lluilistener.h"
 
 #include "lltexlayer.h"
 #include "llappearancemgr.h"
@@ -413,6 +414,8 @@ class LLMenuParcelObserver : public LLParcelObserver
 
 static LLMenuParcelObserver* gMenuParcelObserver = NULL;
 
+static LLUIListener sUIListener("UI");
+
 LLMenuParcelObserver::LLMenuParcelObserver()
 {
 	LLViewerParcelMgr::getInstance()->addObserver(this);
@@ -7064,7 +7067,7 @@ void force_error_bad_memory_access(void *)
 
 void force_error_infinite_loop(void *)
 {
-    LLAppViewer::instance()->forceErrorInifiniteLoop();
+    LLAppViewer::instance()->forceErrorInfiniteLoop();
 }
 
 void force_error_software_exception(void *)
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index 918b15ef09dc5a211b4ecb64c42bc16ebe740e0e..801c46035a20e2c438d23c9b8c70ba2edb67cd54 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -35,6 +35,8 @@
 
 #include "llviewernetwork.h"
 #include "llviewercontrol.h"
+#include "llevents.h"
+#include "lllogin.h"
 
 struct LLGridData
 {
@@ -155,6 +157,10 @@ LLViewerLogin::LLViewerLogin() :
 {
 }
 
+ LLViewerLogin::~LLViewerLogin() 
+ {
+ }
+
 void LLViewerLogin::setGridChoice(EGridInfo grid)
 {	
 	if(grid < 0 || grid >= GRID_INFO_COUNT)
diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h
index 4001ed05c1e5f25eb09cf7f2edbc5db20992e598..edae6dc47b56b87f1770269bf2fde8b61261de56 100644
--- a/indra/newview/llviewernetwork.h
+++ b/indra/newview/llviewernetwork.h
@@ -34,7 +34,10 @@
 #ifndef LL_LLVIEWERNETWORK_H
 #define LL_LLVIEWERNETWORK_H
 
+#include <boost/scoped_ptr.hpp>
+
 class LLHost;
+class LLLogin;
 
 enum EGridInfo
 {
@@ -74,6 +77,7 @@ class LLViewerLogin : public LLSingleton<LLViewerLogin>
 {
 public:
 	LLViewerLogin();
+	~LLViewerLogin();
 
 	void setGridChoice(EGridInfo grid);
 	void setGridChoice(const std::string& grid_name);
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index a3f9c839a0dff6be3b54ac2df0e5413bc8c11011..6233a337a663ff8b2b7971fce0705e3379e01af4 100644
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -226,11 +226,13 @@ void LLViewerParcelMedia::play(LLParcel* parcel)
 				media_height, 
 				media_auto_scale,
 				media_loop);
-			sMediaImpl->navigateTo(media_url);
+			sMediaImpl->navigateTo(media_url, mime_type, true);
 		}
 	}
 	else
 	{
+		LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL;
+
 		// There is no media impl, make a new one
 		sMediaImpl = LLViewerMedia::newMediaImpl(
 			placeholder_texture_id,
@@ -238,7 +240,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel)
 			media_height, 
 			media_auto_scale,
 			media_loop);
-		sMediaImpl->navigateTo(media_url);
+		sMediaImpl->navigateTo(media_url, mime_type, true);
 	}
 
 	LLFirstUse::useMedia();
@@ -544,6 +546,18 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
 			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL;
 		};
 		break;
+		
+		case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL;
+		};
+		break;
+		
+		case MEDIA_EVENT_NAME_CHANGED:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAME_CHANGED" << LL_ENDL;
+		};
+		break;
 	};
 }
 
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 7ca11d83642c0a41fd87ab380fb9ffdf1ddbba53..77b023f6ddfba45e03620d90c7a45cf3878e1bed 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -56,6 +56,7 @@
 #include "llparcelselection.h"
 #include "llresmgr.h"
 #include "llsdutil.h"
+#include "llsdutil_math.h"
 #include "llstatusbar.h"
 #include "llui.h"
 #include "llviewertexture.h"
@@ -1161,10 +1162,11 @@ void LLViewerParcelMgr::sendParcelBuy(ParcelBuyInfo* info)
 	msg->sendReliable(info->mHost);
 }
 
-void LLViewerParcelMgr::deleteParcelBuy(ParcelBuyInfo*& info)
+void LLViewerParcelMgr::deleteParcelBuy(ParcelBuyInfo* *info)
 {
-	delete info;
-	info = NULL;
+	// Must be here because ParcelBuyInfo is local to this .cpp file
+	delete *info;
+	*info = NULL;
 }
 
 void LLViewerParcelMgr::sendParcelDeed(const LLUUID& group_id)
diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h
index 3964a56bf60b3450ff0ce5cb5d43b67f2656fd6d..1c8fe23dba125ed08ca0414935d84988f68ae7f3 100644
--- a/indra/newview/llviewerparcelmgr.h
+++ b/indra/newview/llviewerparcelmgr.h
@@ -246,7 +246,7 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr>
 								  BOOL remove_contribution);
 		// callers responsibility to call deleteParcelBuy() on return value
 	void sendParcelBuy(ParcelBuyInfo*);
-	void deleteParcelBuy(ParcelBuyInfo*&);
+	void deleteParcelBuy(ParcelBuyInfo* *info);
 					   
 	void sendParcelDeed(const LLUUID& group_id);
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index a0ab4cb1e68687c6064bd02ee707b8ea8af83df4..95459a7116b5021b7a89d31f1c9ad9c6d873e61a 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -2434,10 +2434,11 @@ void LLViewerMediaTexture::removeFace(LLFace* facep)
 
 void LLViewerMediaTexture::stopPlaying()
 {
-	if(mMediaImplp)
-	{
-		mMediaImplp->stop() ;
-	}
+	// Don't stop the media impl playing here -- this breaks non-inworld media (login screen, search, and media browser).
+//	if(mMediaImplp)
+//	{
+//		mMediaImplp->stop() ;
+//	}
 	mIsPlaying = FALSE ;			
 }
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5f95e9ccf1b5c67c1ff8c74a98074dab50300c64..c659e58e476d7c5c6f4f397ce3264fe80bb964b9 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -32,6 +32,10 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
 // system library includes
 #include <stdio.h>
 #include <iostream>
@@ -195,6 +199,7 @@
 #include "llfloaternotificationsconsole.h"
 
 #include "llnearbychat.h"
+#include "llviewerwindowlistener.h"
 
 #if LL_WINDOWS
 #include <tchar.h> // For Unicode conversion methods
@@ -1204,7 +1209,8 @@ LLViewerWindow::LLViewerWindow(
 	mResDirty(false),
 	mStatesDirty(false),
 	mIsFullscreenChecked(false),
-	mCurrResolutionIndex(0)
+	mCurrResolutionIndex(0),
+    mViewerWindowListener(new LLViewerWindowListener("LLViewerWindow", this))
 {
 	LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert"));
 	LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal"));
@@ -1627,7 +1633,11 @@ void LLViewerWindow::shutdownViews()
 	{
 		gMorphView->setVisible(FALSE);
 	}
-	
+
+	// DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open
+	// will crump with LL_ERRS.
+	LLModalDialog::shutdownModals();
+
 	// Delete all child views.
 	delete mRootView;
 	mRootView = NULL;
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 231b857d1f0497420c99e48b4f88f9900de9c9e1..d7c403739e492047131fa101ea03da2db3aad9e9 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -53,6 +53,8 @@
 
 #include <boost/function.hpp>
 #include <boost/signals2.hpp>
+#include <boost/scoped_ptr.hpp>
+
 
 class LLView;
 class LLViewerObject;
@@ -65,6 +67,7 @@ class LLImageRaw;
 class LLHUDIcon;
 class LLWindow;
 class LLRootView;
+class LLViewerWindowListener;
 
 #define PICK_HALF_WIDTH 5
 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1)
@@ -456,6 +459,8 @@ class LLViewerWindow : public LLWindowCallbacks
 	bool			mIsFullscreenChecked; // Did the user check the fullscreen checkbox in the display settings
 	U32			mCurrResolutionIndex;
 
+    boost::scoped_ptr<LLViewerWindowListener> mViewerWindowListener;
+
 protected:
 	static std::string sSnapshotBaseName;
 	static std::string sSnapshotDir;
diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..317e361c804d5ca93d16fe880f42307973bfe248
--- /dev/null
+++ b/indra/newview/llviewerwindowlistener.cpp
@@ -0,0 +1,87 @@
+/**
+ * @file   llviewerwindowlistener.cpp
+ * @author Nat Goodspeed
+ * @date   2009-06-30
+ * @brief  Implementation for llviewerwindowlistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "llviewerprecompiledheaders.h"
+// associated header
+#include "llviewerwindowlistener.h"
+// STL headers
+#include <map>
+// std headers
+// external library headers
+// other Linden headers
+#include "llviewerwindow.h"
+
+LLViewerWindowListener::LLViewerWindowListener(const std::string& pumpname, LLViewerWindow* llviewerwindow):
+    LLDispatchListener(pumpname, "op"),
+    mViewerWindow(llviewerwindow)
+{
+    // add() every method we want to be able to invoke via this event API.
+    LLSD saveSnapshotArgs;
+    saveSnapshotArgs["filename"] = LLSD::String();
+    saveSnapshotArgs["reply"] = LLSD::String();
+    // The following are optional, so don't build them into required prototype.
+//  saveSnapshotArgs["width"] = LLSD::Integer();
+//  saveSnapshotArgs["height"] = LLSD::Integer();
+//  saveSnapshotArgs["showui"] = LLSD::Boolean();
+//  saveSnapshotArgs["rebuild"] = LLSD::Boolean();
+//  saveSnapshotArgs["type"] = LLSD::String();
+    add("saveSnapshot", &LLViewerWindowListener::saveSnapshot, saveSnapshotArgs);
+    add("requestReshape", &LLViewerWindowListener::requestReshape);
+}
+
+void LLViewerWindowListener::saveSnapshot(const LLSD& event) const
+{
+    LLReqID reqid(event);
+    typedef std::map<LLSD::String, LLViewerWindow::ESnapshotType> TypeMap;
+    TypeMap types;
+#define tp(name) types[#name] = LLViewerWindow::SNAPSHOT_TYPE_##name
+    tp(COLOR);
+    tp(DEPTH);
+    tp(OBJECT_ID);
+#undef  tp
+    // Our add() call should ensure that the incoming LLSD does in fact
+    // contain our required arguments. Deal with the optional ones.
+    S32 width (mViewerWindow->getWindowDisplayWidth());
+    S32 height(mViewerWindow->getWindowDisplayHeight());
+    if (event.has("width"))
+        width = event["width"].asInteger();
+    if (event.has("height"))
+        height = event["height"].asInteger();
+    // showui defaults to true, requiring special treatment
+    bool showui = true;
+    if (event.has("showui"))
+        showui = event["showui"].asBoolean();
+    bool rebuild(event["rebuild"]); // defaults to false
+    LLViewerWindow::ESnapshotType type(LLViewerWindow::SNAPSHOT_TYPE_COLOR);
+    if (event.has("type"))
+    {
+        TypeMap::const_iterator found = types.find(event["type"]);
+        if (found == types.end())
+        {
+            LL_ERRS("LLViewerWindowListener") << "LLViewerWindowListener::saveSnapshot(): "
+                                              << "unrecognized type " << event["type"] << LL_ENDL;
+        }
+        type = found->second;
+    }
+    bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, rebuild, type);
+    LLSD response(reqid.makeResponse());
+    response["ok"] = ok;
+    LLEventPumps::instance().obtain(event["reply"]).post(response);
+}
+
+void LLViewerWindowListener::requestReshape(LLSD const & event_data) const
+{
+	if(event_data.has("w") && event_data.has("h"))
+	{
+		mViewerWindow->reshape(event_data["w"].asInteger(), event_data["h"].asInteger());
+	}
+}
diff --git a/indra/newview/llviewerwindowlistener.h b/indra/newview/llviewerwindowlistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..59c636ecec85b5b683019d3d7475b45dbe7673d4
--- /dev/null
+++ b/indra/newview/llviewerwindowlistener.h
@@ -0,0 +1,35 @@
+/**
+ * @file   llviewerwindowlistener.h
+ * @author Nat Goodspeed
+ * @date   2009-06-30
+ * @brief  Event API for subset of LLViewerWindow methods
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLVIEWERWINDOWLISTENER_H)
+#define LL_LLVIEWERWINDOWLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLViewerWindow;
+class LLSD;
+
+/// Listen on an LLEventPump with specified name for LLViewerWindow request events.
+class LLViewerWindowListener: public LLDispatchListener
+{
+public:
+    /// Specify the pump name on which to listen, and bind the LLViewerWindow
+    /// instance to use (e.g. gViewerWindow).
+    LLViewerWindowListener(const std::string& pumpname, LLViewerWindow* llviewerwindow);
+
+private:
+    void saveSnapshot(const LLSD& event) const;
+    void requestReshape(LLSD const & event_data) const;
+
+    LLViewerWindow* mViewerWindow;
+};
+
+#endif /* ! defined(LL_LLVIEWERWINDOWLISTENER_H) */
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 469aef62093d0ac7fe952ec5acbb33cb7833a5d6..a402aff8ab56329277db79f346eb694bf0a9365b 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -30,6 +30,12 @@
  * $/LicenseInfo$
  */
 
+#if LL_MSVC
+// disable warning about boost::lexical_cast returning uninitialized data
+// when it fails to parse the string
+#pragma warning (disable:4701)
+#endif
+
 #include "llviewerprecompiledheaders.h"
 
 #include "llvoavatar.h"
@@ -87,7 +93,12 @@
 #include "llvoiceclient.h"
 #include "llvoicevisualizer.h" // Ventrella
 
-#include "boost/lexical_cast.hpp"
+#if LL_MSVC
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
+#include <boost/lexical_cast.hpp>
 
 using namespace LLVOAvatarDefines;
 
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index d05e55a5012fe08b770fd61c892119cfa211fc48..2b2ac81487a59aa66a8d96481fcbeaa2adedd752 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -30,6 +30,12 @@
  * $/LicenseInfo$
  */
 
+#if LL_MSVC
+// disable warning about boost::lexical_cast returning uninitialized data
+// when it fails to parse the string
+#pragma warning (disable:4701)
+#endif
+
 #include "llviewerprecompiledheaders.h"
 
 #include "llvoavatarself.h"
@@ -84,7 +90,12 @@
 #include "llvoicevisualizer.h" // Ventrella
 #include "llappearancemgr.h"
 
-#include "boost/lexical_cast.hpp"
+#if LL_MSVC
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
+#include <boost/lexical_cast.hpp>
 
 using namespace LLVOAvatarDefines;
 
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index ca028269feacf7c84fbc0196513917a6e866ea76..02f63a848be57ee4569085d1cf1d4dd36c2fe482 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -6921,7 +6921,8 @@ void LLVoiceClient::notifyFriendObservers()
 
 void LLVoiceClient::lookupName(const LLUUID &id)
 {
-	gCacheName->get(id, FALSE, &LLVoiceClient::onAvatarNameLookup);
+	BOOL is_group = FALSE;
+	gCacheName->get(id, is_group, &LLVoiceClient::onAvatarNameLookup);
 }
 
 //static
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 583246c23e801a75b13b3050f4920329b0ba2445..d896e1f7db207ac50266e5aa145ee7f1b2a867da 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -91,6 +91,57 @@ LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient =
 static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
 static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
 
+// Implementation class of LLMediaDataClientObject.  See llmediadataclient.h
+class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
+{
+public:
+	LLMediaDataClientObjectImpl(LLVOVolume *obj) : mObject(obj) {}
+	LLMediaDataClientObjectImpl() { mObject = NULL; }
+	
+	virtual U8 getMediaDataCount() const 
+		{ return mObject->getNumTEs(); }
+
+	virtual LLSD getMediaDataLLSD(U8 index) const 
+		{
+			LLSD result;
+			LLTextureEntry *te = mObject->getTE(index); 
+			if (NULL != te)
+			{
+				llassert((te->getMediaData() != NULL) == te->hasMedia());
+				if (te->getMediaData() != NULL)
+				{
+					result = te->getMediaData()->asLLSD();
+				}
+			}
+			return result;
+		}
+
+	virtual LLUUID getID() const
+		{ return mObject->getID(); }
+
+	virtual void mediaNavigateBounceBack(U8 index)
+		{ mObject->mediaNavigateBounceBack(index); }
+	
+	virtual bool hasMedia() const
+		{ return mObject->hasMedia(); }
+	
+	virtual void updateObjectMediaData(LLSD const &data) 
+		{ mObject->updateObjectMediaData(data); }
+
+	virtual F64 getDistanceFromAvatar() const
+		{ return mObject->getRenderPosition().length(); }
+	
+	virtual F64 getTotalMediaInterest() const 
+		{ return mObject->getTotalMediaInterest(); }
+
+	virtual std::string getCapabilityUrl(const std::string &name) const
+		{ return mObject->getRegion()->getCapability(name); }
+	
+private:
+	LLPointer<LLVOVolume> mObject;
+};
+
+
 LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	: LLViewerObject(id, pcode, regionp),
 	  mVolumeImpl(NULL)
@@ -134,8 +185,12 @@ LLVOVolume::~LLVOVolume()
 // static
 void LLVOVolume::initClass()
 {
-    sObjectMediaClient = new LLObjectMediaDataClient();
-    sObjectMediaNavigateClient = new LLObjectMediaNavigateClient();
+	// gSavedSettings better be around
+	const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
+	const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
+	const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries");
+    sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries);
+    sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay, max_retries);
 }
 
 // static
@@ -319,13 +374,23 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 			}
 		}
 	}
-	if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) {
-		// If the media changed at all, request new media data
-		if(mMedia)
+	if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) 
+	{
+		// If only the media URL changed, and it isn't a media version URL,
+		// ignore it
+		if ( ! ( retval & (MEDIA_URL_ADDED | MEDIA_URL_UPDATED) &&
+				 mMedia && ! mMedia->mMediaURL.empty() &&
+				 ! LLTextureEntry::isMediaVersionString(mMedia->mMediaURL) ) )
 		{
-			llinfos << "Media URL: " << mMedia->mMediaURL << llendl;
+			// If the media changed at all, request new media data
+			LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " <<
+                ((mMedia) ?  mMedia->mMediaURL : std::string("")) << LL_ENDL;
+			requestMediaDataUpdate();
 		}
-		requestMediaDataUpdate();
+        else {
+            LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " <<
+                ((mMedia) ?  mMedia->mMediaURL : std::string("")) << LL_ENDL;
+        }
 	}
 	// ...and clean up any media impls
 	cleanUpMediaImpls();
@@ -1624,7 +1689,7 @@ bool LLVOVolume::hasMedia() const
 
 void LLVOVolume::requestMediaDataUpdate()
 {
-    sObjectMediaClient->fetchMedia(this);
+    sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this));
 }
 
 void LLVOVolume::cleanUpMediaImpls()
@@ -1703,6 +1768,119 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m
 	//	<< ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl;
 }
 
+void LLVOVolume::mediaNavigateBounceBack(U8 texture_index)
+{
+	// Find the media entry for this navigate
+	const LLMediaEntry* mep = NULL;
+	viewer_media_t impl = getMediaImpl(texture_index);
+	LLTextureEntry *te = getTE(texture_index);
+	if(te)
+	{
+		mep = te->getMediaData();
+	}
+	
+	if (mep && impl)
+	{
+        std::string url = mep->getCurrentURL();
+        if (url.empty())
+        {
+            url = mep->getHomeURL();
+        }
+        if (! url.empty())
+        {
+            LL_INFOS("LLMediaDataClient") << "bouncing back to URL: " << url << LL_ENDL;
+            impl->navigateTo(url, "", false, true);
+        }
+    }
+}
+
+bool LLVOVolume::hasMediaPermission(const LLMediaEntry* media_entry, MediaPermType perm_type)
+{
+    // NOTE: This logic duplicates the logic in the server (in particular, in llmediaservice.cpp).
+    if (NULL == media_entry ) return false; // XXX should we assert here?
+    
+    // The agent has permissions to navigate if:
+    // - agent has edit permissions, or
+    // - world permissions are on, or
+    // - group permissions are on, and agent_id is in the group, or
+    // - agent permissions are on, and agent_id is the owner
+    
+    if (permModify()) 
+    {
+        return true;
+    }
+    
+    U8 media_perms = (perm_type == MEDIA_PERM_INTERACT) ? media_entry->getPermsInteract() : media_entry->getPermsControl();
+    
+    // World permissions
+    if (0 != (media_perms & LLMediaEntry::PERM_ANYONE)) 
+    {
+        return true;
+    }
+    
+    // Group permissions
+    else if (0 != (media_perms & LLMediaEntry::PERM_GROUP) && permGroupOwner())
+    {
+        return true;
+    }
+    
+    // Owner permissions
+    else if (0 != (media_perms & LLMediaEntry::PERM_OWNER) && permYouOwner()) 
+    {
+        return true;
+    }
+    
+    return false;
+    
+}
+
+void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location)
+{
+	bool block_navigation = false;
+	// FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed
+	// to deal with multiple face indices.
+	int face_index = getFaceIndexWithMediaImpl(impl, -1);
+	
+	// Find the media entry for this navigate
+	LLMediaEntry* mep = NULL;
+	LLTextureEntry *te = getTE(face_index);
+	if(te)
+	{
+		mep = te->getMediaData();
+	}
+	
+	if(mep)
+	{
+		if(!mep->checkCandidateUrl(new_location))
+		{
+			block_navigation = true;
+		}
+		if (!block_navigation && !hasMediaPermission(mep, MEDIA_PERM_INTERACT))
+		{
+			block_navigation = true;
+		}
+	}
+	else
+	{
+		llwarns << "Couldn't find media entry!" << llendl;
+	}
+						
+	if(block_navigation)
+	{
+		llinfos << "blocking navigate to URI " << new_location << llendl;
+
+		// "bounce back" to the current URL from the media entry
+		mediaNavigateBounceBack(face_index);
+	}
+	else
+	{
+		
+		llinfos << "broadcasting navigate with URI " << new_location << llendl;
+
+		sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this), face_index, new_location);
+	}
+}
+
 void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event)
 {
 	switch(event)
@@ -1714,49 +1892,8 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
 			{
 				case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED:
 				{
-					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast.
-
-					bool block_navigation = false;
-					// FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed
-					// to deal with multiple face indices.
-					int face_index = getFaceIndexWithMediaImpl(impl, -1);
-					std::string new_location = plugin->getLocation();
-					
-					// Find the media entry for this navigate
-					LLMediaEntry* mep = NULL;
-					LLTextureEntry *te = getTE(face_index);
-					if(te)
-					{
-						mep = te->getMediaData();
-					}
-					
-					if(mep)
-					{
-						if(!mep->checkCandidateUrl(new_location))
-						{
-							block_navigation = true;
-						}
-					}
-					else
-					{
-						llwarns << "Couldn't find media entry!" << llendl;
-					}
-										
-					if(block_navigation)
-					{
-						llinfos << "blocking navigate to URI " << new_location << llendl;
-
-						// "bounce back" to the current URL from the media entry
-						// NOTE: the only way block_navigation can be true is if we found the media entry, so we're guaranteed here that mep is not NULL.
-						impl->navigateTo(mep->getCurrentURL());
-					}
-					else
-					{
-						
-						llinfos << "broadcasting navigate with URI " << new_location << llendl;
-
-						sObjectMediaNavigateClient->navigate(this, face_index, new_location);
-					}
+					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back.
+					mediaNavigated(impl, plugin, plugin->getLocation());
 				}
 				break;
 				
@@ -1773,6 +1910,29 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
 		}
 		break;
 		
+		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
+		{
+			switch(impl->getNavState())
+			{
+				case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED:
+				{
+					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back.
+					mediaNavigated(impl, plugin, plugin->getNavigateURI());
+				}
+				break;
+				
+				case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED:
+					// This is the the navigate complete event from a server-directed nav.  Don't broadcast it.
+					llinfos << "	NOT broadcasting navigate (server-directed)" << llendl;
+				break;
+				
+				default:
+					// For all other states, the navigate should have been handled by LOCATION_CHANGED events already.
+				break;
+			}
+		}
+		break;
+		
 		default:
 		break;
 	}
@@ -1781,7 +1941,7 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
 
 void LLVOVolume::sendMediaDataUpdate()
 {
-    sObjectMediaClient->updateMedia(this);
+    sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this));
 }
 
 void LLVOVolume::removeMediaImpl(S32 texture_index)
@@ -1874,6 +2034,22 @@ viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const
 	return NULL;
 }
 
+F64 LLVOVolume::getTotalMediaInterest() const
+{
+	F64 interest = (F64)0.0;
+    int i = 0;
+	const int end = getNumTEs();
+	for ( ; i < end; ++i)
+	{
+		const viewer_media_t &impl = getMediaImpl(i);
+		if (!impl.isNull())
+		{
+			interest += impl->getInterest();
+		}
+	}
+	return interest;
+}
+
 S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id)
 {
 	S32 end = (S32)mMediaImplList.size() ;
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 250c3ed9170a6045a13e8de959e70c2df91db54a..00810b22c4d62655cd28d815f97d7594258af396 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -233,7 +233,23 @@ class LLVOVolume : public LLViewerObject
 	BOOL canBeFlexible() const;
 	BOOL setIsFlexible(BOOL is_flexible);
 
-	void updateObjectMediaData(const LLSD &media_data_duples);
+    // Functions that deal with media, or media navigation
+    
+    // Update this object's media data with the given media data array
+    // (typically this is only called upon a response from a server request)
+	void updateObjectMediaData(const LLSD &media_data_array);
+    
+    // Bounce back media at the given index to its current URL (or home URL, if current URL is empty)
+	void mediaNavigateBounceBack(U8 texture_index);
+    
+    // Returns whether or not this object has permission to navigate or control 
+	// the given media entry
+	enum MediaPermType {
+		MEDIA_PERM_INTERACT, MEDIA_PERM_CONTROL
+	};
+    bool hasMediaPermission(const LLMediaEntry* media_entry, MediaPermType perm_type);
+    
+	void mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location);
 	void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event);
 
 	// Sync the given media data with the impl and the given te
@@ -244,6 +260,7 @@ class LLVOVolume : public LLViewerObject
 
 	viewer_media_t getMediaImpl(U8 face_id) const;
 	S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id);
+	F64 getTotalMediaInterest() const;
    
 	bool hasMedia() const;
 
diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp
index 3bbf4c2c4768eeba781b343b1c2c5321a80fd22f..8f74ea29ac7764a79e861f3f5653bb3db54bfa2f 100644
--- a/indra/newview/llwearable.cpp
+++ b/indra/newview/llwearable.cpp
@@ -35,6 +35,7 @@
 #include "llagent.h"
 #include "llagentwearables.h"
 #include "llfloatercustomize.h"
+#include "lllocaltextureobject.h"
 #include "llviewertexturelist.h"
 #include "llinventorymodel.h"
 #include "llviewerregion.h"
diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..af8cb6b9fb87868e5801d38daff5376bb520e725
--- /dev/null
+++ b/indra/newview/llxmlrpclistener.cpp
@@ -0,0 +1,496 @@
+/**
+ * @file   llxmlrpclistener.cpp
+ * @author Nat Goodspeed
+ * @date   2009-03-18
+ * @brief  Implementation for llxmlrpclistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+
+// Precompiled header
+#include "llviewerprecompiledheaders.h"
+// associated header
+#include "llxmlrpclistener.h"
+// STL headers
+#include <map>
+#include <set>
+// std headers
+// external library headers
+#include <boost/scoped_ptr.hpp>
+#include <boost/range.hpp>          // boost::begin(), boost::end()
+// other Linden headers
+#include "llerror.h"
+#include "stringize.h"
+#include "llxmlrpctransaction.h"
+
+#include <xmlrpc-epi/xmlrpc.h>
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+template <typename STATUS>
+class StatusMapperBase
+{
+    typedef std::map<STATUS, std::string> MapType;
+
+public:
+    StatusMapperBase(const std::string& desc):
+        mDesc(desc)
+    {}
+
+    std::string lookup(STATUS status) const
+    {
+        typename MapType::const_iterator found = mMap.find(status);
+        if (found != mMap.end())
+        {
+            return found->second;
+        }
+        return STRINGIZE("<unknown " << mDesc << " " << status << ">");
+    }
+
+protected:
+    std::string mDesc;
+    MapType mMap;
+};
+
+class StatusMapper: public StatusMapperBase<LLXMLRPCTransaction::EStatus>
+{
+public:
+    StatusMapper(): StatusMapperBase<LLXMLRPCTransaction::EStatus>("Status")
+    {
+		mMap[LLXMLRPCTransaction::StatusNotStarted]  = "NotStarted";
+		mMap[LLXMLRPCTransaction::StatusStarted]     = "Started";
+		mMap[LLXMLRPCTransaction::StatusDownloading] = "Downloading";
+		mMap[LLXMLRPCTransaction::StatusComplete]    = "Complete";
+		mMap[LLXMLRPCTransaction::StatusCURLError]   = "CURLError";
+		mMap[LLXMLRPCTransaction::StatusXMLRPCError] = "XMLRPCError";
+		mMap[LLXMLRPCTransaction::StatusOtherError]  = "OtherError";
+    }
+};
+
+static const StatusMapper sStatusMapper;
+
+class CURLcodeMapper: public StatusMapperBase<CURLcode>
+{
+public:
+    CURLcodeMapper(): StatusMapperBase<CURLcode>("CURLcode")
+    {
+        // from curl.h
+// skip the "CURLE_" prefix for each of these strings
+#define def(sym) (mMap[sym] = #sym + 6)
+        def(CURLE_OK);
+        def(CURLE_UNSUPPORTED_PROTOCOL);    /* 1 */
+        def(CURLE_FAILED_INIT);             /* 2 */
+        def(CURLE_URL_MALFORMAT);           /* 3 */
+        def(CURLE_URL_MALFORMAT_USER);      /* 4 - NOT USED */
+        def(CURLE_COULDNT_RESOLVE_PROXY);   /* 5 */
+        def(CURLE_COULDNT_RESOLVE_HOST);    /* 6 */
+        def(CURLE_COULDNT_CONNECT);         /* 7 */
+        def(CURLE_FTP_WEIRD_SERVER_REPLY);  /* 8 */
+        def(CURLE_FTP_ACCESS_DENIED);       /* 9 a service was denied by the FTP server
+                                          due to lack of access - when login fails
+                                          this is not returned. */
+        def(CURLE_FTP_USER_PASSWORD_INCORRECT); /* 10 - NOT USED */
+        def(CURLE_FTP_WEIRD_PASS_REPLY);    /* 11 */
+        def(CURLE_FTP_WEIRD_USER_REPLY);    /* 12 */
+        def(CURLE_FTP_WEIRD_PASV_REPLY);    /* 13 */
+        def(CURLE_FTP_WEIRD_227_FORMAT);    /* 14 */
+        def(CURLE_FTP_CANT_GET_HOST);       /* 15 */
+        def(CURLE_FTP_CANT_RECONNECT);      /* 16 */
+        def(CURLE_FTP_COULDNT_SET_BINARY);  /* 17 */
+        def(CURLE_PARTIAL_FILE);            /* 18 */
+        def(CURLE_FTP_COULDNT_RETR_FILE);   /* 19 */
+        def(CURLE_FTP_WRITE_ERROR);         /* 20 */
+        def(CURLE_FTP_QUOTE_ERROR);         /* 21 */
+        def(CURLE_HTTP_RETURNED_ERROR);     /* 22 */
+        def(CURLE_WRITE_ERROR);             /* 23 */
+        def(CURLE_MALFORMAT_USER);          /* 24 - NOT USED */
+        def(CURLE_UPLOAD_FAILED);           /* 25 - failed upload "command" */
+        def(CURLE_READ_ERROR);              /* 26 - could open/read from file */
+        def(CURLE_OUT_OF_MEMORY);           /* 27 */
+        /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
+                 instead of a memory allocation error if CURL_DOES_CONVERSIONS
+                 is defined
+        */
+        def(CURLE_OPERATION_TIMEOUTED);     /* 28 - the timeout time was reached */
+        def(CURLE_FTP_COULDNT_SET_ASCII);   /* 29 - TYPE A failed */
+        def(CURLE_FTP_PORT_FAILED);         /* 30 - FTP PORT operation failed */
+        def(CURLE_FTP_COULDNT_USE_REST);    /* 31 - the REST command failed */
+        def(CURLE_FTP_COULDNT_GET_SIZE);    /* 32 - the SIZE command failed */
+        def(CURLE_HTTP_RANGE_ERROR);        /* 33 - RANGE "command" didn't work */
+        def(CURLE_HTTP_POST_ERROR);         /* 34 */
+        def(CURLE_SSL_CONNECT_ERROR);       /* 35 - wrong when connecting with SSL */
+        def(CURLE_BAD_DOWNLOAD_RESUME);     /* 36 - couldn't resume download */
+        def(CURLE_FILE_COULDNT_READ_FILE);  /* 37 */
+        def(CURLE_LDAP_CANNOT_BIND);        /* 38 */
+        def(CURLE_LDAP_SEARCH_FAILED);      /* 39 */
+        def(CURLE_LIBRARY_NOT_FOUND);       /* 40 */
+        def(CURLE_FUNCTION_NOT_FOUND);      /* 41 */
+        def(CURLE_ABORTED_BY_CALLBACK);     /* 42 */
+        def(CURLE_BAD_FUNCTION_ARGUMENT);   /* 43 */
+        def(CURLE_BAD_CALLING_ORDER);       /* 44 - NOT USED */
+        def(CURLE_INTERFACE_FAILED);        /* 45 - CURLOPT_INTERFACE failed */
+        def(CURLE_BAD_PASSWORD_ENTERED);    /* 46 - NOT USED */
+        def(CURLE_TOO_MANY_REDIRECTS );     /* 47 - catch endless re-direct loops */
+        def(CURLE_UNKNOWN_TELNET_OPTION);   /* 48 - User specified an unknown option */
+        def(CURLE_TELNET_OPTION_SYNTAX );   /* 49 - Malformed telnet option */
+        def(CURLE_OBSOLETE);                /* 50 - NOT USED */
+        def(CURLE_SSL_PEER_CERTIFICATE);    /* 51 - peer's certificate wasn't ok */
+        def(CURLE_GOT_NOTHING);             /* 52 - when this is a specific error */
+        def(CURLE_SSL_ENGINE_NOTFOUND);     /* 53 - SSL crypto engine not found */
+        def(CURLE_SSL_ENGINE_SETFAILED);    /* 54 - can not set SSL crypto engine as
+                                          default */
+        def(CURLE_SEND_ERROR);              /* 55 - failed sending network data */
+        def(CURLE_RECV_ERROR);              /* 56 - failure in receiving network data */
+        def(CURLE_SHARE_IN_USE);            /* 57 - share is in use */
+        def(CURLE_SSL_CERTPROBLEM);         /* 58 - problem with the local certificate */
+        def(CURLE_SSL_CIPHER);              /* 59 - couldn't use specified cipher */
+        def(CURLE_SSL_CACERT);              /* 60 - problem with the CA cert (path?) */
+        def(CURLE_BAD_CONTENT_ENCODING);    /* 61 - Unrecognized transfer encoding */
+        def(CURLE_LDAP_INVALID_URL);        /* 62 - Invalid LDAP URL */
+        def(CURLE_FILESIZE_EXCEEDED);       /* 63 - Maximum file size exceeded */
+        def(CURLE_FTP_SSL_FAILED);          /* 64 - Requested FTP SSL level failed */
+        def(CURLE_SEND_FAIL_REWIND);        /* 65 - Sending the data requires a rewind
+                                          that failed */
+        def(CURLE_SSL_ENGINE_INITFAILED);   /* 66 - failed to initialise ENGINE */
+        def(CURLE_LOGIN_DENIED);            /* 67 - user); password or similar was not
+                                          accepted and we failed to login */
+        def(CURLE_TFTP_NOTFOUND);           /* 68 - file not found on server */
+        def(CURLE_TFTP_PERM);               /* 69 - permission problem on server */
+        def(CURLE_TFTP_DISKFULL);           /* 70 - out of disk space on server */
+        def(CURLE_TFTP_ILLEGAL);            /* 71 - Illegal TFTP operation */
+        def(CURLE_TFTP_UNKNOWNID);          /* 72 - Unknown transfer ID */
+        def(CURLE_TFTP_EXISTS);             /* 73 - File already exists */
+        def(CURLE_TFTP_NOSUCHUSER);         /* 74 - No such user */
+        def(CURLE_CONV_FAILED);             /* 75 - conversion failed */
+        def(CURLE_CONV_REQD);               /* 76 - caller must register conversion
+                                          callbacks using curl_easy_setopt options
+                                          CURLOPT_CONV_FROM_NETWORK_FUNCTION);
+                                          CURLOPT_CONV_TO_NETWORK_FUNCTION); and
+                                          CURLOPT_CONV_FROM_UTF8_FUNCTION */
+        def(CURLE_SSL_CACERT_BADFILE);      /* 77 - could not load CACERT file); missing
+                                          or wrong format */
+        def(CURLE_REMOTE_FILE_NOT_FOUND);   /* 78 - remote file not found */
+        def(CURLE_SSH);                     /* 79 - error from the SSH layer); somewhat
+                                          generic so the error message will be of
+                                          interest when this has happened */
+
+        def(CURLE_SSL_SHUTDOWN_FAILED);     /* 80 - Failed to shut down the SSL
+                                          connection */
+#undef  def
+    }
+};
+
+static const CURLcodeMapper sCURLcodeMapper;
+
+LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname):
+    mBoundListener(LLEventPumps::instance().
+                   obtain(pumpname).
+                   listen("LLXMLRPCListener", boost::bind(&LLXMLRPCListener::process, this, _1)))
+{
+}
+
+/**
+ * Capture an outstanding LLXMLRPCTransaction and poll it periodically until
+ * done.
+ *
+ * The sequence is:
+ * # Instantiate Poller, which instantiates, populates and initiates an
+ *   LLXMLRPCTransaction. Poller self-registers on the LLEventPump named
+ *   "mainloop".
+ * # "mainloop" is conventionally pumped once per frame. On each such call,
+ *   Poller checks its LLXMLRPCTransaction for completion.
+ * # When the LLXMLRPCTransaction completes, Poller collects results (if any)
+ *   and sends notification.
+ * # The tricky part: Poller frees itself (and thus its LLXMLRPCTransaction)
+ *   when done. The only external reference to it is the connection to the
+ *   "mainloop" LLEventPump.
+ */
+class Poller
+{
+public:
+    /// Validate the passed request for required fields, then use it to
+    /// populate an XMLRPC_REQUEST and an associated LLXMLRPCTransaction. Send
+    /// the request.
+    Poller(const LLSD& command):
+        mReqID(command),
+        mUri(command["uri"]),
+        mMethod(command["method"]),
+        mReplyPump(command["reply"])
+    {
+        // LL_ERRS if any of these are missing
+        const char* required[] = { "uri", "method", "reply" };
+        // optional: "options" (array of string)
+        // Validate the request
+        std::set<std::string> missing;
+        for (const char** ri = boost::begin(required); ri != boost::end(required); ++ri)
+        {
+            // If the command does not contain this required entry, add it to 'missing'.
+            if (! command.has(*ri))
+            {
+                missing.insert(*ri);
+            }
+        }
+        if (! missing.empty())
+        {
+            LL_ERRS("LLXMLRPCListener") << mMethod << " request missing params: ";
+            const char* separator = "";
+            for (std::set<std::string>::const_iterator mi(missing.begin()), mend(missing.end());
+                 mi != mend; ++mi)
+            {
+                LL_CONT << separator << *mi;
+                separator = ", ";
+            }
+            LL_CONT << LL_ENDL;
+        }
+
+        // Build the XMLRPC request.
+        XMLRPC_REQUEST request = XMLRPC_RequestNew();
+        XMLRPC_RequestSetMethodName(request, mMethod.c_str());
+        XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
+        XMLRPC_VALUE xparams = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
+        LLSD params(command["params"]);
+        if (params.isMap())
+        {
+            for (LLSD::map_const_iterator pi(params.beginMap()), pend(params.endMap());
+                 pi != pend; ++pi)
+            {
+                std::string name(pi->first);
+                LLSD param(pi->second);
+                if (param.isString())
+                {
+                    XMLRPC_VectorAppendString(xparams, name.c_str(), param.asString().c_str(), 0);
+                }
+                else if (param.isInteger() || param.isBoolean())
+                {
+                    XMLRPC_VectorAppendInt(xparams, name.c_str(), param.asInteger());
+                }
+                else if (param.isReal())
+                {
+                    XMLRPC_VectorAppendDouble(xparams, name.c_str(), param.asReal());
+                }
+                else
+                {
+                    LL_ERRS("LLXMLRPCListener") << mMethod << " request param "
+                                                << name << " has unknown type: " << param << LL_ENDL;
+                }
+            }
+        }
+        LLSD options(command["options"]);
+        if (options.isArray())
+        {
+            XMLRPC_VALUE xoptions = XMLRPC_CreateVector("options", xmlrpc_vector_array);
+            for (LLSD::array_const_iterator oi(options.beginArray()), oend(options.endArray());
+                 oi != oend; ++oi)
+            {
+                XMLRPC_VectorAppendString(xoptions, NULL, oi->asString().c_str(), 0);
+            }
+            XMLRPC_AddValueToVector(xparams, xoptions);
+        }
+        XMLRPC_RequestSetData(request, xparams);
+
+        mTransaction.reset(new LLXMLRPCTransaction(mUri, request));
+		mPreviousStatus = mTransaction->status(NULL);
+
+        // Free the XMLRPC_REQUEST object and the attached data values.
+        XMLRPC_RequestFree(request, 1);
+
+        // Now ensure that we get regular callbacks to poll for completion.
+        mBoundListener =
+            LLEventPumps::instance().
+            obtain("mainloop").
+            listen(LLEventPump::inventName(), boost::bind(&Poller::poll, this, _1));
+
+        LL_INFOS("LLXMLRPCListener") << mMethod << " request sent to " << mUri << LL_ENDL;
+    }
+
+    /// called by "mainloop" LLEventPump
+    bool poll(const LLSD&)
+    {
+        bool done = mTransaction->process();
+
+        CURLcode curlcode;
+        LLXMLRPCTransaction::EStatus status;
+        {
+            // LLXMLRPCTransaction::status() is defined to accept int* rather
+            // than CURLcode*. I don't feel the urge to fix the signature, but
+            // we want a CURLcode rather than an int. So fetch it as a local
+            // int, but then assign to a CURLcode for the remainder of this
+            // method.
+            int curlint;
+            status = mTransaction->status(&curlint);
+            curlcode = CURLcode(curlint);
+        }
+
+        LLSD data(mReqID.makeResponse());
+        data["status"] = sStatusMapper.lookup(status);
+        data["errorcode"] = sCURLcodeMapper.lookup(curlcode);
+        data["error"] = "";
+        data["transfer_rate"] = 0.0;
+        LLEventPump& replyPump(LLEventPumps::instance().obtain(mReplyPump));
+		if (! done)
+        {
+            // Not done yet, carry on.
+			if (status == LLXMLRPCTransaction::StatusDownloading
+				&& status != mPreviousStatus)
+			{
+				// If a response has been received, send the 
+				// 'downloading' status if it hasn't been sent.
+				replyPump.post(data);
+			}
+
+			mPreviousStatus = status;
+            return false;
+        }
+
+        // Here the transaction is complete. Check status.
+        data["error"] = mTransaction->statusMessage();
+		data["transfer_rate"] = mTransaction->transferRate();
+        LL_INFOS("LLXMLRPCListener") << mMethod << " result from " << mUri << ": status "
+                                     << data["status"].asString() << ", errorcode "
+                                     << data["errorcode"].asString()
+                                     << " (" << data["error"].asString() << ")"
+                                     << LL_ENDL;
+        // In addition to CURLE_OK, LLUserAuth distinguishes different error
+        // values of 'curlcode':
+        // CURLE_COULDNT_RESOLVE_HOST,
+        // CURLE_SSL_PEER_CERTIFICATE,
+        // CURLE_SSL_CACERT,
+        // CURLE_SSL_CONNECT_ERROR.
+        // Given 'message', need we care?
+        if (status == LLXMLRPCTransaction::StatusComplete)
+        {
+            // Success! Parse data.
+            std::string status_string(data["status"]);
+            data["responses"] = parseResponse(status_string);
+            data["status"] = status_string;
+        }
+
+        // whether successful or not, send reply on requested LLEventPump
+        replyPump.post(data);
+
+        // Because mTransaction is a boost::scoped_ptr, deleting this object
+        // frees our LLXMLRPCTransaction object.
+        // Because mBoundListener is an LLTempBoundListener, deleting this
+        // object disconnects it from "mainloop".
+        // *** MUST BE LAST ***
+        delete this;
+        return false;
+    }
+
+private:
+    /// Derived from LLUserAuth::parseResponse() and parseOptionInto()
+    LLSD parseResponse(std::string& status_string)
+    {
+        // Extract every member into data["responses"] (a map of string
+        // values).
+        XMLRPC_REQUEST response = mTransaction->response();
+        if (! response)
+        {
+            LL_DEBUGS("LLXMLRPCListener") << "No response" << LL_ENDL;
+            return LLSD();
+        }
+
+        XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
+        if (! param)
+        {
+            LL_DEBUGS("LLXMLRPCListener") << "Response contains no data" << LL_ENDL;
+            return LLSD();
+        }
+
+        // Now, parse everything
+        return parseValues(status_string, "", param);
+    }
+
+    /**
+     * Parse key/value pairs from a given XMLRPC_VALUE into an LLSD map.
+     * @param key_pfx Used to describe a given key in log messages. At top
+     * level, pass "". When parsing an options array, pass the top-level key
+     * name of the array plus the index of the array entry; to this we'll
+     * append the subkey of interest.
+     * @param param XMLRPC_VALUE iterator. At top level, pass
+     * XMLRPC_RequestGetData(XMLRPC_REQUEST).
+     */
+    LLSD parseValues(std::string& status_string, const std::string& key_pfx, XMLRPC_VALUE param)
+    {
+        LLSD responses;
+        for (XMLRPC_VALUE current = XMLRPC_VectorRewind(param); current;
+             current = XMLRPC_VectorNext(param))
+        {
+            std::string key(XMLRPC_GetValueID(current));
+            LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL;
+            XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(current);
+            if (xmlrpc_type_string == type)
+            {
+                LLSD::String val(XMLRPC_GetValueString(current));
+                LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL;
+                responses.insert(key, val);
+            }
+            else if (xmlrpc_type_int == type)
+            {
+                LLSD::Integer val(XMLRPC_GetValueInt(current));
+                LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL;
+                responses.insert(key, val);
+            }
+            else if (xmlrpc_type_double == type)
+            {
+                LLSD::Real val(XMLRPC_GetValueDouble(current));
+                LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL;
+                responses.insert(key, val);
+            }
+            else if (xmlrpc_type_array == type)
+            {
+                // We expect this to be an array of submaps. Walk the array,
+                // recursively parsing each submap and collecting them.
+                LLSD array;
+                int i = 0;          // for descriptive purposes
+                for (XMLRPC_VALUE row = XMLRPC_VectorRewind(current); row;
+                     row = XMLRPC_VectorNext(current), ++i)
+                {
+                    // Recursive call. For the lower-level key_pfx, if 'key'
+                    // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the
+                    // nested call, a subkey "bar" will then be logged as
+                    // "foo[0]:bar", and so forth.
+                    // Parse the scalar subkey/value pairs from this array
+                    // entry into a temp submap. Collect such submaps in 'array'.
+                    array.append(parseValues(status_string,
+                                             STRINGIZE(key_pfx << key << '[' << i << "]:"),
+                                             row));
+                }
+                // Having collected an 'array' of 'submap's, insert that whole
+                // 'array' as the value of this 'key'.
+                responses.insert(key, array);
+            }
+            else
+            {
+                // whoops - unrecognized type
+                LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key "
+                                             << key_pfx << key << LL_ENDL;
+                responses.insert(key, STRINGIZE("<bad XMLRPC type " << type << '>'));
+                status_string = "BadType";
+            }
+        }
+        return responses;
+    }
+
+    const LLReqID mReqID;
+    const std::string mUri;
+    const std::string mMethod;
+    const std::string mReplyPump;
+    LLTempBoundListener mBoundListener;
+    boost::scoped_ptr<LLXMLRPCTransaction> mTransaction;
+	LLXMLRPCTransaction::EStatus mPreviousStatus; // To detect state changes.
+};
+
+bool LLXMLRPCListener::process(const LLSD& command)
+{
+    // Allocate a new heap Poller, but do not save a pointer to it. Poller
+    // will check its own status and free itself on completion of the request.
+    (new Poller(command));
+    // conventional event listener return
+    return false;
+}
diff --git a/indra/newview/llxmlrpclistener.h b/indra/newview/llxmlrpclistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..120c2b329be5413c6279fb546e3b16ef819c6844
--- /dev/null
+++ b/indra/newview/llxmlrpclistener.h
@@ -0,0 +1,35 @@
+/**
+ * @file   llxmlrpclistener.h
+ * @author Nat Goodspeed
+ * @date   2009-03-18
+ * @brief  LLEventPump API for LLXMLRPCTransaction. This header doesn't
+ *         actually define the API; the API is defined by the pump name on
+ *         which this class listens, and by the expected content of LLSD it
+ *         receives.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLXMLRPCLISTENER_H)
+#define LL_LLXMLRPCLISTENER_H
+
+#include "llevents.h"
+
+/// Listen on an LLEventPump with specified name for LLXMLRPCTransaction
+/// request events.
+class LLXMLRPCListener
+{
+public:
+    /// Specify the pump name on which to listen
+    LLXMLRPCListener(const std::string& pumpname);
+
+    /// Handle request events on the event pump specified at construction time
+    bool process(const LLSD& command);
+
+private:
+    LLTempBoundListener mBoundListener;
+};
+
+#endif /* ! defined(LL_LLXMLRPCLISTENER_H) */
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 58ff84a8a69a332df0686f7e4ed73ebf90fb3d53..70859e8ea51da3368cee182a4f67cd678fdfad4a 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -33,6 +33,7 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llxmlrpctransaction.h"
+#include "llxmlrpclistener.h"
 
 #include "llcurl.h"
 #include "llviewercontrol.h"
@@ -42,6 +43,13 @@
 
 #include "llappviewer.h"
 
+// Static instance of LLXMLRPCListener declared here so that every time we
+// bring in this code, we instantiate a listener. If we put the static
+// instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would
+// simply omit llxmlrpclistener.o, and shouting on the LLEventPump would do
+// nothing.
+static LLXMLRPCListener listener("LLXMLRPCTransaction");
+
 LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
 {
 	return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id));
@@ -213,6 +221,11 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
 	XMLRPC_RequestSetData(request, params.getValue());
 	
 	init(request, useGzip);
+    // DEV-28398: without this XMLRPC_RequestFree() call, it looks as though
+    // the 'request' object is simply leaked. It's less clear to me whether we
+    // should also ask to free request value data (second param 1), since the
+    // data come from 'params'.
+    XMLRPC_RequestFree(request, 1);
 }
 
 
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index 38570e1a7ed06f8d85044b729b6e299bf859a758..433070ce343994999732af519451ce2f844d5c6a 100644
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -134,8 +134,8 @@ TOOLMEDIAOPEN           CURSOR                  "toolmediaopen.cur"
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,0,0
- PRODUCTVERSION 2,0,0,0
+ FILEVERSION 2,0,0,3256
+ PRODUCTVERSION 2,0,0,3256
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -152,12 +152,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Linden Lab"
             VALUE "FileDescription", "Second Life"
-            VALUE "FileVersion", "2.0.0.0"
+            VALUE "FileVersion", "2.0.0.3256"
             VALUE "InternalName", "Second Life"
             VALUE "LegalCopyright", "Copyright © 2001-2008, Linden Research, Inc."
             VALUE "OriginalFilename", "SecondLife.exe"
             VALUE "ProductName", "Second Life"
-            VALUE "ProductVersion", "2.0.0.0"
+            VALUE "ProductVersion", "2.0.0.3256"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 4d7433233aa92205497ec26b2ed402900a0f6b3c..b194b533aff921e299f8a6cc48e8374b79c07205 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -157,11 +157,13 @@ DBus/dbus-glib Copyright (C) 2002, 2003  CodeFactory AB / Copyright (C) 2003, 20
 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
 FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org).
 GL Copyright (C) 1999-2004 Brian Paul.
+google-perftools Copyright (c) 2005, Google Inc.
 Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
 jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
 jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
 ogg/vorbis Copyright (C) 2001, Xiphophorus
 OpenSSL Copyright (C) 1998-2002 The OpenSSL Project.
+Pth Copyright (C) 1999-2006 Ralf S. Engelschall &lt;rse@gnu.org&gt;
 SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
 SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
diff --git a/indra/newview/skins/default/xui/en/floater_media_settings.xml b/indra/newview/skins/default/xui/en/floater_media_settings.xml
index 6ba26f938d9d501975c5f2c2be65a66e51642c76..b96573b32abd96046c54c6b38b1a61a8fad51470 100644
--- a/indra/newview/skins/default/xui/en/floater_media_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_media_settings.xml
@@ -1,20 +1,74 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater bottom="-666" can_close="true" can_drag_on_left="false" can_minimize="true"
-     can_resize="false" can_tear_off="true" default_tab_group="1" enabled="true"
-      width="365" height="535" left="330" min_height="430" min_width="620"
-     mouse_opaque="true" name="Medis Settings" title="Media Settings">
-	<button bottom="-525" enabled="true" follows="right|bottom" font="SansSerif"
-	     halign="center" height="20" label="OK" label_selected="OK" left="75"
-	     mouse_opaque="true" name="OK" scale_image="true" width="90" />
-	<button bottom_delta="0" enabled="true" follows="right|bottom" font="SansSerif"
-	     halign="center" height="20" label="Cancel" label_selected="Cancel"
-	     left_delta="93" mouse_opaque="true" name="Cancel" scale_image="true"
-	     width="90" />
-	<button bottom_delta="0" enabled="true" follows="right|bottom" font="SansSerif"
-	     halign="center" height="20" label="Apply" label_selected="Apply"
-	     left_delta="93" mouse_opaque="true" name="Apply" scale_image="true"
-	     width="90" />
-	<tab_container bottom="-500" enabled="true" follows="left|top|right|bottom" height="485"
-	     left="0" mouse_opaque="false" name="tab_container" tab_group="1"
-	     tab_position="top" tab_width="80" width="365" />
+<floater 
+ bottom="-666" 
+ can_close="true" 
+ can_drag_on_left="false" 
+ can_minimize="true"
+ can_resize="false" 
+ can_tear_off="true" 
+ default_tab_group="1" 
+ enabled="true"
+ width="365" 
+ height="535" 
+ left="330" 
+ min_height="430" 
+ min_width="620"
+ mouse_opaque="true" 
+ name="Medis Settings" 
+ help_topic = "media_settings"
+ title="Media Settings">
+	<button 
+	 bottom="-525" 
+	 enabled="true" 
+	 follows="right|bottom" 
+	 font="SansSerif"
+	 halign="center" 
+	 height="20" 
+	 label="OK" 
+	 label_selected="OK" 
+	 left="75"
+	 mouse_opaque="true" 
+	 name="OK" 
+	 scale_image="true" 
+	 width="90" />
+	<button 
+	 bottom_delta="0" 
+	 enabled="true" 
+	 follows="right|bottom" 
+	 font="SansSerif"
+	 halign="center" 
+	 height="20" 
+	 label="Cancel" 
+	 label_selected="Cancel"
+	 left_delta="93" 
+	 mouse_opaque="true" 
+	 name="Cancel" 
+	 scale_image="true"
+	 width="90" />
+	<button 
+	 bottom_delta="0" 
+	 enabled="true" 
+	 follows="right|bottom" 
+	 font="SansSerif"
+	 halign="center" 
+	 height="20" 
+	 label="Apply" 
+	 label_selected="Apply"
+	 left_delta="93" 
+	 mouse_opaque="true" 
+	 name="Apply" 
+	 scale_image="true"
+	 width="90" />
+	<tab_container 
+	 bottom="-500" 
+	 enabled="true" 
+	 follows="left|top|right|bottom" 
+	 height="485"
+	 left="0" 
+	 mouse_opaque="false" 
+	 name="tab_container" 
+	 tab_group="1"
+	 tab_position="top" 
+	 tab_width="80" 
+	 width="365" />
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 7829a4fa933b3a49cc704acbc1915c3d12d4e5e6..8cdcee69277fe5e0bf5d1adbb8ee61a9f1e079bb 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -207,71 +207,71 @@
      layout="topleft"
      name="move_radio_group">
         <radio_item
-      top_pad="6"
+         top_pad="6"
          label="Move"
          layout="topleft"
          name="radio move" />
         <radio_item
-      top_pad="6"
+		 top_pad="6"
          label="Lift (Ctrl)"
          layout="topleft"
          name="radio lift" />
         <radio_item
-      top_pad="6"
+         top_pad="6"
          label="Spin (Ctrl+Shift)"
          layout="topleft"
          name="radio spin" />
 		 <radio_group.commit_callback
-	     function="BuildTool.commitRadioMove"/>
-   </radio_group>
-    <radio_group
+			function="BuildTool.commitRadioMove"/>
+	</radio_group>
+	<radio_group
      follows="left|top"
-      left="10"
-      top="54"
-      height="70"
+	 left="10"
+	 top="54"
+	 height="70"
      layout="topleft"
-     name="edit_radio_group">
+	 name="edit_radio_group">
         <radio_item
-         label="Move"
-         layout="topleft"
-         name="radio position" />
+		 label="Move"
+		 layout="topleft"
+		 name="radio position" />
         <radio_item
-      top_pad="6"
+		 top_pad="6"
          label="Rotate (Ctrl)"
          layout="topleft"
          name="radio rotate" />
         <radio_item
-      top_pad="6"
+		 top_pad="6"
          label="Stretch (Ctrl+Shift)"
          layout="topleft"
          name="radio stretch" />
         <radio_item
-      top_pad="6"
-         label="Select Texture"
+		 top_pad="6"
+         label="Select Face"
          layout="topleft"
          name="radio select face" />
-		  <radio_group.commit_callback
-	     function="BuildTool.commitRadioEdit"/>
+			<radio_group.commit_callback
+			function="BuildTool.commitRadioEdit"/>
     </radio_group>
     <check_box
      left="10"
      follows="left|top"
      height="16"
-      control_name="EditLinkedParts"
+	 control_name="EditLinkedParts"
      label="Edit linked"
      layout="topleft"
      name="checkbox edit linked parts" >
 		  <check_box.commit_callback
-	     function="BuildTool.selectComponent"/>
+			function="BuildTool.selectComponent"/>
 	</check_box>
-        <check_box
+	<check_box
      control_name="ScaleUniform"
      height="19"
      label="Stretch Both Sides"
      layout="topleft"
      left="143"
      name="checkbox uniform"
-      top="50"
+	 top="50"
      width="134" />
     <check_box
      control_name="ScaleStretchTextures"
@@ -312,7 +312,7 @@
 		 <combo_box.commit_callback
 	     function="BuildTool.gridMode"/>
     </combo_box>
-   <button
+    <button
      left_pad="0"
      image_disabled="ForwardArrow_Disabled"
      image_selected="ForwardArrow_Press"
@@ -754,24 +754,24 @@
      tab_height="25"
      top="170"
      width="280">
-        <panel
-         border="false"
-         follows="all"
-         label="General"
-         layout="topleft"
-         mouse_opaque="false"
-         help_topic="toolbox_general_tab"
-         name="General"
-         top="16"
-         width="280">
-            <panel.string
-             name="text deed continued">
-                Deed
-            </panel.string>
-            <panel.string
-             name="text deed">
-                Deed
-            </panel.string>
+	<panel
+	 border="false"
+	 follows="all"
+	 label="General"
+	 layout="topleft"
+	 mouse_opaque="false"
+	 help_topic="toolbox_general_tab"
+	 name="General"
+	 top="16"
+	 width="280">
+	 <panel.string
+	  name="text deed continued">
+		Deed
+	 </panel.string>
+	<panel.string
+	 name="text deed">
+		Deed
+	</panel.string>
             <panel.string
              name="text modify info 1">
                 You can modify this object
@@ -912,21 +912,21 @@
              width="75">
                 Group:
             </text>
-           <button
-     follows="top|left"
-     height="10"
-     image_disabled="Activate_Checkmark"
-     image_selected="Activate_Checkmark"
-     image_unselected="Activate_Checkmark"
-     image_color="White_50"
-     layout="topleft"
-     left_pad="0"
-     top_delta="0"
-     name="button set group"
-     picture_style="true"
-     tab_stop="false"
-     tool_tip="Choose a group to share this object's permissions"
-     width="10" />
+            <button
+			 follows="top|left"
+			 height="10"
+			 image_disabled="Activate_Checkmark"
+			 image_selected="Activate_Checkmark"
+			 image_unselected="Activate_Checkmark"
+			 image_color="White_50"
+			 layout="topleft"
+			 left_pad="0"
+			 top_delta="0"
+			 name="button set group"
+			 picture_style="true"
+			 tab_stop="false"
+			 tool_tip="Choose a group to share this object's permissions"
+			 width="10" />
             <name_box
              follows="left|top"
              height="18"
@@ -1046,15 +1046,15 @@
         height="20"
         max_val="999999999" />
       <check_box
-             height="15"
-             width="110"
-             top_pad="3"
-             label="Show in search"
+	   height="15"
+	   width="110"
+	   top_pad="3"
+	   label="Show in search"
        layout="topleft"
-        left="100"
+	   left="100"
        name="search_check"
        tool_tip="Let people see this object in search results" />
-<panel
+		<panel
          border="false"
          follows="left|top"
          layout="topleft"
@@ -2353,7 +2353,7 @@
              left_delta="0"
              name="combobox texgen"
              top_pad="4"
-             width="87">
+             width="60">
                 <combo_box.item
                  label="Default"
                  name="Default"
@@ -2372,7 +2372,7 @@
              name="label shininess"
              left_pad="5"
              top_pad="-36"
-             width="80">
+             width="60">
                 Shininess
             </text>
             <combo_box
@@ -2381,7 +2381,7 @@
              left_delta="0"
              name="combobox shininess"
              top_pad="4"
-             width="80">
+             width="60">
                 <combo_box.item
                  label="None"
                  name="None"
@@ -2584,9 +2584,9 @@
              height="19"
              increment="1"
              initial_value="0"
-	    label="RotationËš"
+			 label="RotationËš"
              layout="topleft"
-	    label_width="100"
+			 label_width="100"
              left="10"
              max_val="9999"
              min_val="-9999"
@@ -2599,9 +2599,9 @@
              follows="left|top"
              height="19"
              initial_value="1"
-	    label="Repeats / Meter"
+			 label="Repeats / Meter"
              layout="topleft"
-	    label_width="100"
+			 label_width="100"
              left="10"
              max_val="10"
              min_val="0.1"
@@ -2654,7 +2654,7 @@
              name="TexOffsetV"
              top_pad="1"
              width="160" />
-      <panel
+        <panel
          border="false"
          follows="left|top"
          layout="topleft"
@@ -2667,88 +2667,88 @@
          height="75"
          width="278">
             <text
-           type="string"
-           length="1"
-           follows="left|top"
-           height="12"
-           layout="topleft"
-           left="10"
-           top_pad="5"
-           name="media_tex"
-           width="260">
-            Media URL
-	    </text>
-	    <line_editor
-             follows="left|top|right"
-             height="18"
-             layout="topleft"
-             left="10"
-	    read_only="true"
-             name="media_info"
-             select_on_focus="true"
-             width="220" />
-            <button
-            follows="top|left"
-            height="18"
-            image_selected="AddItem_Press"
-            image_unselected="AddItem_Off"
-            image_disabled="AddItem_Disabled"
-            layout="topleft"
-            left_pad="0"
-            name="add_media"
-            picture_style="true"
-            tab_stop="false"
-            top_delta="0"
-            tool_tip="Add media"
-            width="18">
-            <button.commit_callback
-		function="BuildTool.AddMedia"/>
-	</button>
-            <button
-                 follows="bottom|left"
-                 height="18"
-                 image_selected="TrashItem_Press"
-                 image_unselected="TrashItem_Off"
-                 layout="topleft"
-                 left_pad="5"
-                 name="delete_media"
-                 picture_style="true"
-                 right="-10"
-                 tool_tip="Delete this media texture"
-                 top_delta="0"
-                 width="18">
-	    <button.commit_callback
-		function="BuildTool.DeleteMedia"/>
-	     </button>
-         <button
+             type="string"
+             length="1"
              follows="left|top"
-             font="SansSerifSmall"
-             height="19"
-             label="Align"
-             label_selected="Align Media"
+             height="12"
              layout="topleft"
              left="10"
-             name="button align"
              top_pad="5"
-             width="100" />
-              <button
-               follows="bottom|left"
-               tool_tip="Change sort and view of recent residents list"
-               height="18"
-               image_disabled="OptionsMenu_Disabled"
-               image_selected="OptionsMenu_Press"
-               image_unselected="OptionsMenu_Off"
-               layout="topleft"
-               left_pad="10"
-               name="edit_media"
-               picture_style="true"
-               top_delta="0"
-               width="18">
-               <button.commit_callback
-		function="BuildTool.EditMedia"/>
-	       </button>
-            </panel>
-        </panel>
+             name="media_tex"
+             width="260">
+              Media URL
+			</text>
+			<line_editor
+			 follows="left|top|right"
+			 height="18"
+			 layout="topleft"
+			 left="10"
+			 read_only="true"
+			 name="media_info"
+			 select_on_focus="true"
+			 width="180" />
+			<button
+			 follows="top|left"
+			 height="18"
+			 image_selected="AddItem_Press"
+			 image_unselected="AddItem_Off"
+			 image_disabled="AddItem_Disabled"
+			 layout="topleft"
+			 left_pad="0"
+			 name="add_media"
+			 picture_style="true"
+			 tab_stop="false"
+			 top_delta="0"
+			 tool_tip="Add Media"
+			 width="18">
+				<button.commit_callback
+				function="BuildTool.AddMedia"/>
+			</button>
+			<button
+			 follows="top|left"
+			 height="18"
+			 image_selected="TrashItem_Press"
+			 image_unselected="TrashItem_Off"
+			 layout="topleft"
+			 left_pad="5"
+			 name="delete_media"
+			 picture_style="true"
+			 tool_tip="Delete this media texture"
+			 top_delta="0"
+			 width="18">
+				<button.commit_callback
+				function="BuildTool.DeleteMedia"/>
+			</button>
+			<button
+			 follows="top|left"
+			 tool_tip="Edit this Media"
+			 height="18"
+			 image_disabled="OptionsMenu_Disabled"
+			 image_selected="OptionsMenu_Press"
+			 image_unselected="OptionsMenu_Off"
+			 layout="topleft"
+			 left_pad="10"
+			 name="edit_media"
+			 picture_style="true"
+			 top_delta="0"
+			 width="18">
+				<button.commit_callback
+				function="BuildTool.EditMedia"/>
+			</button>
+
+			<button
+			 follows="left|top"
+			 font="SansSerifSmall"
+			 height="19"
+			 label="Align"
+			 label_selected="Align Media"
+			 layout="topleft"
+			 left="10"
+			 name="button align"
+			 top_pad="5"
+			 width="100" />
+		</panel>
+	   </panel>
        <panel
          border="false"
          follows="all"
@@ -2786,10 +2786,10 @@
              name="contents_inventory"
              top="50"
              width="260" />
-	 </panel>
+		</panel>
         </tab_container>
-<panel
-      follows="left|top"
+	<panel
+	 follows="left|top"
      height="384"
      layout="topleft"
      left_delta="0"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 284594426c7439b9ac5a18f6e8a5fcc2f1d75430..34d049818056519ec1a68cd838ffc4b827fb34ae 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1091,6 +1091,14 @@
             <menu_item_call.on_click
              function="Advanced.RebakeTextures" />
         </menu_item_call>
+        <menu_item_call
+           label="Set UI Size to Default"
+           layout="topleft"
+           name="Set UI Size to Default">
+          <menu_item_call.on_click
+             function="View.DefaultUISize" />
+        </menu_item_call>
+        <menu_item_separator/>
         <menu_item_check
          label="Limit Select Distance"
          layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d4b6dd04e0625a6e0a187bf63400c33fc22cff73..7c5925550a50d9e6bf8d8c0fabaa0b315b69f73d 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -673,6 +673,19 @@ To place the media on only one face, choose Select Texture and click on the desi
      yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="WhiteListInvalidatesHomeUrl"
+   type="alertmodal">
+Adding this entry to the whitelist will invalidate the home URL you
+specified for this instance of media. You are not allowed to do this
+so the entry cannot be added to the whitelist.
+    <usetemplate
+     name="okbutton"
+     yestext="Ok"/>
+  </notification>
+
+
   <notification
    icon="alertmodal.tga"
    name="MustBeInParcel"
diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_general.xml b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml
index a56f1cf8fee1cf6dc7ff20070c113465fbe50fe6..f9e4b9e7c067186165aa373ede5665a08867619a 100644
--- a/indra/newview/skins/default/xui/en/panel_media_settings_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml
@@ -8,6 +8,7 @@
  left="102" 
  mouse_opaque="true"
  name="Media Settings General" 
+ help_topic = "media_settings_general"
  width="365">
 	
   <text 
@@ -135,7 +136,8 @@
 
   <check_box 
    bottom_delta="-25" 
-   enabled="true" 
+   visible="false" 
+   enabled="false" 
    follows="left|top" 
    font="SansSerifSmall"
    height="16" 
@@ -148,7 +150,7 @@
    width="150" />
 
   <check_box 
-   bottom_delta="-25" 
+   bottom_delta="0" 
    enabled="true" 
    follows="left|top"
    font="SansSerifSmall"
@@ -161,20 +163,6 @@
    radio_style="false" 
    width="150" />
 
-  <check_box 
-   bottom_delta="-25" 
-   enabled="true" 
-   follows="left|top" 
-   font="SansSerifSmall"
-   height="16" 
-   initial_value="false"
-   label="Use Default Alternative Image" 
-   left="10" 
-   mouse_opaque="true"
-   name="alt_image_enable" 
-   radio_style="false" 
-   width="150" />
-
   <check_box 
    bottom_delta="-25" 
    enabled="true" 
@@ -234,7 +222,7 @@
    label="" 
    label_width="0"
    left_delta="40" 
-   max_val="2000" 
+   max_val="2048" 
    min_val="0" 
    mouse_opaque="true"
    name="width_pixels" 
@@ -246,7 +234,7 @@
   <spinner bottom_delta="0"
 	     decimal_digits="0" enabled="true" follows="left|top" height="16"
 	     increment="1" initial_val="256" label="" label_width="0"
-	     left_delta="20" max_val="2000" min_val="0" mouse_opaque="true"
+	     left_delta="20" max_val="2048" min_val="0" mouse_opaque="true"
 	     name="height_pixels" width="50" />
  
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml
index 0cc1406d6277b305bb85cdbe12a0a23c79347be4..85f534c4a3bf4e192ec3366ed4940328634e172d 100644
--- a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml
@@ -8,6 +8,7 @@
  left="102" 
  mouse_opaque="true"
  name="Media settings for controls" 
+ help_topic = "media_settings_controls"
  width="365">
 
   <text 
@@ -15,7 +16,6 @@
    follows="top|left" 
    height="15" 
    left="10" 
-   name="media_perms_label_owner" 
    enabled="false">
     Owner
   </text>
@@ -53,9 +53,8 @@
    follows="top|left" 
    height="15" 
    left="10" 
-   name="media_perms_label_group" 
    enabled="false">
-    Group
+    Group:
   </text>
   
   <name_box 
@@ -101,7 +100,6 @@
    follows="top|left" 
    height="15" 
    left="10" 
-   name="media_perms_label_anyone" 
    enabled="false">
     Anyone
   </text>
diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_security.xml b/indra/newview/skins/default/xui/en/panel_media_settings_security.xml
index 695e956e41b1b363f800a5c3c5dbf3403fd2ebce..a26f74844e6960c636477b528c3b4b3c2fc392cb 100644
--- a/indra/newview/skins/default/xui/en/panel_media_settings_security.xml
+++ b/indra/newview/skins/default/xui/en/panel_media_settings_security.xml
@@ -8,6 +8,7 @@
  left="102" 
  mouse_opaque="true"
  name="Media Settings Security" 
+ help_topic = "media_settings_security"
  width="365">
   <check_box 
    bottom_delta="-40" 
diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml
index 1ea6e1149d2f10e44d1a3e0c61668f78a0b7e57f..50108aa21f433b2fd3418177446d6b5094b5be7d 100644
--- a/indra/newview/skins/default/xui/en/panel_places.xml
+++ b/indra/newview/skins/default/xui/en/panel_places.xml
@@ -1,17 +1,18 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <panel
- background_visible="true"
+background_visible="true"
  follows="all"
- height="400"
+ height="570"
  label="Places"
  layout="topleft"
  min_height="350"
- min_width="240"
  name="places panel"
+ top="0"
+ left="0"
  width="333">
     <string
      name="landmarks_tab_title"
-     value="Landmarks" />
+     value="My Landmarks" />
     <string
      name="teleport_history_tab_title"
      value="Teleport History" />
@@ -19,44 +20,47 @@
      follows="left|top|right"
      font="SansSerif"
      height="23"
-     label="Filter"
      layout="topleft"
      left="15"
+     label="Filter"
+     max_length="300"
      name="Filter"
      top="3"
-     width="300" />
+     width="303" />
     <tab_container
      follows="all"
-     height="326"
+     height="500"
      layout="topleft"
-     left="9"
+     left="10"
      name="Places Tabs"
+     tab_min_width="70"
+     tab_height="30"
      tab_position="top"
-     top="30"
+     top_pad="10"
      width="313" />
     <panel
      class="panel_place_info"
      filename="panel_place_info.xml"
      follows="all"
-     height="326"
+     height="533"
      layout="topleft"
      left="0"
      help_topic="places_info_tab"
      name="panel_place_info"
-     top="30"
-     visible="false" />
+     top="5"
+     visible="false"
+     width="313" />
     <panel
-     height="25"
+     height="19"
      layout="topleft"
      left="0"
      help_topic="places_button_tab"
      name="button_panel"
-     top_pad="10"
      width="313">
         <button
          follows="bottom|left"
-         font="SansSerifSmallBold"
-         height="25"
+         font="SansSerifSmall"
+         height="19"
          label="Teleport"
          layout="topleft"
          left="5"
@@ -65,8 +69,8 @@
          width="77" />
         <button
          follows="bottom|left"
-         font="SansSerifSmallBold"
-         height="25"
+         font="SansSerifSmall"
+         height="19"
          label="Map"
          layout="topleft"
          left_pad="5"
@@ -76,8 +80,8 @@
         <button
          enabled="false"
          follows="bottom|left"
-         font="SansSerifSmallBold"
-         height="25"
+         font="SansSerifSmall"
+         height="19"
          label="Share"
          layout="topleft"
          left_pad="5"
@@ -86,8 +90,8 @@
          width="60" />
         <button
          follows="bottom|left"
-         font="SansSerifSmallBold"
-         height="25"
+         font="SansSerifSmall"
+         height="19"
          label="Edit"
          layout="topleft"
          left_pad="5"
@@ -96,18 +100,21 @@
          width="50" />
         <button
          follows="bottom|right"
-         font="SansSerifSmallBold"
-         height="25"
-         label="â–¼"
+         font="SansSerifSmall"
+         height="19"
+         image_disabled="ForwardArrow_Disabled"
+         image_selected="ForwardArrow_Press"
+         image_unselected="ForwardArrow_Off"
+         picture_style="true"
          layout="topleft"
          name="overflow_btn"
          right="-10"
          top="0"
-         width="30" />
+         width="18" />
         <button
          follows="bottom|right"
-         font="SansSerifSmallBold"
-         height="25"
+         font="SansSerifSmall"
+         height="19"
          label="Close"
          layout="topleft"
          name="close_btn"
@@ -116,8 +123,8 @@
          width="60" />
         <button
          follows="bottom|right"
-         font="SansSerifSmallBold"
-         height="25"
+         font="SansSerifSmall"
+         height="19"
          label="Cancel"
          layout="topleft"
          name="cancel_btn"
@@ -126,8 +133,8 @@
          width="60" />
         <button
          follows="bottom|right"
-         font="SansSerifSmallBold"
-         height="25"
+         font="SansSerifSmall"
+         height="19"
          label="Save"
          layout="topleft"
          name="save_btn"
diff --git a/indra/newview/skins/default/xui/en/panel_side_tray.xml b/indra/newview/skins/default/xui/en/panel_side_tray.xml
index 395b574425fec74cd077ad51c620ba96f7d2931f..6abcbc40d2d3c0376a428af4bb5fb5bfe8d65e4c 100644
--- a/indra/newview/skins/default/xui/en/panel_side_tray.xml
+++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml
@@ -18,6 +18,7 @@
     tab_title="Home"
     description="Home."
     image="TabIcon_Open_Off"
+	image_selected="TabIcon_Close_Off"
     mouse_opaque="false"
     background_visible="true"
   >
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index a57c9cd97f16e5e95a36d78f3382e44fba4eafb6..4c19b22ac596e9ace0b441119d72a5b6ce5126e9 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1819,6 +1819,7 @@ this texture in your inventory
 	<string name="broken_link" value=" (broken_link)" />
 	<string name="LoadingContents">Loading contents...</string>
 	<string name="NoContents">No contents</string>
+	<string name="WornOnAttachmentPoint"> (worn on [ATTACHMENT_POINT])</string>
 
 	<!-- Gestures labels -->
     <!-- use value="" because they have preceding spaces -->
diff --git a/indra/newview/skins/default/xui/en/widgets/accordion_tab.xml b/indra/newview/skins/default/xui/en/widgets/accordion_tab.xml
index 3ff0b3062aaf2ec54f0b040e4de05d8c4d95c10f..dabcb1038bf97b539aa5277fbbde91eb09a2a829 100644
--- a/indra/newview/skins/default/xui/en/widgets/accordion_tab.xml
+++ b/indra/newview/skins/default/xui/en/widgets/accordion_tab.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <accordion_tab
-    header_bg_color="0.68 0.68 0.68 1"
-    header_txt_color="0.68 0.68 0.68 1"
+    header_bg_color="DkGray2"
+    header_txt_color="LtGray"
     header_collapse_img="Accordion_ArrowClosed_Off"
     header_collapse_img_pressed="Accordion_ArrowClosed_Press"
     header_expand_img="Accordion_ArrowOpened_Off"
     header_expand_img_pressed="Accordion_ArrowOpened_Press"
-    header_image="Accordion_Off.png"
+    header_image="Accordion_Off"
     header_image_over="Accordion_Over"
     header_image_pressed="Accordion_Press"
     />
diff --git a/indra/newview/tests/llagentaccess_test.cpp b/indra/newview/tests/llagentaccess_test.cpp
index 42872d85fba7a6d403d54cff380bfc7ba682bb35..e08193f78562e0ffe75d26facee76ccda7acd39b 100644
--- a/indra/newview/tests/llagentaccess_test.cpp
+++ b/indra/newview/tests/llagentaccess_test.cpp
@@ -29,6 +29,8 @@
  * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
+
+#include "linden_common.h"
 #include "../test/lltut.h"
 
 #include "../llagentaccess.h"
diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp
index bd6ae90fabb595f350432b29c097aa01e44e7136..4759c7dc912189b401ebcf9217eb3ce971de2aef 100644
--- a/indra/newview/tests/llcapabilitylistener_test.cpp
+++ b/indra/newview/tests/llcapabilitylistener_test.cpp
@@ -47,9 +47,9 @@
 #include "../test/lltut.h"
 #include "../llcapabilityprovider.h"
 #include "lluuid.h"
-#include "llerrorcontrol.h"
 #include "tests/networkio.h"
 #include "tests/commtest.h"
+#include "tests/wrapllerrs.h"
 #include "stringize.h"
 
 #if defined(LL_WINDOWS)
@@ -127,28 +127,6 @@ namespace tut
     typedef llcapears_group::object llcapears_object;
     llcapears_group llsdmgr("llcapabilitylistener");
 
-    struct CaptureError: public LLError::OverrideFatalFunction
-    {
-        CaptureError():
-            LLError::OverrideFatalFunction(boost::bind(&CaptureError::operator(), this, _1))
-        {
-            LLError::setPrintLocation(false);
-        }
-
-        struct FatalException: public std::runtime_error
-        {
-            FatalException(const std::string& what): std::runtime_error(what) {}
-        };
-
-        void operator()(const std::string& message)
-        {
-            error = message;
-            throw FatalException(message);
-        }
-
-        std::string error;
-    };
-
     template<> template<>
     void llcapears_object::test<1>()
     {
@@ -160,10 +138,10 @@ namespace tut
         std::string threw;
         try
         {
-            CaptureError capture;
+            WrapLL_ERRS capture;
             regionPump.post(request);
         }
-        catch (const CaptureError::FatalException& e)
+        catch (const WrapLL_ERRS::FatalException& e)
         {
             threw = e.what();
         }
@@ -207,10 +185,10 @@ namespace tut
         std::string threw;
         try
         {
-            CaptureError capture;
+            WrapLL_ERRS capture;
             regionPump.post(request);
         }
-        catch (const CaptureError::FatalException& e)
+        catch (const WrapLL_ERRS::FatalException& e)
         {
             threw = e.what();
         }
@@ -269,10 +247,10 @@ namespace tut
         std::string threw;
         try
         {
-            CaptureError capture;
+            WrapLL_ERRS capture;
             regionPump.post(request);
         }
-        catch (const CaptureError::FatalException& e)
+        catch (const WrapLL_ERRS::FatalException& e)
         {
             threw = e.what();
         }
diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp
index 30e39a3bcf4b60ff0d89b01b0d9ae241809c6362..ed753b6ff7a2788f11a4c1f69fef47ac40e57127 100644
--- a/indra/newview/tests/lldateutil_test.cpp
+++ b/indra/newview/tests/lldateutil_test.cpp
@@ -28,6 +28,9 @@
  * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
+
+#include "linden_common.h"
+
 #include "../test/lltut.h"
 
 #include "../lldateutil.h"
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..009be35f641390be0b032aaee9355d0c85694733
--- /dev/null
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -0,0 +1,423 @@
+/**
+ * @file   lllogininstance_test.cpp
+ * @brief  Test for lllogininstance.cpp.
+ * 
+ * $LicenseInfo:firstyear=2008&license=internal$
+ * Copyright (c) 2008, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+// Own header
+#include "../lllogininstance.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "llevents.h"
+
+#if defined(LL_WINDOWS)
+#pragma warning(disable: 4355)      // using 'this' in base-class ctor initializer expr
+#endif
+
+// Constants
+const std::string VIEWERLOGIN_URI("viewerlogin_uri");
+const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid");
+
+const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno");
+
+// Link seams.
+
+//-----------------------------------------------------------------------------
+static LLEventStream gTestPump("test_pump");
+
+#include "lllogin.h"
+static std::string gLoginURI;
+static LLSD gLoginCreds;
+static bool gDisconnectCalled = false;
+class LLLogin::Impl
+{
+};
+LLLogin::LLLogin() {}
+LLLogin::~LLLogin() {}
+LLEventPump& LLLogin::getEventPump() { return gTestPump; }
+void LLLogin::connect(const std::string& uri, const LLSD& credentials) 
+{
+	gLoginURI = uri;
+	gLoginCreds = credentials;
+}
+
+void LLLogin::disconnect() 
+{
+	gDisconnectCalled = true;
+}
+
+//-----------------------------------------------------------------------------
+#include "../llviewernetwork.h"
+unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'};		/* Flawfinder: ignore */
+
+LLViewerLogin::LLViewerLogin() {}
+LLViewerLogin::~LLViewerLogin() {}
+void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const 
+{
+	uris.push_back(VIEWERLOGIN_URI);
+}
+std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; }
+
+//-----------------------------------------------------------------------------
+#include "../llviewercontrol.h"
+LLControlGroup gSavedSettings("Global");
+std::string gCurrentVersion = "invalid_version";
+
+LLControlGroup::LLControlGroup(const std::string& name) :
+	LLInstanceTracker<LLControlGroup, std::string>(name){}
+LLControlGroup::~LLControlGroup() {}
+void LLControlGroup::setBOOL(const std::string& name, BOOL val) {}
+BOOL LLControlGroup::getBOOL(const std::string& name) { return FALSE; }
+U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { return 1; }
+void LLControlGroup::setString(const std::string& name, const std::string& val) {}
+std::string LLControlGroup::getString(const std::string& name) { return "test_string"; }
+BOOL LLControlGroup::declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, BOOL persist) { return TRUE; }
+BOOL LLControlGroup::declareString(const std::string& name, const std::string &initial_val, const std::string& comment, BOOL persist) { return TRUE; }
+
+#include "lluicolortable.h"
+void LLUIColorTable::saveUserSettings(void)const {}
+
+//-----------------------------------------------------------------------------
+#include "../llurlsimstring.h"
+LLURLSimString LLURLSimString::sInstance;
+bool LLURLSimString::parse() { return true; }
+
+//-----------------------------------------------------------------------------
+#include "llnotifications.h"
+#include "llfloaterreg.h"
+static std::string gTOSType;
+static LLEventPump * gTOSReplyPump = NULL;
+
+//static
+LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)
+{
+	gTOSType = name;
+	gTOSReplyPump = &LLEventPumps::instance().obtain(key["reply_pump"]);
+	return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// LLNotifications
+class MockNotifications : public LLNotificationsInterface
+{
+	boost::function<void (const LLSD&, const LLSD&)> mResponder;
+	int mAddedCount;
+
+public: 
+	MockNotifications() :
+		mResponder(0),
+		mAddedCount(0)
+	{
+	}
+
+	virtual ~MockNotifications() {}
+
+	/* virtual */ LLNotificationPtr add(
+					const std::string& name,
+					const LLSD& substitutions,
+					const LLSD& payload, 
+					LLNotificationFunctorRegistry::ResponseFunctor functor)
+	{
+		mResponder = functor;
+		mAddedCount++;
+		return LLNotificationPtr((LLNotification*)NULL);
+	}
+
+	void sendYesResponse()
+	{
+		LLSD notification;
+		LLSD response;
+		response = 1;
+		mResponder(notification, response);
+	}
+
+	void sendNoResponse()
+	{
+		LLSD notification;
+		LLSD response;
+		response = 2;
+		mResponder(notification, response);
+	}
+
+	void sendBogusResponse()
+	{
+		LLSD notification;
+		LLSD response;
+		response = 666;
+		mResponder(notification, response);
+	}
+
+	int addedCount() { return mAddedCount; }
+};
+
+S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response)
+{
+	return response.asInteger();
+}
+
+// misc
+std::string xml_escape_string(const std::string& in)
+{
+	return in;
+}
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct lllogininstance_data
+    {
+		lllogininstance_data() : logininstance(LLLoginInstance::getInstance())
+		{
+			// Global initialization
+			gLoginURI.clear();
+			gLoginCreds.clear();
+			gDisconnectCalled = false;
+
+			gTOSType = ""; // Set to invalid value.
+			gTOSReplyPump = 0; // clear the callback.
+
+
+			gSavedSettings.declareBOOL("NoInventoryLibrary", FALSE, "", FALSE);
+			gSavedSettings.declareBOOL("ConnectAsGod", FALSE, "", FALSE);
+			gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE);
+			gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE);
+			gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE);
+			gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE);
+			gSavedSettings.declareString("NextLoginLocation", "", "", FALSE);
+			gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE);
+
+			credentials["first"] = "testfirst";
+			credentials["last"] = "testlast";
+			credentials["passwd"] = "testpass";
+
+			logininstance->setNotificationsInterface(&notifications);
+		}
+
+		LLLoginInstance* logininstance;
+		LLSD credentials;
+		MockNotifications notifications;
+    };
+
+    typedef test_group<lllogininstance_data> lllogininstance_group;
+    typedef lllogininstance_group::object lllogininstance_object;
+    lllogininstance_group llsdmgr("lllogininstance");
+
+    template<> template<>
+    void lllogininstance_object::test<1>()
+    {
+		set_test_name("Test Simple Success And Disconnect");
+
+		// Test default connect.
+		logininstance->connect(credentials);
+
+		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
+
+		// Dummy success response.
+		LLSD response;
+		response["state"] = "online";
+		response["change"] = "connect";
+		response["progress"] = 1.0;
+		response["transfer_rate"] = 7;
+		response["data"] = "test_data";
+
+		gTestPump.post(response);
+
+		ensure("Success response", logininstance->authSuccess());
+		ensure_equals("Test Response Data", logininstance->getResponse().asString(), "test_data");
+
+		logininstance->disconnect();
+
+		ensure_equals("Called Login Module Disconnect", gDisconnectCalled, true);
+
+		response.clear();
+		response["state"] = "offline";
+		response["change"] = "disconnect";
+		response["progress"] = 0.0;
+		response["transfer_rate"] = 0;
+		response["data"] = "test_data";
+
+		gTestPump.post(response);
+
+		ensure("Disconnected", !(logininstance->authSuccess()));
+    }
+
+    template<> template<>
+    void lllogininstance_object::test<2>()
+    {
+		set_test_name("Test User TOS/Critical message Interaction");
+
+		const std::string test_uri = "testing-uri";
+
+		// Test default connect.
+		logininstance->connect(test_uri, credentials);
+
+		// connect should call LLLogin::connect to init gLoginURI and gLoginCreds.
+		ensure_equals("Default connect uri", gLoginURI, "testing-uri"); 
+		ensure_equals("Default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false);
+		ensure_equals("Default for read critical", gLoginCreds["params"]["read_critical"].asBoolean(), false);
+
+		// TOS failure response.
+		LLSD response;
+		response["state"] = "offline";
+		response["change"] = "fail.login";
+		response["progress"] = 0.0;
+		response["transfer_rate"] = 7;
+		response["data"]["reason"] = "tos";
+		gTestPump.post(response);
+
+		ensure_equals("TOS Dialog type", gTOSType, "message_tos");
+		ensure("TOS callback given", gTOSReplyPump != 0);
+		gTOSReplyPump->post(false); // Call callback denying TOS.
+		ensure("No TOS, failed auth", logininstance->authFailure());
+
+		// Start again.
+		logininstance->connect(test_uri, credentials);
+		gTestPump.post(response); // Fail for tos again.
+		gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos.
+		ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true);
+		ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess());
+	
+		// Fail connection, attempt connect again.
+		// The new request should have reset agree to tos to default.
+		response["data"]["reason"] = "key"; // bad creds.
+		gTestPump.post(response);
+		ensure("TOS auth failure", logininstance->authFailure());
+
+		logininstance->connect(test_uri, credentials);
+		ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false);
+
+		// Critical Message failure response.
+		logininstance->connect(test_uri, credentials);
+		response["data"]["reason"] = "critical"; // Change response to "critical message"
+		gTestPump.post(response);
+
+		ensure_equals("TOS Dialog type", gTOSType, "message_critical");
+		ensure("TOS callback given", gTOSReplyPump != 0);
+		gTOSReplyPump->post(true); 
+		ensure_equals("Accepted read critical message", gLoginCreds["params"]["read_critical"].asBoolean(), true);
+		ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess());
+
+		// Fail then attempt new connection
+		response["data"]["reason"] = "key"; // bad creds.
+		gTestPump.post(response);
+		ensure("TOS auth failure", logininstance->authFailure());
+		logininstance->connect(test_uri, credentials);
+		ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false);
+	}
+
+    template<> template<>
+    void lllogininstance_object::test<3>()
+    {
+		set_test_name("Test Mandatory Update User Accepts");
+
+		// Part 1 - Mandatory Update, with User accepts response.
+		// Test connect with update needed.
+		logininstance->connect(credentials);
+
+		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
+
+		// Update needed failure response.
+		LLSD response;
+		response["state"] = "offline";
+		response["change"] = "fail.login";
+		response["progress"] = 0.0;
+		response["transfer_rate"] = 7;
+		response["data"]["reason"] = "update";
+		gTestPump.post(response);
+
+		ensure_equals("Notification added", notifications.addedCount(), 1);
+
+		notifications.sendYesResponse();
+
+		ensure("Disconnected", !(logininstance->authSuccess()));
+	}
+
+	template<> template<>
+    void lllogininstance_object::test<4>()
+    {
+		set_test_name("Test Mandatory Update User Decline");
+
+		// Test connect with update needed.
+		logininstance->connect(credentials);
+
+		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
+
+		// Update needed failure response.
+		LLSD response;
+		response["state"] = "offline";
+		response["change"] = "fail.login";
+		response["progress"] = 0.0;
+		response["transfer_rate"] = 7;
+		response["data"]["reason"] = "update";
+		gTestPump.post(response);
+
+		ensure_equals("Notification added", notifications.addedCount(), 1);
+		notifications.sendNoResponse();
+
+		ensure("Disconnected", !(logininstance->authSuccess()));
+	}
+
+	template<> template<>
+    void lllogininstance_object::test<6>()
+    {
+		set_test_name("Test Optional Update User Accept");
+
+		// Part 3 - Mandatory Update, with bogus response.
+		// Test connect with update needed.
+		logininstance->connect(credentials);
+
+		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
+
+		// Update needed failure response.
+		LLSD response;
+		response["state"] = "offline";
+		response["change"] = "fail.login";
+		response["progress"] = 0.0;
+		response["transfer_rate"] = 7;
+		response["data"]["reason"] = "optional";
+		gTestPump.post(response);
+
+		ensure_equals("Notification added", notifications.addedCount(), 1);
+		notifications.sendYesResponse();
+
+		ensure("Disconnected", !(logininstance->authSuccess()));
+	}
+
+	template<> template<>
+    void lllogininstance_object::test<7>()
+    {
+		set_test_name("Test Optional Update User Denies");
+
+		// Part 3 - Mandatory Update, with bogus response.
+		// Test connect with update needed.
+		logininstance->connect(credentials);
+
+		ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); 
+
+		// Update needed failure response.
+		LLSD response;
+		response["state"] = "offline";
+		response["change"] = "fail.login";
+		response["progress"] = 0.0;
+		response["transfer_rate"] = 7;
+		response["data"]["reason"] = "optional";
+		gTestPump.post(response);
+
+		ensure_equals("Notification added", notifications.addedCount(), 1);
+		notifications.sendNoResponse();
+
+		// User skips, should be reconnecting.
+		ensure_equals("reconnect uri", gLoginURI, VIEWERLOGIN_URI); 
+		ensure_equals("skipping optional update", gLoginCreds["params"]["skipoptional"].asBoolean(), true); 
+	}
+}
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..445ec7aa344cd13f1f1903a8ed3bf262dea9f969
--- /dev/null
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -0,0 +1,501 @@
+/** 
+ * @file llmediadataclient_test.cpp
+ * @brief LLMediaDatClient tests
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "../llviewerprecompiledheaders.h"
+ 
+#include <iostream>
+#include "../test/lltut.h"
+
+#include "llsdserialize.h"
+#include "llsdutil.h"
+#include "llerrorcontrol.h"
+#include "llhttpstatuscodes.h"
+
+#include "../llmediadataclient.h"
+#include "../llvovolume.h"
+
+#include "../../llprimitive/llmediaentry.cpp"
+#include "../../llprimitive/lltextureentry.cpp"
+#include "../../llmessage/tests/llcurl_stub.cpp"
+
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable : 4702) // boost::lexical_cast generates this warning
+#endif
+#include <boost/lexical_cast.hpp>
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
+
+#define VALID_OBJECT_ID   "3607d5c4-644b-4a8a-871a-8b78471af2a2"
+#define VALID_OBJECT_ID_1 "11111111-1111-1111-1111-111111111111"
+#define VALID_OBJECT_ID_2 "22222222-2222-2222-2222-222222222222"
+#define VALID_OBJECT_ID_3 "33333333-3333-3333-3333-333333333333"
+#define VALID_OBJECT_ID_4 "44444444-4444-4444-4444-444444444444"
+
+#define FAKE_OBJECT_MEDIA_CAP_URL "foo_ObjectMedia"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL "foo_ObjectMediaNavigate"
+#define FAKE_OBJECT_MEDIA_CAP_URL_503 "foo_ObjectMedia_503"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR "foo_ObjectMediaNavigate_ERROR"
+
+#define MEDIA_DATA "\
+<array>														\
+<string>foo</string>										\
+<string>bar</string>										\
+<string>baz</string>										\
+</array>"
+
+#define _DATA_URLS(ID,DIST,INT,URL1,URL2) "					\
+<llsd>											\
+  <map>											\
+    <key>uuid</key>								\
+    <string>" ID "</string>						\
+    <key>distance</key>											\
+    <real>" DIST "</real>										\
+    <key>interest</key>											\
+    <real>" INT "</real>											\
+    <key>cap_urls</key>											\
+    <map>														\
+      <key>ObjectMedia</key>									\
+      <string>" URL1 "</string>			\
+      <key>ObjectMediaNavigate</key>							\
+      <string>" URL2 "</string>	\
+    </map>														\
+    <key>media_data</key>                                       \
+	" MEDIA_DATA "												\
+  </map>														\
+</llsd>"
+
+#define _DATA(ID,DIST,INT) _DATA_URLS(ID,DIST,INT,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)
+
+const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","1.0");
+	
+#define STR(I) boost::lexical_cast<std::string>(I)
+
+#define LOG_TEST(N) LL_DEBUGS("LLMediaDataClient") << "\n" <<			\
+"================================================================================\n" << \
+"===================================== TEST " #N " ===================================\n" << \
+"================================================================================\n" << LL_ENDL;
+
+LLSD *gPostRecords = NULL;
+
+// stubs:
+void LLHTTPClient::post(
+		const std::string& url,
+		const LLSD& body,
+		LLHTTPClient::ResponderPtr responder,
+		const LLSD& headers,
+		const F32 timeout)
+{
+	LLSD record;
+	record["url"] = url;
+	record["body"] = body;
+	record["headers"] = headers;
+	record["timeout"] = timeout;
+	gPostRecords->append(record);
+	
+	// Magic URL that triggers a 503:
+	if ( url == FAKE_OBJECT_MEDIA_CAP_URL_503 )
+	{
+		responder->error(HTTP_SERVICE_UNAVAILABLE, "fake reason");
+	}
+	else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR) 
+	{
+		LLSD result;
+		LLSD error;
+		error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;
+		result["error"] = error;
+		responder->result(result);
+	}
+	else {
+		responder->result(LLSD());
+	}
+}
+
+const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
+
+class LLMediaDataClientObjectTest : public LLMediaDataClientObject
+{
+public:
+	LLMediaDataClientObjectTest(const char *data) 
+		{
+			std::istringstream d(data);
+			LLSDSerialize::fromXML(mRep, d);
+			mNumBounceBacks = 0;
+            
+           // std::cout << ll_pretty_print_sd(mRep) << std::endl;
+           // std::cout << "ID: " << getID() << std::endl;
+		}
+	LLMediaDataClientObjectTest(const LLSD &rep) 
+		: mRep(rep), mNumBounceBacks(0) {}
+	~LLMediaDataClientObjectTest()
+		{ LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClientObjectTest" << LL_ENDL; }
+	
+	virtual U8 getMediaDataCount() const 
+		{ return mRep["media_data"].size(); }
+	virtual LLSD getMediaDataLLSD(U8 index) const
+		{ return mRep["media_data"][(LLSD::Integer)index]; }
+	virtual LLUUID getID() const 
+		{ return mRep["uuid"]; }
+	virtual void mediaNavigateBounceBack(U8 index)
+		{
+			mNumBounceBacks++;
+		}
+	
+	virtual bool hasMedia() const
+		{ return mRep.has("media_data"); }
+	
+	virtual void updateObjectMediaData(LLSD const &media_data_array)
+		{ mRep["media_data"] = media_data_array; }
+	
+	virtual F64 getDistanceFromAvatar() const
+		{ return (LLSD::Real)mRep["distance"]; }
+	
+	virtual F64 getTotalMediaInterest() const
+		{ return (LLSD::Real)mRep["interest"]; }
+
+	virtual std::string getCapabilityUrl(const std::string &name) const 
+		{ return mRep["cap_urls"][name]; }
+
+	int getNumBounceBacks() const
+		{ return mNumBounceBacks; }
+	
+private:
+	LLSD mRep;
+	int mNumBounceBacks;
+};
+
+// This special timer delay should ensure that the timer will fire on the very
+// next pump, no matter what (though this does make an assumption about the
+// implementation of LLEventTimer::updateClass()):
+const F32 NO_PERIOD = -1000.0f;
+
+static void pump_timers()
+{
+	LLEventTimer::updateClass();
+}
+
+namespace tut
+{
+    struct mediadataclient
+    {
+		mediadataclient() {
+			gPostRecords = &mLLSD;
+			
+ 			//LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ 			//LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
+			//LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
+		}
+		LLSD mLLSD;
+    };
+    
+	typedef test_group<mediadataclient> mediadataclient_t;
+	typedef mediadataclient_t::object mediadataclient_object_t;
+	tut::mediadataclient_t tut_mediadataclient("mediadataclient");
+    
+    void ensure(const std::string &msg, int value, int expected)
+    {
+        std::string m = msg;
+        m += " value: " + STR(value);
+        m += ", expected: " + STR(expected);
+        ensure(m, value == expected);
+    }
+    
+    void ensure(const std::string &msg, const std::string & value, const std::string & expected)
+    {
+        std::string m = msg;
+        m += " value: " + value;
+        m += ", expected: " + expected;
+        ensure(m, value == expected);
+    }
+    
+    void ensure(const std::string &msg, const LLUUID & value, const LLUUID & expected)
+    {
+        std::string m = msg;
+        m += " value: " + value.asString();
+        m += ", expected: " + expected.asString();
+        ensure(m, value == expected);
+    }
+    
+    void ensure_llsd(const std::string &msg, const LLSD & value, const char *expected)
+    {
+        LLSD expected_llsd;
+        std::istringstream e(expected);
+        LLSDSerialize::fromXML(expected_llsd, e);
+   
+        std::string value_str = ll_pretty_print_sd(value);
+        std::string expected_str = ll_pretty_print_sd(expected_llsd);
+        std::string m = msg;
+        m += " value: " + value_str;
+        m += ", expected: " + expected_str;
+        ensure(m, value_str == expected_str);
+    }
+
+	//////////////////////////////////////////////////////////////////////////////////////////
+	
+	template<> template<>
+	void mediadataclient_object_t::test<1>()
+	{
+		//
+		// Test fetchMedia()
+		//
+		LOG_TEST(1);
+		
+		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+		int num_refs_start = o->getNumRefs();
+		{
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+			mdc->fetchMedia(o);
+
+			// Make sure no posts happened yet...
+			ensure("post records", gPostRecords->size(), 0);
+
+			::pump_timers();
+		
+			ensure("post records", gPostRecords->size(), 1);
+			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+			ensure("post GET", (*gPostRecords)[0]["body"]["verb"], "GET");
+			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+			ensure("queue empty", mdc->isEmpty());
+		}
+		
+		// Make sure everyone's destroyed properly
+		ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+    }
+
+	//////////////////////////////////////////////////////////////////////////////////////////
+
+	template<> template<>
+	void mediadataclient_object_t::test<2>()
+	{
+		//
+		// Test updateMedia()
+		//
+		LOG_TEST(2);
+
+		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+		{
+			// queue time w/ no delay ensures that ::pump_timers() will hit the tick()
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);  
+			mdc->updateMedia(o);
+			ensure("post records", gPostRecords->size(), 0);
+			::pump_timers();
+		
+			ensure("post records", gPostRecords->size(), 1);
+			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+			ensure("post UPDATE", (*gPostRecords)[0]["body"]["verb"], "UPDATE");
+			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+			ensure_llsd("post data llsd", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_MEDIA_DATA_KEY], 
+						"<llsd>" MEDIA_DATA "</llsd>");
+			ensure("queue empty", mdc->isEmpty());
+		}
+
+		ensure("REF COUNT", o->getNumRefs(), 1);
+	}
+
+	//////////////////////////////////////////////////////////////////////////////////////////
+
+    template<> template<>
+    void mediadataclient_object_t::test<3>()
+    {
+		//
+		// Test navigate()
+		//
+		LOG_TEST(3);
+
+		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+		{		
+			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
+			const char *TEST_URL = "http://example.com";
+			mdc->navigate(o, 0, TEST_URL);
+			ensure("post records", gPostRecords->size(), 0);
+			::pump_timers();
+
+			// ensure no bounce back
+			ensure("bounce back", dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), 0);
+		
+			ensure("post records", gPostRecords->size(), 1);
+			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL);
+			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+			ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+			ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+			ensure("queue empty", mdc->isEmpty());
+		}
+		ensure("REF COUNT", o->getNumRefs(), 1);
+    }
+	
+	//////////////////////////////////////////////////////////////////////////////////////////
+
+    template<> template<>
+    void mediadataclient_object_t::test<4>()
+    {
+		//
+		// Test queue ordering
+		//
+		LOG_TEST(4);
+
+		LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
+			_DATA(VALID_OBJECT_ID_1,"3.0","1.0"));
+		LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
+			_DATA(VALID_OBJECT_ID_2,"1.0","1.0"));
+		LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(
+			_DATA(VALID_OBJECT_ID_3,"2.0","1.0"));
+		{
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);  
+			const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 };
+			mdc->fetchMedia(o1);
+			mdc->fetchMedia(o2);
+			mdc->fetchMedia(o3);
+
+			// Make sure no posts happened yet...
+			ensure("post records", gPostRecords->size(), 0);
+
+			// tick 3 times...
+			::pump_timers();
+			ensure("post records", gPostRecords->size(), 1);
+			::pump_timers();
+			ensure("post records", gPostRecords->size(), 2);
+			::pump_timers();
+			ensure("post records", gPostRecords->size(), 3);
+		
+			for( int i=0; i < 3; i++ )
+			{
+				ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+				ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+				ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), 
+					   LLUUID(ORDERED_OBJECT_IDS[i]));
+			}
+
+			ensure("queue empty", mdc->isEmpty());
+		}
+		ensure("refcount of o1", o1->getNumRefs(), 1);
+		ensure("refcount of o2", o2->getNumRefs(), 1);
+		ensure("refcount of o3", o3->getNumRefs(), 1);
+    }
+
+	//////////////////////////////////////////////////////////////////////////////////////////
+
+	template<> template<>
+	void mediadataclient_object_t::test<5>()
+	{
+		//
+		// Test fetchMedia() getting a 503 error
+		//
+		LOG_TEST(5);
+		
+		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+			_DATA_URLS(VALID_OBJECT_ID,
+					   "1.0",
+					   "1.0",
+					   FAKE_OBJECT_MEDIA_CAP_URL_503,
+					   FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL));
+		int num_refs_start = o->getNumRefs();
+		{
+			const int NUM_RETRIES = 5;
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD,NUM_RETRIES);
+
+			// This should generate a retry
+			mdc->fetchMedia(o);
+
+			// Make sure no posts happened yet...
+			ensure("post records before", gPostRecords->size(), 0);
+
+			// Once, causes retry
+			// Second, fires retry timer
+			// Third, fires queue timer again
+			for (int i=0; i<NUM_RETRIES; ++i)
+			{
+				::pump_timers();  // Should pump (fire) the queue timer, causing a retry timer to be scheduled
+				// XXX This ensure is not guaranteed, because scheduling a timer might actually get it pumped in the same loop
+				//ensure("post records " + STR(i), gPostRecords->size(), i+1);
+				::pump_timers();  // Should pump (fire) the retry timer, scheduling the queue timer
+			}
+
+			// Do some extra pumps to make sure no other timer work occurs.
+			::pump_timers();
+			::pump_timers();
+			::pump_timers();
+			
+			// Make sure there were 2 posts
+			ensure("post records after", gPostRecords->size(), NUM_RETRIES);
+			for (int i=0; i<NUM_RETRIES; ++i)
+			{
+				ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL_503);
+				ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+				ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+			}
+			ensure("queue empty", mdc->isEmpty());
+		}
+		
+		// Make sure everyone's destroyed properly
+		ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+    }
+
+    template<> template<>
+    void mediadataclient_object_t::test<6>()
+    {
+		//
+		// Test navigate() with a bounce back
+		//
+		LOG_TEST(6);
+
+		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+			_DATA_URLS(VALID_OBJECT_ID,
+					   "1.0",
+					   "1.0",
+					   FAKE_OBJECT_MEDIA_CAP_URL,
+					   FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR));
+		{		
+			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
+			const char *TEST_URL = "http://example.com";
+			mdc->navigate(o, 0, TEST_URL);
+			ensure("post records", gPostRecords->size(), 0);
+			::pump_timers();
+
+			// ensure bounce back
+			ensure("bounce back", 
+				   dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(),
+				   1);
+			
+			ensure("post records", gPostRecords->size(), 1);
+			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR);
+			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+			ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+			ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+			ensure("queue empty", mdc->isEmpty());
+		}
+		ensure("REF COUNT", o->getNumRefs(), 1);
+    }
+
+	
+}
diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp
index 40f7d532bc6846280c2e60b501ab69eaa851213c..988d28c3016fe50a5587b1eab84f6f94fb2b3c1e 100644
--- a/indra/newview/tests/llviewerhelputil_test.cpp
+++ b/indra/newview/tests/llviewerhelputil_test.cpp
@@ -30,6 +30,9 @@
  * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+
 #include "../test/lltut.h"
 
 #include "../llviewerhelputil.h"
diff --git a/indra/newview/tests/llxmlrpclistener_test.cpp b/indra/newview/tests/llxmlrpclistener_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c94ba0a3e89032e2d22cb5f1b8839d3449b45957
--- /dev/null
+++ b/indra/newview/tests/llxmlrpclistener_test.cpp
@@ -0,0 +1,230 @@
+/*
+ * @file   llxmlrpclistener_test.cpp
+ * @author Nat Goodspeed
+ * @date   2009-03-20
+ * @brief  Test for llxmlrpclistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=internal$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+// associated header
+#include "../llxmlrpclistener.h"
+// STL headers
+#include <iomanip>
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "../llxmlrpctransaction.h"
+#include "llevents.h"
+#include "lleventfilter.h"
+#include "llsd.h"
+#include "llcontrol.h"
+#include "tests/wrapllerrs.h"
+
+LLControlGroup gSavedSettings("Global");
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct data
+    {
+        data():
+            pumps(LLEventPumps::instance()),
+            uri("http://127.0.0.1:8000")
+        {
+            // These variables are required by machinery used by
+            // LLXMLRPCTransaction. The values reflect reality for this test
+            // executable; hopefully these values are correct.
+            gSavedSettings.declareBOOL("BrowserProxyEnabled", FALSE, "", FALSE); // don't persist
+            gSavedSettings.declareBOOL("NoVerifySSLCert", TRUE, "", FALSE); // don't persist
+        }
+
+        // LLEventPump listener signature
+        bool captureReply(const LLSD& r)
+        {
+            reply = r;
+            return false;
+        }
+
+        LLSD reply;
+        LLEventPumps& pumps;
+        std::string uri;
+    };
+    typedef test_group<data> llxmlrpclistener_group;
+    typedef llxmlrpclistener_group::object object;
+    llxmlrpclistener_group llxmlrpclistenergrp("llxmlrpclistener");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("request validation");
+        WrapLL_ERRS capture;
+        LLSD request;
+        request["uri"] = uri;
+        std::string threw;
+        try
+        {
+            pumps.obtain("LLXMLRPCTransaction").post(request);
+        }
+        catch (const WrapLL_ERRS::FatalException& e)
+        {
+            threw = e.what();
+        }
+        ensure_contains("threw exception", threw, "missing params");
+        ensure_contains("identified missing", threw, "method");
+        ensure_contains("identified missing", threw, "reply");
+    }
+
+    template<> template<>
+    void object::test<2>()
+    {
+        set_test_name("param types validation");
+        WrapLL_ERRS capture;
+        LLSD request;
+        request["uri"] = uri;
+        request["method"] = "hello";
+        request["reply"] = "reply";
+        LLSD& params(request["params"]);
+        params["who"]["specifically"] = "world"; // LLXMLRPCListener only handles scalar params
+        std::string threw;
+        try
+        {
+            pumps.obtain("LLXMLRPCTransaction").post(request);
+        }
+        catch (const WrapLL_ERRS::FatalException& e)
+        {
+            threw = e.what();
+        }
+        ensure_contains("threw exception", threw, "unknown type");
+    }
+
+    template<> template<>
+    void object::test<3>()
+    {
+        set_test_name("success case");
+        LLSD request;
+        request["uri"] = uri;
+        request["method"] = "hello";
+        request["reply"] = "reply";
+        LLSD& params(request["params"]);
+        params["who"] = "world";
+        // Set up a timeout filter so we don't spin forever waiting.
+        LLEventTimeout watchdog;
+        // Connect the timeout filter to the reply pump.
+        LLTempBoundListener temp(
+            pumps.obtain("reply").
+            listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+        // Now connect our target listener to the timeout filter.
+        watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+        // Kick off the request...
+        reply.clear();
+        pumps.obtain("LLXMLRPCTransaction").post(request);
+        // Set the timer
+        F32 timeout(10);
+        watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+        // and pump "mainloop" until we get something, whether from
+        // LLXMLRPCListener or from the watchdog filter.
+        LLTimer timer;
+        F32 start = timer.getElapsedTimeF32();
+        LLEventPump& mainloop(pumps.obtain("mainloop"));
+        while (reply.isUndefined())
+        {
+            mainloop.post(LLSD());
+        }
+        ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+        ensure_equals(reply["responses"]["hi_there"].asString(), "Hello, world!");
+    }
+
+    template<> template<>
+    void object::test<4>()
+    {
+        set_test_name("bogus method");
+        LLSD request;
+        request["uri"] = uri;
+        request["method"] = "goodbye";
+        request["reply"] = "reply";
+        LLSD& params(request["params"]);
+        params["who"] = "world";
+        // Set up a timeout filter so we don't spin forever waiting.
+        LLEventTimeout watchdog;
+        // Connect the timeout filter to the reply pump.
+        LLTempBoundListener temp(
+            pumps.obtain("reply").
+            listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+        // Now connect our target listener to the timeout filter.
+        watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+        // Kick off the request...
+        reply.clear();
+        pumps.obtain("LLXMLRPCTransaction").post(request);
+        // Set the timer
+        F32 timeout(10);
+        watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+        // and pump "mainloop" until we get something, whether from
+        // LLXMLRPCListener or from the watchdog filter.
+        LLTimer timer;
+        F32 start = timer.getElapsedTimeF32();
+        LLEventPump& mainloop(pumps.obtain("mainloop"));
+        while (reply.isUndefined())
+        {
+            mainloop.post(LLSD());
+        }
+        ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+        ensure_equals("XMLRPC error", reply["status"].asString(), "XMLRPCError");
+    }
+
+    template<> template<>
+    void object::test<5>()
+    {
+        set_test_name("bad type");
+        LLSD request;
+        request["uri"] = uri;
+        request["method"] = "getdict";
+        request["reply"] = "reply";
+        (void)request["params"];
+        // Set up a timeout filter so we don't spin forever waiting.
+        LLEventTimeout watchdog;
+        // Connect the timeout filter to the reply pump.
+        LLTempBoundListener temp(
+            pumps.obtain("reply").
+            listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+        // Now connect our target listener to the timeout filter.
+        watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+        // Kick off the request...
+        reply.clear();
+        pumps.obtain("LLXMLRPCTransaction").post(request);
+        // Set the timer
+        F32 timeout(10);
+        watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+        // and pump "mainloop" until we get something, whether from
+        // LLXMLRPCListener or from the watchdog filter.
+        LLTimer timer;
+        F32 start = timer.getElapsedTimeF32();
+        LLEventPump& mainloop(pumps.obtain("mainloop"));
+        while (reply.isUndefined())
+        {
+            mainloop.post(LLSD());
+        }
+        ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+        ensure_equals(reply["status"].asString(), "BadType");
+        ensure_contains("bad type", reply["responses"]["nested_dict"].asString(), "bad XMLRPC type");
+    }
+} // namespace tut
+
+/*****************************************************************************
+*   Resolve link errors: use real machinery here, since we intend to exchange
+*   actual XML with a peer process.
+*****************************************************************************/
+// Including llxmlrpctransaction.cpp drags in the static LLXMLRPCListener
+// instantiated there. That's why it works to post requests to the LLEventPump
+// named "LLXMLRPCTransaction".
+#include "../llxmlrpctransaction.cpp"
+#include "llcontrol.cpp"
+#include "llxmltree.cpp"
+#include "llxmlparser.cpp"
diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb8f7d26c4cb6dab263468bbdd0d551b0356c95c
--- /dev/null
+++ b/indra/newview/tests/test_llxmlrpc_peer.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+"""\
+@file   test_llxmlrpc_peer.py
+@author Nat Goodspeed
+@date   2008-10-09
+@brief  This script asynchronously runs the executable (with args) specified on
+        the command line, returning its result code. While that executable is
+        running, we provide dummy local services for use by C++ tests.
+
+$LicenseInfo:firstyear=2008&license=viewergpl$
+Copyright (c) 2008, Linden Research, Inc.
+$/LicenseInfo$
+"""
+
+import os
+import sys
+from threading import Thread
+from SimpleXMLRPCServer import SimpleXMLRPCServer
+
+mydir = os.path.dirname(__file__)       # expected to be .../indra/newview/tests/
+sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
+sys.path.insert(1, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests"))
+from testrunner import run, debug
+
+class TestServer(SimpleXMLRPCServer):
+    def _dispatch(self, method, params):
+        try:
+            func = getattr(self, method)
+        except AttributeError:
+            raise Exception('method "%s" is not supported' % method)
+        else:
+            # LLXMLRPCListener constructs XMLRPC parameters that arrive as a
+            # 1-tuple containing a dict.
+            return func(**(params[0]))
+
+    def hello(self, who):
+        # LLXMLRPCListener expects a dict return.
+        return {"hi_there": "Hello, %s!" % who}
+
+    def getdict(self):
+        return dict(nested_dict=dict(a=17, b=5))
+
+    def log_request(self, code, size=None):
+        # For present purposes, we don't want the request splattered onto
+        # stderr, as it would upset devs watching the test run
+        pass
+
+    def log_error(self, format, *args):
+        # Suppress error output as well
+        pass
+
+class ServerRunner(Thread):
+    def run(self):
+        server = TestServer(('127.0.0.1', 8000))
+        debug("Starting XMLRPC server...\n")
+        server.serve_forever()
+
+if __name__ == "__main__":
+    sys.exit(run(server=ServerRunner(name="xmlrpc"), *sys.argv[1:]))
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 045990811b4bac5c3460a456b04c01753656447e..b85d31d1ac6563ce26a12340afd982688fea8a39 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -164,28 +164,103 @@ def final_exe(self):
             return ''.join(self.channel().split()) + '.exe'
 
 
+    def test_msvcrt_and_copy_action(self, src, dst):
+        # This is used to test a dll manifest.
+        # It is used as a temporary override during the construct method
+        from test_win32_manifest import test_assembly_binding
+        if src and (os.path.exists(src) or os.path.islink(src)):
+            # ensure that destination path exists
+            self.cmakedirs(os.path.dirname(dst))
+            self.created_paths.append(dst)
+            if not os.path.isdir(src):
+                if(self.args['configuration'].lower() == 'debug'):
+                    test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "8.0.50727.4053")
+                else:
+                    test_assembly_binding(src, "Microsoft.VC80.CRT", "8.0.50727.4053")
+                self.ccopy(src,dst)
+            else:
+                raise Exception("Directories are not supported by test_CRT_and_copy_action()")
+        else:
+            print "Doesn't exist:", src
+
+    def test_for_no_msvcrt_manifest_and_copy_action(self, src, dst):
+        # This is used to test that no manifest for the msvcrt exists.
+        # It is used as a temporary override during the construct method
+        from test_win32_manifest import test_assembly_binding
+        from test_win32_manifest import NoManifestException, NoMatchingAssemblyException
+        if src and (os.path.exists(src) or os.path.islink(src)):
+            # ensure that destination path exists
+            self.cmakedirs(os.path.dirname(dst))
+            self.created_paths.append(dst)
+            if not os.path.isdir(src):
+                try:
+                    if(self.args['configuration'].lower() == 'debug'):
+                        test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "")
+                    else:
+                        test_assembly_binding(src, "Microsoft.VC80.CRT", "")
+                    raise Exception("Unknown condition")
+                except NoManifestException, err:
+                    pass
+                except NoMatchingAssemblyException, err:
+                    pass
+                    
+                self.ccopy(src,dst)
+            else:
+                raise Exception("Directories are not supported by test_CRT_and_copy_action()")
+        else:
+            print "Doesn't exist:", src
+        
+    def enable_crt_manifest_check(self):
+        WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action
+
+    def enable_no_crt_manifest_check(self):
+        WindowsManifest.copy_action = WindowsManifest.test_for_no_msvcrt_manifest_and_copy_action
+
+    def disable_manifest_check(self):
+        del WindowsManifest.copy_action
+
     def construct(self):
         super(WindowsManifest, self).construct()
-        # the final exe is complicated because we're not sure where it's coming from,
-        # nor do we have a fixed name for the executable
-        self.path(self.find_existing_file('debug/secondlife-bin.exe', 'release/secondlife-bin.exe', 'relwithdebinfo/secondlife-bin.exe'), dst=self.final_exe())
+        # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
+        self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
+
+        self.enable_crt_manifest_check()
 
         # Plugin host application
         self.path(os.path.join(os.pardir,
                                'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"),
                   "slplugin.exe")
- 
-        # need to get the kdu dll from any of the build directories as well
+        
+        # need to get the llcommon.dll from the build directory as well
+        if self.prefix(src=self.args['configuration'], dst=""):
+            try:
+                self.path('llcommon.dll')
+                self.path('libapr-1.dll')
+                self.path('libaprutil-1.dll')
+                self.path('libapriconv-1.dll')
+            except RuntimeError, err:
+                print err.message
+                print "Skipping llcommon.dll (assuming llcommon was linked statically)"
+
+            self.end_prefix()
+
+        # need to get the kdu dll from the build directory as well
         try:
-            self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'],
-                '../../libraries/i686-win32/lib/release/llkdu.dll'), 
-                  dst='llkdu.dll')
-            pass
-        except:
+            self.path('%s/llkdu.dll' % self.args['configuration'], dst='llkdu.dll')
+        except RuntimeError:
             print "Skipping llkdu.dll"
-            pass
-        self.path(src="licenses-win32.txt", dst="licenses.txt")
 
+        self.disable_manifest_check()
+
+        # For textures
+        if self.prefix(src=self.args['configuration'], dst=""):
+            if(self.args['configuration'].lower() == 'debug'):
+                self.path("openjpegd.dll")
+            else:
+                self.path("openjpeg.dll")
+            self.end_prefix()
+
+        self.path(src="licenses-win32.txt", dst="licenses.txt")
         self.path("featuretable.txt")
 
         # For use in crash reporting (generates minidumps)
@@ -194,11 +269,7 @@ def construct(self):
         # For using FMOD for sound... DJS
         self.path("fmod.dll")
 
-        # For textures
-        if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
-            self.path("openjpeg.dll")
-            self.end_prefix()
-
+        self.enable_no_crt_manifest_check()
         # Media plugins - QuickTime
         if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
             self.path("media_plugin_quicktime.dll")
@@ -209,7 +280,6 @@ def construct(self):
             self.path("media_plugin_webkit.dll")
             self.end_prefix()
             
-        # For WebKit/Qt plugin runtimes
         if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"):
             self.path("libeay32.dll")
             self.path("qtcore4.dll")
@@ -230,6 +300,8 @@ def construct(self):
             self.path("qtiff4.dll")
             self.end_prefix()
 
+        self.disable_manifest_check()
+
         # These need to be installed as a SxS assembly, currently a 'private' assembly.
         # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
         if self.prefix(src=self.args['configuration'], dst=""):
@@ -243,11 +315,8 @@ def construct(self):
                 self.path("Microsoft.VC80.CRT.manifest")
             self.end_prefix()
 
-        # The config file name needs to match the exe's name.
-        self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config")
-
         # Vivox runtimes
-        if self.prefix(src="vivox-runtime/i686-win32", dst=""):
+        if self.prefix(src=self.args['configuration'], dst=""):
             self.path("SLVoice.exe")
             self.path("alut.dll")
             self.path("vivoxsdk.dll")
@@ -256,22 +325,22 @@ def construct(self):
             self.end_prefix()
 
         # pull in the crash logger and updater from other projects
-        self.path(src=self.find_existing_file( # tag:"crash-logger" here as a cue to the exporter
-                "../win_crash_logger/debug/windows-crash-logger.exe",
-                "../win_crash_logger/release/windows-crash-logger.exe",
-                "../win_crash_logger/relwithdebinfo/windows-crash-logger.exe"),
+        # tag:"crash-logger" here as a cue to the exporter
+        self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
                   dst="win_crash_logger.exe")
-        self.path(src=self.find_existing_file(
-                "../win_updater/debug/windows-updater.exe",
-                "../win_updater/release/windows-updater.exe",
-                "../win_updater/relwithdebinfo/windows-updater.exe"),
+        self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'],
                   dst="updater.exe")
 
         # For google-perftools tcmalloc allocator.
-        if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
-                self.path("libtcmalloc_minimal.dll")
-                self.end_prefix()
-
+        if self.prefix(src=self.args['configuration'], dst=""):
+            try:
+                if self.args['configuration'] == 'Debug':
+                    self.path('libtcmalloc_minimal-debug.dll')
+                else:
+                    self.path('libtcmalloc_minimal.dll')
+            except:
+                print "Skipping libtcmalloc_minimal.dll"
+            self.end_prefix()
 
     def nsi_file_commands(self, install=True):
         def wpath(path):
@@ -392,7 +461,11 @@ def package_finish(self):
 
         # We use the Unicode version of NSIS, available from
         # http://www.scratchpaper.com/
-        NSIS_path = 'C:\\Program Files\\NSIS\\Unicode\\makensis.exe'
+        # Check two paths, one for Program Files, and one for Program Files (x86).
+        # Yay 64bit windows.
+        NSIS_path = os.path.expandvars('${ProgramFiles}\\NSIS\\Unicode\\makensis.exe')
+        if not os.path.exists(NSIS_path):
+            NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe')
         self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
         # self.remove(self.dst_path_of(tempfile))
         # If we're on a build machine, sign the code using our Authenticode certificate. JC
@@ -468,16 +541,31 @@ def construct(self):
                 self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")
                 self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice")
 
+                libdir = "../../libraries/universal-darwin/lib_release"
+                dylibs = {}
+
                 # need to get the kdu dll from any of the build directories as well
-                try:
-                    self.path(self.find_existing_file('../llkdu/%s/libllkdu.dylib' % self.args['configuration'],
-                        "../../libraries/universal-darwin/lib_release/libllkdu.dylib"),
-                        dst='libllkdu.dylib')
-                    pass
-                except:
-                    print "Skipping libllkdu.dylib"
-                    pass
-                
+                for lib in "llkdu", "llcommon":
+                    libfile = "lib%s.dylib" % lib
+                    try:
+                        self.path(self.find_existing_file(os.path.join(os.pardir,
+                                                                       lib,
+                                                                       self.args['configuration'],
+                                                                       libfile),
+                                                          os.path.join(libdir, libfile)),
+                                  dst=libfile)
+                    except RuntimeError:
+                        print "Skipping %s" % libfile
+                        dylibs[lib] = False
+                    else:
+                        dylibs[lib] = True
+
+                if dylibs["llcommon"]:
+                    for libfile in ("libapr-1.0.3.7.dylib",
+                                    "libaprutil-1.0.3.8.dylib",
+                                    "libexpat.0.5.0.dylib"):
+                        self.path(os.path.join(libdir, libfile), libfile)
+
                 #libfmodwrapper.dylib
                 self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib")
                 
@@ -485,6 +573,24 @@ def construct(self):
                 self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
                 self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
 
+                # our apps dependencies on shared libs
+                if dylibs["llcommon"]:
+                    mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
+                    mac_updater_res_path = self.dst_path_of("mac-updater.app/Contents/Resources")
+                    for libfile in ("libllcommon.dylib",
+                                    "libapr-1.0.3.7.dylib",
+                                    "libaprutil-1.0.3.8.dylib",
+                                    "libexpat.0.5.0.dylib"):
+                        target_lib = os.path.join('../../..', libfile)
+                        self.run_command("ln -sf %(target)r %(link)r" % 
+                                         {'target': target_lib,
+                                          'link' : os.path.join(mac_crash_logger_res_path, libfile)}
+                                         )
+                        self.run_command("ln -sf %(target)r %(link)r" % 
+                                         {'target': target_lib,
+                                          'link' : os.path.join(mac_updater_res_path, libfile)}
+                                         )
+
                 # plugin launcher
                 self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin")
 
@@ -509,7 +615,7 @@ def construct(self):
         # This may be desirable for the final release.  Or not.
         if ("package" in self.args['actions'] or 
             "unpacked" in self.args['actions']):
-            self.run_command('strip -S "%(viewer_binary)s"' %
+            self.run_command('strip -S %(viewer_binary)r' %
                              { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
 
 
@@ -538,12 +644,12 @@ def package_finish(self):
         # make sure we don't have stale files laying about
         self.remove(sparsename, finalname)
 
-        self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
+        self.run_command('hdiutil create %(sparse)r -volname %(vol)r -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
                 'sparse':sparsename,
                 'vol':volname})
 
         # mount the image and get the name of the mount point and device node
-        hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"')
+        hdi_output = self.run_command('hdiutil attach -private %r' % sparsename)
         devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
         volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
 
@@ -577,24 +683,25 @@ def package_finish(self):
             self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
 
         # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit)
-        self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"')
-        self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"')
-        self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"')
+        for f in ".VolumeIcon.icns", "background.jpg", ".DS_Store":
+            self.run_command('SetFile -a V %r' % os.path.join(volpath, f))
 
         # Create the alias file (which is a resource file) from the .r
-        self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"')
+        self.run_command('rez %r -o %r' %
+                         (self.src_path_of("installers/darwin/release-dmg/Applications-alias.r"),
+                          os.path.join(volpath, "Applications")))
 
         # Set the alias file's alias and custom icon bits
-        self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"')
+        self.run_command('SetFile -a AC %r' % os.path.join(volpath, "Applications"))
 
         # Set the disk image root's custom icon bit
-        self.run_command('SetFile -a C "' + volpath + '"')
+        self.run_command('SetFile -a C %r' % volpath)
 
         # Unmount the image
-        self.run_command('hdiutil detach -force "' + devfile + '"')
+        self.run_command('hdiutil detach -force %r' % devfile)
 
         print "Converting temp disk image to final disk image"
-        self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname})
+        self.run_command('hdiutil convert %(sparse)r -format UDZO -imagekey zlib-level=9 -o %(final)r' % {'sparse':sparsename, 'final':finalname})
         # get rid of the temp file
         self.package_file = finalname
         self.remove(sparsename)
@@ -667,15 +774,17 @@ def construct(self):
 
         # install either the libllkdu we just built, or a prebuilt one, in
         # decreasing order of preference.  for linux package, this goes to bin/
-        try:
-            self.path(self.find_existing_file('../llkdu/libllkdu.so',
-                '../../libraries/i686-linux/lib_release_client/libllkdu.so'), 
-                  dst='bin/libllkdu.so')
-            # keep this one to preserve syntax, open source mangling removes previous lines
-            pass
-        except:
-            print "Skipping libllkdu.so - not found"
-            pass
+        for lib, destdir in ("llkdu", "bin"), ("llcommon", "lib"):
+            libfile = "lib%s.so" % lib
+            try:
+                self.path(self.find_existing_file(os.path.join(os.pardir, lib, libfile),
+                    '../../libraries/i686-linux/lib_release_client/%s' % libfile), 
+                      dst=os.path.join(destdir, libfile))
+                # keep this one to preserve syntax, open source mangling removes previous lines
+                pass
+            except RuntimeError:
+                print "Skipping %s - not found" % libfile
+                pass
 
         self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin")
         self.path("../linux_crash_logger/linux-crash-logger-stripped","bin/linux-crash-logger.bin")
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 920211ce3961996ca15815dd37131b7cb5161aaf..cc9fa598f25f5a2a0ec3e3d95fbcf305b05e8f21 100644
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -13,7 +13,8 @@ include(LLXML)
 include(LScript)
 include(Linking)
 include(Tut)
-include(Boost)
+
+include(GoogleMock)
 
 include_directories(
     ${LLCOMMON_INCLUDE_DIRS}
@@ -24,6 +25,7 @@ include_directories(
     ${LLVFS_INCLUDE_DIRS}
     ${LLXML_INCLUDE_DIRS}
     ${LSCRIPT_INCLUDE_DIRS}
+    ${GOOGLEMOCK_INCLUDE_DIRS}
     )
 
 set(test_SOURCE_FILES
@@ -60,6 +62,7 @@ set(test_SOURCE_FILES
 set(test_HEADER_FILES
     CMakeLists.txt
 
+    debug.h
     llpipeutil.h
     llsdtraits.h
     lltut.h
@@ -93,6 +96,8 @@ target_link_libraries(test
     ${LLXML_LIBRARIES}
     ${LSCRIPT_LIBRARIES}
     ${LLCOMMON_LIBRARIES}
+    ${EXPAT_LIBRARIES}
+    ${GOOGLEMOCK_LIBRARIES}
     ${APRICONV_LIBRARIES}
     ${PTHREAD_LIBRARY}
     ${WINDOWS_LIBRARIES}
@@ -112,16 +117,21 @@ endif (WINDOWS)
 
 get_target_property(TEST_EXE test LOCATION)
 
-add_custom_command(
+IF(WINDOWS)
+  set(LD_LIBRARY_PATH ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR})
+ELSE(WINDOWS)
+  set(LD_LIBRARY_PATH ${ARCH_PREBUILT_DIRS}:${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}:/usr/lib)
+ENDIF(WINDOWS)
+
+LL_TEST_COMMAND("${LD_LIBRARY_PATH}"
+  "${TEST_EXE}" "--output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt" "--touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt")
+ADD_CUSTOM_COMMAND(
   OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt
-  COMMAND ${TEST_EXE}
-  ARGS
-    --output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt
-    --touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt
+  COMMAND ${LL_TEST_COMMAND_value}
   DEPENDS test
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
   COMMENT "C++ unit tests"
-  )
+ )
 
 set(test_results ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt)
 
diff --git a/indra/test/debug.h b/indra/test/debug.h
new file mode 100644
index 0000000000000000000000000000000000000000..a00659d880d5ac358f846b4eba81b913761a51df
--- /dev/null
+++ b/indra/test/debug.h
@@ -0,0 +1,68 @@
+/**
+ * @file   debug.h
+ * @author Nat Goodspeed
+ * @date   2009-05-28
+ * @brief  Debug output for unit test code
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_DEBUG_H)
+#define LL_DEBUG_H
+
+#include <iostream>
+
+/*****************************************************************************
+*   Debugging stuff
+*****************************************************************************/
+// This class is intended to illuminate entry to a given block, exit from the
+// same block and checkpoints along the way. It also provides a convenient
+// place to turn std::cout output on and off.
+class Debug
+{
+public:
+    Debug(const std::string& block):
+        mBlock(block)
+    {
+        (*this)("entry");
+    }
+
+    ~Debug()
+    {
+        (*this)("exit");
+    }
+
+    void operator()(const std::string& status)
+    {
+#if defined(DEBUG_ON)
+        std::cout << mBlock << ' ' << status << std::endl;
+#endif
+    }
+
+private:
+    const std::string mBlock;
+};
+
+// It's often convenient to use the name of the enclosing function as the name
+// of the Debug block.
+#define DEBUG Debug debug(__FUNCTION__)
+
+// These BEGIN/END macros are specifically for debugging output -- please
+// don't assume you must use such for coroutines in general! They only help to
+// make control flow (as well as exception exits) explicit.
+#define BEGIN                                   \
+{                                               \
+    DEBUG;                                      \
+    try
+
+#define END                                     \
+    catch (...)                                 \
+    {                                           \
+        debug("*** exceptional ");              \
+        throw;                                  \
+    }                                           \
+}
+
+#endif /* ! defined(LL_DEBUG_H) */
diff --git a/indra/test/llevents_tut.cpp b/indra/test/llevents_tut.cpp
index e401f89b22b3e0e56c36d717f678b7117d0dd4be..31130c3c7932eb3ff08d548e3f4da6b9107803c4 100644
--- a/indra/test/llevents_tut.cpp
+++ b/indra/test/llevents_tut.cpp
@@ -32,96 +32,10 @@
 // other Linden headers
 #include "lltut.h"
 #include "stringize.h"
+#include "tests/listener.h"
 
 using boost::assign::list_of;
 
-/*****************************************************************************
-*   test listener class
-*****************************************************************************/
-class Listener;
-std::ostream& operator<<(std::ostream&, const Listener&);
-
-class Listener
-{
-public:
-    Listener(const std::string& name):
-        mName(name)
-    {
-//      std::cout << *this << ": ctor\n";
-    }
-    Listener(const Listener& that):
-        mName(that.mName),
-        mLastEvent(that.mLastEvent)
-    {
-//      std::cout << *this << ": copy\n";
-    }
-    virtual ~Listener()
-    {
-//      std::cout << *this << ": dtor\n";
-    }
-    std::string getName() const { return mName; }
-    bool call(const LLSD& event)
-    {
-//      std::cout << *this << "::call(" << event << ")\n";
-        mLastEvent = event;
-        return false;
-    }
-    bool callstop(const LLSD& event)
-    {
-//      std::cout << *this << "::callstop(" << event << ")\n";
-        mLastEvent = event;
-        return true;
-    }
-    LLSD getLastEvent() const
-    {
-//      std::cout << *this << "::getLastEvent() -> " << mLastEvent << "\n";
-        return mLastEvent;
-    }
-    void reset(const LLSD& to = LLSD())
-    {
-//      std::cout << *this << "::reset(" << to << ")\n";
-        mLastEvent = to;
-    }
-
-private:
-    std::string mName;
-    LLSD mLastEvent;
-};
-
-std::ostream& operator<<(std::ostream& out, const Listener& listener)
-{
-    out << "Listener(" << listener.getName() /* << "@" << &listener */ << ')';
-    return out;
-}
-
-struct Collect
-{
-    bool add(const std::string& bound, const LLSD& event)
-    {
-        result.push_back(bound);
-        return false;
-    }
-    void clear() { result.clear(); }
-    typedef std::vector<std::string> StringList;
-    StringList result;
-};
-
-std::ostream& operator<<(std::ostream& out, const Collect::StringList& strings)
-{
-    out << '(';
-    Collect::StringList::const_iterator begin(strings.begin()), end(strings.end());
-    if (begin != end)
-    {
-        out << '"' << *begin << '"';
-        while (++begin != end)
-        {
-            out << ", \"" << *begin << '"';
-        }
-    }
-    out << ')';
-    return out;
-}
-
 template<typename T>
 T make(const T& value) { return value; }
 
@@ -174,14 +88,7 @@ namespace tut
         // default combiner is defined to return the value returned by the
         // last listener, which is meaningless if there were no listeners.
         per_frame.post(0);
-        // NOTE: boost::bind() saves its arguments by VALUE! If you pass an
-        // object instance rather than a pointer, you'll end up binding to an
-        // internal copy of that instance! Use boost::ref() to capture a
-        // reference instead.
-        LLBoundListener connection = per_frame.listen(listener0.getName(),
-                                                      boost::bind(&Listener::call,
-                                                                  boost::ref(listener0),
-                                                                  _1));
+        LLBoundListener connection = listener0.listenTo(per_frame);
         ensure("connected", connection.connected());
         ensure("not blocked", ! connection.blocked());
         per_frame.post(1);
@@ -207,6 +114,10 @@ namespace tut
         bool threw = false;
         try
         {
+            // NOTE: boost::bind() saves its arguments by VALUE! If you pass
+            // an object instance rather than a pointer, you'll end up binding
+            // to an internal copy of that instance! Use boost::ref() to
+            // capture a reference instead.
             per_frame.listen(listener0.getName(), // note bug, dup name
                              boost::bind(&Listener::call, boost::ref(listener1), _1));
         }
@@ -221,8 +132,7 @@ namespace tut
         }
         ensure("threw DupListenerName", threw);
         // do it right this time
-        per_frame.listen(listener1.getName(),
-                         boost::bind(&Listener::call, boost::ref(listener1), _1));
+        listener1.listenTo(per_frame);
         per_frame.post(5);
         check_listener("got", listener0, 5);
         check_listener("got", listener1, 5);
@@ -252,16 +162,10 @@ namespace tut
         LLEventPump& per_frame(pumps.obtain("per-frame"));
         listener0.reset(0);
         listener1.reset(0);
-        LLBoundListener bound0 = per_frame.listen(listener0.getName(),
-                                                  boost::bind(&Listener::callstop,
-                                                              boost::ref(listener0),
-                                                              _1));
-        LLBoundListener bound1 = per_frame.listen(listener1.getName(),
-                                                  boost::bind(&Listener::call,
-                                                              boost::ref(listener1),
-                                                              _1),
-                                                  // after listener0
-                                                  make<LLEventPump::NameList>(list_of(listener0.getName())));
+        LLBoundListener bound0 = listener0.listenTo(per_frame, &Listener::callstop);
+        LLBoundListener bound1 = listener1.listenTo(per_frame, &Listener::call,
+                                                    // after listener0
+                                                    make<LLEventPump::NameList>(list_of(listener0.getName())));
         ensure("enabled", per_frame.enabled());
         ensure("connected 0", bound0.connected());
         ensure("unblocked 0", ! bound0.blocked());
@@ -301,7 +205,7 @@ namespace tut
         // LLEventQueue.
         LLEventPump& mainloop(pumps.obtain("mainloop"));
         ensure("LLEventQueue leaf class", dynamic_cast<LLEventQueue*>(&login));
-        login.listen(listener0.getName(), boost::bind(&Listener::call, boost::ref(listener0), _1));
+        listener0.listenTo(login);
         listener0.reset(0);
         login.post(1);
         check_listener("waiting for queued event", listener0, 0);
@@ -354,11 +258,10 @@ namespace tut
     {
         set_test_name("stopListening()");
         LLEventPump& login(pumps.obtain("login"));
-        login.listen(listener0.getName(), boost::bind(&Listener::call, boost::ref(listener0), _1));
+        listener0.listenTo(login);
         login.stopListening(listener0.getName());
         // should not throw because stopListening() should have removed name
-        login.listen(listener0.getName(),
-                     boost::bind(&Listener::callstop, boost::ref(listener0), _1));
+        listener0.listenTo(login, &Listener::callstop);
         LLBoundListener wrong = login.getListener("bogus");
         ensure("bogus connection disconnected", ! wrong.connected());
         ensure("bogus connection blocked", wrong.blocked());
@@ -378,10 +281,8 @@ namespace tut
                         boost::bind(&LLEventPump::post, boost::ref(filter0), _1));
         upstream.listen(filter1.getName(),
                         boost::bind(&LLEventPump::post, boost::ref(filter1), _1));
-        filter0.listen(listener0.getName(),
-                       boost::bind(&Listener::call, boost::ref(listener0), _1));
-        filter1.listen(listener1.getName(),
-                       boost::bind(&Listener::call, boost::ref(listener1), _1));
+        listener0.listenTo(filter0);
+        listener1.listenTo(filter1);
         listener0.reset(0);
         listener1.reset(0);
         upstream.post(1);
@@ -536,7 +437,7 @@ namespace tut
         // Passing a string LLEventPump name to LLListenerOrPumpName
         listener0.reset(0);
         LLEventStream random("random");
-        random.listen(listener0.getName(), boost::bind(&Listener::call, boost::ref(listener0), _1));
+        listener0.listenTo(random);
         eventSource("random");
         check_listener("got by pump name", listener0, 17);
         bool threw = false;
diff --git a/indra/test/llsdmessagebuilder_tut.cpp b/indra/test/llsdmessagebuilder_tut.cpp
index 34f3530308113a5078d41340bbbd2d96802fa78e..ca15314e69cc08d82868dcac12e45bd7551e9c47 100755
--- a/indra/test/llsdmessagebuilder_tut.cpp
+++ b/indra/test/llsdmessagebuilder_tut.cpp
@@ -44,6 +44,8 @@
 #include "v3dmath.h"
 #include "v3math.h"
 #include "v4math.h"
+#include "llsdutil.h"
+//#include "llsdutil.cpp"
 #include "llsdutil_math.cpp"
 #include "lltemplatemessagebuilder.h"
 
diff --git a/indra/test/llsdmessagereader_tut.cpp b/indra/test/llsdmessagereader_tut.cpp
index 36cfe5ebfcdd70a843f55cf08ac728a377a2623e..f11e148ccaf816262f922bae0a60546ac2b5a2a2 100755
--- a/indra/test/llsdmessagereader_tut.cpp
+++ b/indra/test/llsdmessagereader_tut.cpp
@@ -42,6 +42,7 @@
 #include "message.h"
 #include "llsdmessagereader.h"
 #include "llsdutil.h"
+#include "llsdutil_math.h"
 
 namespace tut
 {	
diff --git a/indra/test/llsdutil_tut.cpp b/indra/test/llsdutil_tut.cpp
index 0c4bbc2e625ad0ef75648cd234be813d9f309a3b..d125bb00050e5e72effccbd239001215aaf359f4 100644
--- a/indra/test/llsdutil_tut.cpp
+++ b/indra/test/llsdutil_tut.cpp
@@ -44,12 +44,42 @@
 #include "v4math.h"
 #include "llquaternion.h"
 #include "llsdutil.h"
-
+#include "llsdutil_math.h"
+#include "stringize.h"
+#include <set>
+#include <boost/range.hpp>
 
 namespace tut
 {
 	struct llsdutil_data
 	{
+        void test_matches(const std::string& proto_key, const LLSD& possibles,
+                          const char** begin, const char** end)
+        {
+            std::set<std::string> succeed(begin, end);
+            LLSD prototype(possibles[proto_key]);
+            for (LLSD::map_const_iterator pi(possibles.beginMap()), pend(possibles.endMap());
+                 pi != pend; ++pi)
+            {
+                std::string match(llsd_matches(prototype, pi->second));
+                std::set<std::string>::const_iterator found = succeed.find(pi->first);
+                if (found != succeed.end())
+                {
+                    // This test is supposed to succeed. Comparing to the
+                    // empty string ensures that if the test fails, it will
+                    // display the string received so we can tell what failed.
+                    ensure_equals("match", match, "");
+                }
+                else
+                {
+                    // This test is supposed to fail. If we get a false match,
+                    // the string 'match' will be empty, which doesn't tell us
+                    // much about which case went awry. So construct a more
+                    // detailed description string.
+                    ensure(proto_key + " shouldn't match " + pi->first, ! match.empty());
+                }
+            }
+        }
 	};
 	typedef test_group<llsdutil_data> llsdutil_test;;
 	typedef llsdutil_test::object llsdutil_object;
@@ -159,4 +189,207 @@ namespace tut
 		LLSD sd1 = ll_sd_from_color4(c1);
 		ensure_equals("sd -> LLColor4 -> sd", sd, sd1);
 	}
+
+    template<> template<>
+    void llsdutil_object::test<9>()
+    {
+        set_test_name("llsd_matches");
+
+        // for this test, construct a map of all possible LLSD types
+        LLSD map;
+        map.insert("empty",     LLSD());
+        map.insert("Boolean",   LLSD::Boolean());
+        map.insert("Integer",   LLSD::Integer(0));
+        map.insert("Real",      LLSD::Real(0.0));
+        map.insert("String",    LLSD::String("bah"));
+        map.insert("NumString", LLSD::String("1"));
+        map.insert("UUID",      LLSD::UUID());
+        map.insert("Date",      LLSD::Date());
+        map.insert("URI",       LLSD::URI());
+        map.insert("Binary",    LLSD::Binary());
+        map.insert("Map",       LLSD().insert("foo", LLSD()));
+        // Only an empty array can be constructed on the fly
+        LLSD array;
+        array.append(LLSD());
+        map.insert("Array",     array);
+
+        // These iterators are declared outside our various for loops to avoid
+        // fatal MSVC warning: "I used to be broken, but I'm all better now!"
+        LLSD::map_const_iterator mi, mend(map.endMap());
+
+        /*-------------------------- llsd_matches --------------------------*/
+
+        // empty prototype matches anything
+        for (mi = map.beginMap(); mi != mend; ++mi)
+        {
+            ensure_equals(std::string("empty matches ") + mi->first, llsd_matches(LLSD(), mi->second), "");
+        }
+
+        LLSD proto_array, data_array;
+        for (int i = 0; i < 3; ++i)
+        {
+            proto_array.append(LLSD());
+            data_array.append(LLSD());
+        }
+
+        // prototype array matches only array
+        for (mi = map.beginMap(); mi != mend; ++mi)
+        {
+            ensure(std::string("array doesn't match ") + mi->first,
+                   ! llsd_matches(proto_array, mi->second).empty());
+        }
+
+        // data array must be at least as long as prototype array
+        proto_array.append(LLSD());
+        ensure_equals("data array too short", llsd_matches(proto_array, data_array),
+                      "Array size 4 required instead of Array size 3");
+        data_array.append(LLSD());
+        ensure_equals("data array just right", llsd_matches(proto_array, data_array), "");
+        data_array.append(LLSD());
+        ensure_equals("data array longer", llsd_matches(proto_array, data_array), "");
+
+        // array element matching
+        data_array[0] = LLSD::String();
+        ensure_equals("undefined prototype array entry", llsd_matches(proto_array, data_array), "");
+        proto_array[0] = LLSD::Binary();
+        ensure_equals("scalar prototype array entry", llsd_matches(proto_array, data_array),
+                      "[0]: Binary required instead of String");
+        data_array[0] = LLSD::Binary();
+        ensure_equals("matching prototype array entry", llsd_matches(proto_array, data_array), "");
+
+        // build a coupla maps
+        LLSD proto_map, data_map;
+        data_map["got"] = LLSD();
+        data_map["found"] = LLSD();
+        for (LLSD::map_const_iterator dmi(data_map.beginMap()), dmend(data_map.endMap());
+             dmi != dmend; ++dmi)
+        {
+            proto_map[dmi->first] = dmi->second;
+        }
+        proto_map["foo"] = LLSD();
+        proto_map["bar"] = LLSD();
+
+        // prototype map matches only map
+        for (mi = map.beginMap(); mi != mend; ++mi)
+        {
+            ensure(std::string("map doesn't match ") + mi->first,
+                   ! llsd_matches(proto_map, mi->second).empty());
+        }
+
+        // data map must contain all keys in prototype map
+        std::string error(llsd_matches(proto_map, data_map));
+        ensure_contains("missing keys", error, "missing keys");
+        ensure_contains("missing foo", error, "foo");
+        ensure_contains("missing bar", error, "bar");
+        ensure_does_not_contain("found found", error, "found");
+        ensure_does_not_contain("got got", error, "got");
+        data_map["bar"] = LLSD();
+        error = llsd_matches(proto_map, data_map);
+        ensure_contains("missing foo", error, "foo");
+        ensure_does_not_contain("got bar", error, "bar");
+        data_map["foo"] = LLSD();
+        ensure_equals("data map just right", llsd_matches(proto_map, data_map), "");
+        data_map["extra"] = LLSD();
+        ensure_equals("data map with extra", llsd_matches(proto_map, data_map), "");
+
+        // map element matching
+        data_map["foo"] = LLSD::String();
+        ensure_equals("undefined prototype map entry", llsd_matches(proto_map, data_map), "");
+        proto_map["foo"] = LLSD::Binary();
+        ensure_equals("scalar prototype map entry", llsd_matches(proto_map, data_map),
+                      "['foo']: Binary required instead of String");
+        data_map["foo"] = LLSD::Binary();
+        ensure_equals("matching prototype map entry", llsd_matches(proto_map, data_map), "");
+
+        // String
+        {
+            static const char* matches[] = { "String", "NumString", "Boolean", "Integer",
+                                             "Real", "UUID", "Date", "URI" };
+            test_matches("String", map, boost::begin(matches), boost::end(matches));
+        }
+
+        // Boolean, Integer, Real
+        static const char* numerics[] = { "Boolean", "Integer", "Real" };
+        for (const char **ni = boost::begin(numerics), **nend = boost::end(numerics);
+             ni != nend; ++ni)
+        {
+            static const char* matches[] = { "Boolean", "Integer", "Real", "String", "NumString" };
+            test_matches(*ni, map, boost::begin(matches), boost::end(matches));
+        }
+
+        // UUID
+        {
+            static const char* matches[] = { "UUID", "String", "NumString" };
+            test_matches("UUID", map, boost::begin(matches), boost::end(matches));
+        }
+
+        // Date
+        {
+            static const char* matches[] = { "Date", "String", "NumString" };
+            test_matches("Date", map, boost::begin(matches), boost::end(matches));
+        }
+
+        // URI
+        {
+            static const char* matches[] = { "URI", "String", "NumString" };
+            test_matches("URI", map, boost::begin(matches), boost::end(matches));
+        }
+
+        // Binary
+        {
+            static const char* matches[] = { "Binary" };
+            test_matches("Binary", map, boost::begin(matches), boost::end(matches));
+        }
+
+        /*-------------------------- llsd_equals ---------------------------*/
+
+        // Cross-product of each LLSD type with every other
+        for (LLSD::map_const_iterator lmi(map.beginMap()), lmend(map.endMap());
+             lmi != lmend; ++lmi)
+        {
+            for (LLSD::map_const_iterator rmi(map.beginMap()), rmend(map.endMap());
+                 rmi != rmend; ++rmi)
+            {
+                // Name this test based on the map keys naming the types of
+                // interest, e.g "String::Integer".
+                // We expect the values (xmi->second) to be equal if and only
+                // if the type names (xmi->first) are equal.
+                ensure(STRINGIZE(lmi->first << "::" << rmi->first),
+                       bool(lmi->first == rmi->first) ==
+                       bool(llsd_equals(lmi->second, rmi->second)));
+            }
+        }
+
+        // Array cases
+        LLSD rarray;
+        rarray.append(1.0);
+        rarray.append(2);
+        rarray.append("3");
+        LLSD larray(rarray);
+        ensure("llsd_equals(equal arrays)", llsd_equals(larray, rarray));
+        rarray[2] = "4";
+        ensure("llsd_equals(different [2])", ! llsd_equals(larray, rarray));
+        rarray = larray;
+        rarray.append(LLSD::Date());
+        ensure("llsd_equals(longer right array)", ! llsd_equals(larray, rarray));
+        rarray = larray;
+        rarray.erase(2);
+        ensure("llsd_equals(shorter right array)", ! llsd_equals(larray, rarray));
+
+        // Map cases
+        LLSD rmap;
+        rmap["San Francisco"] = 65;
+        rmap["Phoenix"] = 92;
+        rmap["Boston"] = 77;
+        LLSD lmap(rmap);
+        ensure("llsd_equals(equal maps)", llsd_equals(lmap, rmap));
+        rmap["Boston"] = 80;
+        ensure("llsd_equals(different [\"Boston\"])", ! llsd_equals(lmap, rmap));
+        rmap = lmap;
+        rmap["Atlanta"] = 95;
+        ensure("llsd_equals(superset right map)", ! llsd_equals(lmap, rmap));
+        rmap = lmap;
+        lmap["Seattle"] = 72;
+        ensure("llsd_equals(superset left map)", ! llsd_equals(lmap, rmap));
+    }
 }
diff --git a/indra/test/lltut.cpp b/indra/test/lltut.cpp
index 201e174f9cf608289e75ee9c286a5adb1b8eb988..e4e0de1ff1d7696f13a46bf63535edc3114a0da3 100644
--- a/indra/test/lltut.cpp
+++ b/indra/test/lltut.cpp
@@ -76,9 +76,13 @@ namespace tut
 
 	void ensure_equals(const char* m, const LLSD& actual,
 		const LLSD& expected)
+    {
+        ensure_equals(std::string(m), actual, expected);
+    }
+
+	void ensure_equals(const std::string& msg, const LLSD& actual,
+		const LLSD& expected)
 	{
-		const std::string& msg = m ? m : "";
-		
 		ensure_equals(msg + " type", actual.type(), expected.type());
 		switch (actual.type())
 		{
@@ -128,7 +132,7 @@ namespace tut
 				{
 					ensure_equals(msg + " map keys", 
 						actual_iter->first, expected_iter->first);
-					ensure_equals((msg + "[" + actual_iter->first + "]").c_str(),
+					ensure_equals(msg + "[" + actual_iter->first + "]",
 						actual_iter->second, expected_iter->second);
 					++actual_iter;
 					++expected_iter;
@@ -141,7 +145,7 @@ namespace tut
 				
 				for(int i = 0; i < actual.size(); ++i)
 				{
-					ensure_equals((msg + llformat("[%d]", i)).c_str(),
+					ensure_equals(msg + llformat("[%d]", i),
 						actual[i], expected[i]);
 				}
 				return;
diff --git a/indra/test/lltut.h b/indra/test/lltut.h
index bbb437c3f9c638288767f94809c6a6a35b8e3c5c..6322753253fb7621fe6213529c02ec337d3d19ac 100644
--- a/indra/test/lltut.h
+++ b/indra/test/lltut.h
@@ -121,6 +121,9 @@ namespace tut
 
 	void ensure_equals(const char* msg,
 		const LLSD& actual, const LLSD& expected);
+
+	void ensure_equals(const std::string& msg,
+		const LLSD& actual, const LLSD& expected);
 	
 	void ensure_starts_with(const std::string& msg,
 		const std::string& actual, const std::string& expectedStart);
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index c2e0a11156efcaf97c272dad683e8b765caf1963..7dfe8f40b785ab0e48d10533a7cb24517b92de95 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -54,6 +54,11 @@
 #	include "ctype_workaround.h"
 #endif
 
+#ifndef LL_WINDOWS
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#endif
+
 namespace tut
 {
 	std::string sSourceDir;
@@ -235,6 +240,11 @@ void wouldHaveCrashed(const std::string& message)
 
 int main(int argc, char **argv)
 {
+	// The following line must be executed to initialize Google Mock
+	// (and Google Test) before running the tests.
+#ifndef LL_WINDOWS
+	::testing::InitGoogleMock(&argc, argv);
+#endif
 	LLError::initForApplication(".");
 	LLError::setFatalFunction(wouldHaveCrashed);
 	LLError::setDefaultLevel(LLError::LEVEL_ERROR);
diff --git a/indra/test_apps/llplugintest/CMakeLists.txt b/indra/test_apps/llplugintest/CMakeLists.txt
index 789ead04fe9c531fc2ef0cd34b1e36c6d654bba7..88c4ba8ad9a739959f6940c49bde2da5f93c2dce 100644
--- a/indra/test_apps/llplugintest/CMakeLists.txt
+++ b/indra/test_apps/llplugintest/CMakeLists.txt
@@ -28,7 +28,7 @@ include_directories(
 
 if (DARWIN)
     include(CMakeFindFrameworks)
-    find_library(CARBON_LIBRARY Carbon)
+    find_library(COREFOUNDATION_LIBRARY CoreFoundation)
 endif (DARWIN)
 
 ### demo_plugin
@@ -136,7 +136,7 @@ endif (DARWIN)
 #    ${media_simple_test_SOURCE_FILES}
 #)
 #
-#add_dependencies(media_simple_test copy_win_libs)
+#add_dependencies(media_simple_test stage_third_party_libs)
 #
 #set_target_properties(media_simple_test
 #    PROPERTIES
@@ -177,7 +177,7 @@ endif (DARWIN)
 #)
 #
 #add_dependencies(media_plugin_test
-#  copy_win_libs
+#  stage_third_party_libs
 #  SLPlugin
 #  demo_media_plugin
 #  ${LLPLUGIN_LIBRARIES}
@@ -261,6 +261,7 @@ set(llmediaplugintest_SOURCE_FILES
 
 add_executable(llmediaplugintest
     WIN32
+    MACOSX_BUNDLE
     ${llmediaplugintest_SOURCE_FILES}
 )
 
@@ -280,8 +281,15 @@ target_link_libraries(llmediaplugintest
   ${PLUGIN_API_WINDOWS_LIBRARIES}
 )
 
+if (DARWIN)
+  # The testbed needs to use a couple of CoreFoundation calls now, to deal with being a bundled app.
+  target_link_libraries(llmediaplugintest
+    ${COREFOUNDATION_LIBRARY}
+  )
+endif (DARWIN)
+
 add_dependencies(llmediaplugintest
-  copy_win_libs
+  stage_third_party_libs
   SLPlugin
   media_plugin_quicktime
   media_plugin_webkit
@@ -300,22 +308,64 @@ endif (DARWIN OR LINUX)
 
 # Gather build products of the various dependencies into the build directory for the testbed.
 
+if (DARWIN)
+  # path inside the app bundle where we'll need to copy plugins and other related files
+  set(PLUGINS_DESTINATION_DIR
+    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llmediaplugintest.app/Contents/Resources
+  )
+  
+  # create the Contents/Resources directory
+  add_custom_command(
+    TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    ARGS
+      -E
+      make_directory
+      ${PLUGINS_DESTINATION_DIR}
+    COMMENT "Creating Resources directory in app bundle."
+  )
+
+  # copy the llcommon dylib and its dependencies to Contents/Resources.
+  get_target_property(BUILT_LLCOMMON llcommon LOCATION)
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON}  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${BUILT_LLCOMMON}
+  )
+  # FIXME: these paths should come from somewhere reliable.  The canonical list seems to be in indra/newview/viewer_manifest.py
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib
+  )
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib
+  )
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libexpat.0.5.0.dylib  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libexpat.0.5.0.dylib
+  )
+else (DARWIN)
+  set(PLUGINS_DESTINATION_DIR
+    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+  )
+endif (DARWIN)
+
 get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION)
 add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN}  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN}  ${PLUGINS_DESTINATION_DIR}
   DEPENDS ${BUILT_SLPLUGIN}
 )
 
 if (DARWIN OR WINDOWS)
   get_target_property(BUILT_WEBKIT_PLUGIN media_plugin_webkit LOCATION)
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN}  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${BUILT_WEBKIT_PLUGIN}
   )
 
   get_target_property(BUILT_QUICKTIME_PLUGIN media_plugin_quicktime LOCATION)
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_QUICKTIME_PLUGIN}  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_QUICKTIME_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${BUILT_QUICKTIME_PLUGIN}
   )
   
@@ -325,18 +375,137 @@ if (DARWIN OR WINDOWS)
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/
     DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
   )
-  # also copy it to the build configuration directory, which is what the mac wants...
+  # also copy it to the same place as SLPlugin, which is what the mac wants...
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
   )
 endif (DARWIN OR WINDOWS)
 
 if (DARWIN)
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib
   )
 endif (DARWIN)
 
+if(WINDOWS)
+  #********************
+  # Plugin test library deploy
+  #
+  # Debug config runtime files required for the plugin test mule
+  set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
+  set(plugintest_debug_files
+    libeay32.dll
+    libglib-2.0-0.dll
+    libgmodule-2.0-0.dll
+    libgobject-2.0-0.dll
+    libgthread-2.0-0.dll
+    qtcored4.dll
+    qtguid4.dll
+    qtnetworkd4.dll
+    qtopengld4.dll
+    qtwebkitd4.dll
+    ssleay32.dll
+    )
+  copy_if_different(
+    ${plugintest_debug_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/Debug"
+    out_targets
+    ${plugintest_debug_files}
+    )
+  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
+  
+  # Debug config runtime files required for the plugin test mule (Qt image format plugins)
+  set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/imageformats")
+  set(plugintest_debug_files
+    qgifd4.dll
+    qicod4.dll
+    qjpegd4.dll
+    qmngd4.dll
+    qsvgd4.dll
+    qtiffd4.dll
+    )
+  copy_if_different(
+    ${plugintest_debug_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/Debug/imageformats"
+    out_targets
+    ${plugintest_debug_files}
+    )
+  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
+  
+  # Release & ReleaseDebInfo config runtime files required for the plugin test mule
+  set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
+  set(plugintest_release_files
+    libeay32.dll
+    libglib-2.0-0.dll
+    libgmodule-2.0-0.dll
+    libgobject-2.0-0.dll
+    libgthread-2.0-0.dll
+    qtcore4.dll
+    qtgui4.dll
+    qtnetwork4.dll
+    qtopengl4.dll
+    qtwebkit4.dll
+    ssleay32.dll
+    )
+  copy_if_different(
+    ${plugintest_release_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/Release"
+    out_targets
+    ${plugintest_release_files}
+    )
+  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
+
+  copy_if_different(
+    ${plugintest_release_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo"
+    out_targets
+    ${plugintest_release_files}
+    )
+  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
+
+  # Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt image format plugins)
+  set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/imageformats")
+  set(plugintest_release_files
+    qgif4.dll
+    qico4.dll
+    qjpeg4.dll
+    qmng4.dll
+    qsvg4.dll
+    qtiff4.dll
+    )
+  copy_if_different(
+    ${plugintest_release_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/Release/imageformats"
+    out_targets
+    ${plugintest_release_files}
+    )
+  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
+
+  copy_if_different(
+    ${plugintest_release_src_dir}
+    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/imageformats"
+    out_targets
+    ${plugintest_release_files}
+    )
+  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
+
+  copy_if_different(
+    "${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}"
+    "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
+    out_targets
+    llcommon.dll libapr-1.dll libaprutil-1.dll libapriconv-1.dll
+    )
+  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
+
+  add_custom_target(copy_plugintest_libs ALL
+    DEPENDS 
+      ${plugin_test_targets}
+      llcommon
+    )
+
+  add_dependencies(llmediaplugintest copy_plugintest_libs)
+
+endif(WINDOWS)
 
diff --git a/indra/test_apps/llplugintest/bookmarks.txt b/indra/test_apps/llplugintest/bookmarks.txt
index 796cc5d1b28feaadda6a154db144f719df7ca461..e5268fcac90df64d5ac5209e248123dc978a42b9 100644
--- a/indra/test_apps/llplugintest/bookmarks.txt
+++ b/indra/test_apps/llplugintest/bookmarks.txt
@@ -8,7 +8,14 @@
 (WK) Canvas Paint (DHTML version of MS Paint),http://www.canvaspaint.org
 (WK) DHTML Lemmings!,http://www.elizium.nu/scripts/lemmings/
 (WK) DHTML graphics demos,http://www.dhteumeuleu.com/
-(WK) Neat Javascript 3D,http://gyu.que.jp/jscloth/
+(Flash) YouTube,http://youtube.com
+(Flash) Vimeo,http://www.vimeo.com/1778399
+(Flash) Simple whiteboard,http://www.imaginationcubed.com/
+(Flash) Dabble Board,http://www.dabbleboard.com/draw
+(Flash) Bubble Shooter game,http://www.wiicade.com/playGame.aspx?gameID=72&gameName=Bubble%20Shooter 
+(Flash) Pixlr photo editor,http://pixlr.com/editor/
+(Flash) Scribd,http://www.scribd.com/doc/14427744/Second-Life-Quickstart-Guide
+(Flash) MAME,http://yvern.com/fMAME/fMAME.html
 (QT) Local sample,file:///C|/Program Files/QuickTime/Sample.mov
 (QT) Movie - Watchmen Trailer,http://movies.apple.com/movies/wb/watchmen/watchmen-tlr2_480p.mov
 (QT) Movie - Transformers - Revenge of the Fallen,http://movies.apple.com/movies/paramount/transformers2/transformersrevengeofthefallen-tlr1_h.320.mov
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index 7869763302f30d5fa67c460e7261f2a8209897c8..234422b68a785f01b59a7fa55f7b596ae5508910 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -44,6 +44,7 @@
 
 #if __APPLE__
 	#include <GLUT/glut.h>
+	#include <CoreFoundation/CoreFoundation.h>
 #else
 	#define FREEGLUT_STATIC
 	#include "GL/freeglut.h"
@@ -137,6 +138,8 @@ LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int wind
 	mMediaBrowserControlBackButtonFlag( true ),
 	mMediaBrowserControlForwardButtonFlag( true ),
 	mHomeWebUrl( "http://www.google.com/" )
+	//mHomeWebUrl( "file:///C|/Program Files/QuickTime/Sample.mov" )
+	//mHomeWebUrl( "http://movies.apple.com/movies/wb/watchmen/watchmen-tlr2_480p.mov" )
 {
 	// debugging spam
 	std::cout << std::endl << "             GLUT version: " << "3.7.6" << std::endl;	// no way to get real version from GLUT
@@ -2007,6 +2010,11 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e
 			std::cerr <<  "Media event:  MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << std::endl;
 		break;
 
+		case MEDIA_EVENT_NAME_CHANGED:
+			std::cerr <<  "Media event:  MEDIA_EVENT_NAME_CHANGED, new name is: " << self->getMediaName() << std::endl;
+			glutSetWindowTitle( self->getMediaName().c_str() );
+		break;
+
 		case MEDIA_EVENT_LOCATION_CHANGED:
 		{
 			std::cerr <<  "Media event:  MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << std::endl;
@@ -2033,6 +2041,10 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e
 		case MEDIA_EVENT_PLUGIN_FAILED:
 			std::cerr <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED" << std::endl;
 		break;
+
+		case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
+			std::cerr <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << std::endl;
+		break;
 	}
 }
 
@@ -2107,6 +2119,25 @@ void glutMouseButton( int button, int state, int x, int y )
 //
 int main( int argc, char* argv[] )
 {
+#if LL_DARWIN
+	// Set the current working directory to <application bundle>/Contents/Resources/
+	CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
+	if(resources_url != NULL)
+	{
+		CFStringRef resources_string = CFURLCopyFileSystemPath(resources_url, kCFURLPOSIXPathStyle);
+		CFRelease(resources_url);
+		if(resources_string != NULL)
+		{
+			char buffer[PATH_MAX] = "";
+			if(CFStringGetCString(resources_string, buffer, sizeof(buffer), kCFStringEncodingUTF8))
+			{
+				chdir(buffer);
+			}
+			CFRelease(resources_string);
+		}
+	}
+#endif
+
 	glutInit( &argc, argv );
 	glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );
 
diff --git a/indra/viewer_components/CMakeLists.txt b/indra/viewer_components/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c95c854b7c60b4108819410df5ea9cdded549c4d
--- /dev/null
+++ b/indra/viewer_components/CMakeLists.txt
@@ -0,0 +1,5 @@
+# -*- cmake -*-
+
+add_subdirectory(login)
+add_subdirectory(eventhost)
+
diff --git a/indra/viewer_components/login/CMakeLists.txt b/indra/viewer_components/login/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fb65779eb7320a1866b4f9cb1756b7a8411a2bd5
--- /dev/null
+++ b/indra/viewer_components/login/CMakeLists.txt
@@ -0,0 +1,56 @@
+# -*- cmake -*-
+
+project(login)
+
+include(00-Common)
+include(LLAddBuildTest)
+include(LLCommon)
+include(LLMath)
+include(LLXML)
+include(Pth)
+
+include_directories(
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLMATH_INCLUDE_DIRS}
+    ${LLXML_INCLUDE_DIRS}
+    ${PTH_INCLUDE_DIRS}
+    )
+
+set(login_SOURCE_FILES
+    lllogin.cpp
+    )
+
+set(login_HEADER_FILES
+    lllogin.h
+    )
+
+set_source_files_properties(${login_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND 
+    login_SOURCE_FILES 
+    ${login_HEADER_FILES} 
+    )
+
+add_library(lllogin 
+            ${login_SOURCE_FILES}
+            )
+
+target_link_libraries(lllogin
+    ${LLCOMMON_LIBRARIES}
+    ${LLMATH_LIBRARIES}
+    ${LLXML_LIBRARIES}
+    ${PTH_LIBRARIES}
+    )
+
+SET(lllogin_TEST_SOURCE_FILES
+    lllogin.cpp
+    )
+
+set_source_files_properties(
+  lllogin.cpp
+  PROPERTIES
+    LL_TEST_ADDITIONAL_LIBRARIES "${PTH_LIBRARIES}"
+  )
+
+LL_ADD_PROJECT_UNIT_TESTS(lllogin "${lllogin_TEST_SOURCE_FILES}")
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7a30315b9a8c7c30b110f4c3f78bf84c1fe942f8
--- /dev/null
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -0,0 +1,374 @@
+/** 
+ * @file lllogin.cpp
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include <boost/coroutine/coroutine.hpp>
+#include "linden_common.h"
+#include "llsd.h"
+#include "llsdutil.h"
+
+/*==========================================================================*|
+#ifdef LL_WINDOWS
+	// non-virtual destructor warning, boost::statechart does this intentionally.
+	#pragma warning (disable : 4265) 
+#endif
+|*==========================================================================*/
+
+#include "lllogin.h"
+
+#include <boost/bind.hpp>
+
+#include "llcoros.h"
+#include "llevents.h"
+#include "lleventfilter.h"
+#include "lleventcoro.h"
+
+//*********************
+// LLLogin
+// *NOTE:Mani - Is this Impl needed now that the state machine runs the show?
+class LLLogin::Impl
+{
+public:
+    Impl():
+		mPump("login", true) // Create the module's event pump with a tweaked (unique) name.
+    {
+        mValidAuthResponse["status"]        = LLSD();
+        mValidAuthResponse["errorcode"]     = LLSD();
+        mValidAuthResponse["error"]         = LLSD();
+        mValidAuthResponse["transfer_rate"] = LLSD();
+    }
+
+    void connect(const std::string& uri, const LLSD& credentials);
+    void disconnect();
+	LLEventPump& getEventPump() { return mPump; }
+
+private:
+	void sendProgressEvent(const std::string& state, const std::string& change,
+						   const LLSD& data = LLSD())
+	{
+		LLSD status_data;
+		status_data["state"] = state;
+		status_data["change"] = change;
+		status_data["progress"] = 0.0f;
+
+		if(mAuthResponse.has("transfer_rate"))
+		{
+			status_data["transfer_rate"] = mAuthResponse["transfer_rate"];
+		}
+
+		if(data.isDefined())
+		{
+			status_data["data"] = data;
+		}
+
+		mPump.post(status_data);
+	}
+
+    LLSD validateResponse(const std::string& pumpName, const LLSD& response)
+    {
+        // Validate the response. If we don't recognize it, things
+        // could get ugly.
+        std::string mismatch(llsd_matches(mValidAuthResponse, response));
+        if (! mismatch.empty())
+        {
+            LL_ERRS("LLLogin") << "Received unrecognized event (" << mismatch << ") on "
+                               << pumpName << "pump: " << response
+                               << LL_ENDL;
+            return LLSD();
+        }
+
+        return response;
+    }
+
+    // In a coroutine's top-level function args, do NOT NOT NOT accept
+    // references (const or otherwise) to anything but the self argument! Pass
+    // by value only!
+    void login_(LLCoros::self& self, std::string uri, LLSD credentials);
+
+    LLEventStream mPump;
+	LLSD mAuthResponse, mValidAuthResponse;
+};
+
+void LLLogin::Impl::connect(const std::string& uri, const LLSD& credentials)
+{
+    // Launch a coroutine with our login_() method. Run the coroutine until
+    // its first wait; at that point, return here.
+    std::string coroname = 
+        LLCoros::instance().launch("LLLogin::Impl::login_",
+                                   boost::bind(&Impl::login_, this, _1, uri, credentials));
+}
+
+void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credentials)
+{
+    LL_INFOS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
+                        << " with uri '" << uri << "', credentials " << credentials << LL_ENDL;
+    // Arriving in SRVRequest state
+    LLEventStream replyPump("reply", true);
+    // Should be an array of one or more uri strings.
+    LLSD rewrittenURIs;
+    {
+        LLEventTimeout filter(replyPump);
+        sendProgressEvent("offline", "srvrequest");
+
+        // Request SRV record.
+        LL_INFOS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
+
+        // *NOTE:Mani - Completely arbitrary timeout value for SRV request.
+        filter.errorAfter(5, "SRV Request timed out!");
+
+        // Make request
+        LLSD request;
+        request["op"] = "rewriteURI";
+        request["uri"] = uri;
+        request["reply"] = replyPump.getName();
+        rewrittenURIs = postAndWait(self, request, "LLAres", filter);
+    } // we no longer need the filter
+
+    LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction"));
+
+    // Loop through the rewrittenURIs, counting attempts along the way.
+    // Because of possible redirect responses, we may make more than one
+    // attempt per rewrittenURIs entry.
+    LLSD::Integer attempts = 0;
+    for (LLSD::array_const_iterator urit(rewrittenURIs.beginArray()),
+             urend(rewrittenURIs.endArray());
+         urit != urend; ++urit)
+    {
+        LLSD request(credentials);
+        request["reply"] = replyPump.getName();
+        request["uri"] = *urit;
+        std::string status;
+
+        // Loop back to here if login attempt redirects to a different
+        // request["uri"]
+        for (;;)
+        {
+            ++attempts;
+            LLSD progress_data;
+            progress_data["attempt"] = attempts;
+            progress_data["request"] = request;
+            sendProgressEvent("offline", "authenticating", progress_data);
+
+            // We expect zero or more "Downloading" status events, followed by
+            // exactly one event with some other status. Use postAndWait() the
+            // first time, because -- at least in unit-test land -- it's
+            // possible for the reply to arrive before the post() call
+            // returns. Subsequent responses, of course, must be awaited
+            // without posting again.
+            for (mAuthResponse = validateResponse(replyPump.getName(),
+                                     postAndWait(self, request, xmlrpcPump, replyPump, "reply"));
+                 mAuthResponse["status"].asString() == "Downloading";
+                 mAuthResponse = validateResponse(replyPump.getName(),
+                                     waitForEventOn(self, replyPump)))
+            {
+                // Still Downloading -- send progress update.
+                sendProgressEvent("offline", "downloading");
+            }
+            status = mAuthResponse["status"].asString();
+
+            // Okay, we've received our final status event for this
+            // request. Unless we got a redirect response, break the retry
+            // loop for the current rewrittenURIs entry.
+            if (! (status == "Complete" &&
+                   mAuthResponse["responses"]["login"].asString() == "indeterminate"))
+            {
+                break;
+            }
+
+            // Here the login service at the current URI is redirecting us
+            // to some other URI ("indeterminate" -- why not "redirect"?).
+            // The response should contain another uri to try, with its
+            // own auth method.
+            request["uri"] = mAuthResponse["next_url"];
+            request["method"] = mAuthResponse["next_method"];
+        } // loop back to try the redirected URI
+
+        // Here we're done with redirects for the current rewrittenURIs
+        // entry.
+        if (status == "Complete")
+        {
+            // StatusComplete does not imply auth success. Check the
+            // actual outcome of the request. We've already handled the
+            // "indeterminate" case in the loop above.
+            if (mAuthResponse["responses"]["login"].asString() == "true")
+            {
+                sendProgressEvent("online", "connect", mAuthResponse["responses"]);
+            }
+            else
+            {
+                sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
+            }
+            return;             // Done!
+        }
+        // If we don't recognize status at all, trouble
+        if (! (status == "CURLError"
+               || status == "XMLRPCError"
+               || status == "OtherError"))
+        {
+            LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
+                               << mAuthResponse << LL_ENDL;
+            return;
+        }
+
+        // Here status IS one of the errors tested above.
+    } // Retry if there are any more rewrittenURIs.
+
+    // Here we got through all the rewrittenURIs without succeeding. Tell
+    // caller this didn't work out so well. Of course, the only failure data
+    // we can reasonably show are from the last of the rewrittenURIs.
+    sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
+}
+
+void LLLogin::Impl::disconnect()
+{
+    sendProgressEvent("offline", "disconnect");
+}
+
+//*********************
+// LLLogin
+LLLogin::LLLogin() :
+	mImpl(new LLLogin::Impl())
+{
+}
+
+LLLogin::~LLLogin()
+{
+}
+
+void LLLogin::connect(const std::string& uri, const LLSD& credentials)
+{
+	mImpl->connect(uri, credentials);
+}
+
+
+void LLLogin::disconnect()
+{
+	mImpl->disconnect();
+}
+
+LLEventPump& LLLogin::getEventPump()
+{
+	return mImpl->getEventPump();
+}
+
+// The following is the list of important functions that happen in the 
+// current login process that we want to move to this login module.
+
+// The list associates to event with the original idle_startup() 'STATE'.
+
+// Rewrite URIs
+ // State_LOGIN_AUTH_INIT
+// Given a vector of login uris (usually just one), perform a dns lookup for the 
+// SRV record from each URI. I think this is used to distribute login requests to 
+// a single URI to multiple hosts.
+// This is currently a synchronous action. (See LLSRV::rewriteURI() implementation)
+// On dns lookup error the output uris == the input uris.
+//
+// Input: A vector of login uris
+// Output: A vector of login uris
+//
+// Code:
+// std::vector<std::string> uris;
+// LLViewerLogin::getInstance()->getLoginURIs(uris);
+// std::vector<std::string>::const_iterator iter, end;
+// for (iter = uris.begin(), end = uris.end(); iter != end; ++iter)
+// {
+//	std::vector<std::string> rewritten;
+//	rewritten = LLSRV::rewriteURI(*iter);
+//	sAuthUris.insert(sAuthUris.end(),
+//					 rewritten.begin(), rewritten.end());
+// }
+// sAuthUriNum = 0;
+
+// Authenticate 
+// STATE_LOGIN_AUTHENTICATE
+// Connect to the login server, presumably login.cgi, requesting the login 
+// and a slew of related initial connection information.
+// This is an asynch action. The final response, whether success or error
+// is handled by STATE_LOGIN_PROCESS_REPONSE.
+// There is no immediate error or output from this call.
+// 
+// Input: 
+//  URI
+//  Credentials (first, last, password)
+//  Start location
+//  Bool Flags:
+//    skip optional update
+//    accept terms of service
+//    accept critical message
+//  Last exec event. (crash state of previous session)
+//  requested optional data (inventory skel, initial outfit, etc.)
+//  local mac address
+//  viewer serial no. (md5 checksum?)
+
+//sAuthUriNum = llclamp(sAuthUriNum, 0, (S32)sAuthUris.size()-1);
+//LLUserAuth::getInstance()->authenticate(
+//	sAuthUris[sAuthUriNum],
+//	auth_method,
+//	firstname,
+//	lastname,			
+//	password, // web_login_key,
+//	start.str(),
+//	gSkipOptionalUpdate,
+//	gAcceptTOS,
+//	gAcceptCriticalMessage,
+//	gLastExecEvent,
+//	requested_options,
+//	hashed_mac_string,
+//	LLAppViewer::instance()->getSerialNumber());
+
+//
+// Download the Response
+// STATE_LOGIN_NO_REPONSE_YET and STATE_LOGIN_DOWNLOADING
+// I had assumed that this was default behavior of the message system. However...
+// During login, the message system is checked only by these two states in idle_startup().
+// I guess this avoids the overhead of checking network messages for those login states
+// that don't need to do so, but geez!
+// There are two states to do this one function just to update the login
+// status text from 'Logging In...' to 'Downloading...'
+// 
+
+//
+// Handle Login Response
+// STATE_LOGIN_PROCESS_RESPONSE
+// 
+// This state handle the result of the request to login. There is a metric ton of
+// code in this case. This state will transition to:
+// STATE_WORLD_INIT, on success.
+// STATE_AUTHENTICATE, on failure.
+// STATE_UPDATE_CHECK, to handle user during login interaction like TOS display.
+//
+// Much of the code in this case belongs on the viewer side of the fence and not in login. 
+// Login should probably return with a couple of events, success and failure.
+// Failure conditions can be specified in the events data pacet to allow the viewer 
+// to re-engauge login as is appropriate. (Or should there be multiple failure messages?)
+// Success is returned with the data requested from the login. According to OGP specs 
+// there may be intermediate steps before reaching this result in future login 
+// implementations.
diff --git a/indra/viewer_components/login/lllogin.h b/indra/viewer_components/login/lllogin.h
new file mode 100644
index 0000000000000000000000000000000000000000..0598b4e45724c3386b6bfb053e29ef966b0e34bc
--- /dev/null
+++ b/indra/viewer_components/login/lllogin.h
@@ -0,0 +1,133 @@
+/** 
+ * @file lllogin.h
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLOGIN_H
+#define LL_LLLOGIN_H
+
+#include <boost/scoped_ptr.hpp>
+
+class LLSD;
+class LLEventPump;
+
+/**
+ * @class LLLogin
+ * @brief Class to encapsulate the action and state of grid login.
+ */
+class LLLogin
+{
+public:
+	LLLogin();
+	~LLLogin();
+
+	/** 
+	 * Make a connection to a grid.
+	 * @param uri The 'well known and published' authentication URL.
+	 * @param credentials LLSD data that contians the credentials.
+	 * *NOTE:Mani The credential data can vary depending upon the authentication
+	 * method used. The current interface matches the values passed to
+	 * the XMLRPC login request.
+	 {
+		method			:	string, 
+		first			:	string,
+		last			:	string,
+		passwd			:	string,
+		start			:	string,
+		skipoptional	:	bool,
+		agree_to_tos	:	bool,
+		read_critical	:	bool,
+		last_exec_event	:	int,
+		version			:	string,
+		channel			:	string,
+		mac				:	string,
+		id0				:	string,
+		options			:   [ strings ]
+	 }
+	 
+	 */
+	void connect(const std::string& uri, const LLSD& credentials);
+	
+    /** 
+	 * Disconnect from a the current connection.
+	 */
+	void disconnect();
+
+    /** 
+	 * Retrieve the event pump from this login class.
+	 */
+	LLEventPump& getEventPump();
+
+	/*
+	Event API
+
+	LLLogin will issue multiple events to it pump to indicate the 
+	progression of states through login. The most important 
+	states are "offline" and "online" which indicate auth failure 
+	and auth success respectively.
+
+	pump: login (tweaked)
+	These are the events posted to the 'login' 
+	event pump from the login module.
+	{
+		state		:	string, // See below for the list of states.
+		progress	:   real // for progress bar.
+		data		:   LLSD // Dependent upon state.
+	}
+	
+	States for method 'login_to_simulator'
+	offline - set initially state and upon failure. data is the server response.
+	srvrequest - upon uri rewrite request. no data.
+	authenticating - upon auth request. data, 'attempt' number and 'request' llsd.
+	downloading - upon ack from auth server, before completion. no data
+	online - upon auth success. data is server response.
+
+
+	Dependencies:
+	pump: LLAres 
+	LLLogin makes a request for a SRV record from the uri provided by the connect method.
+	The following event pump should exist to service that request.
+	pump name: LLAres
+	request = {
+		op : "rewriteURI"
+		uri : string
+		reply : string
+
+	pump: LLXMLRPCListener
+	The request merely passes the credentials LLSD along, with one additional 
+	member, 'reply', which is the string name of the event pump to reply on. 
+	
+	*/
+
+private:
+	class Impl;
+	boost::scoped_ptr<Impl> mImpl;
+};
+
+#endif // LL_LLLOGIN_H
diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a8ae2883d54ddcd13899e2d4a7bdc6284c46f686
--- /dev/null
+++ b/indra/viewer_components/login/tests/lllogin_test.cpp
@@ -0,0 +1,417 @@
+/**
+ * @file   lllogin_test.cpp
+ * @author Mark Palange
+ * @date   2009-02-26
+ * @brief  Tests of lllogin.cpp.
+ * 
+ * $LicenseInfo:firstyear=2009&license=internal$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "../lllogin.h"
+// STL headers
+// std headers
+#include <iostream>
+// external library headers
+// other Linden headers
+#include "llsd.h"
+#include "../../../test/lltut.h"
+//#define DEBUG_ON
+#include "../../../test/debug.h"
+#include "llevents.h"
+#include "stringize.h"
+
+/*****************************************************************************
+*   Helper classes
+*****************************************************************************/
+// This is a listener to receive results from lllogin.
+class LoginListener: public LLEventTrackable
+{
+	std::string mName;
+	LLSD mLastEvent;
+    Debug mDebug;
+public:
+	LoginListener(const std::string& name) : 
+		mName(name),
+        mDebug(stringize(*this))
+	{}
+
+	bool call(const LLSD& event)
+	{
+		mDebug(STRINGIZE("LoginListener called!: " << event));
+		mLastEvent = event;
+		return false;
+	}
+
+    LLBoundListener listenTo(LLEventPump& pump)
+    {
+        return pump.listen(mName, boost::bind(&LoginListener::call, this, _1));
+	}
+
+	LLSD lastEvent() const { return mLastEvent; }
+
+    friend std::ostream& operator<<(std::ostream& out, const LoginListener& listener)
+    {
+        return out << "LoginListener(" << listener.mName << ')';
+    }
+};
+
+class LLAresListener: public LLEventTrackable
+{
+	std::string mName;
+	LLSD mEvent;
+	bool mImmediateResponse;
+	bool mMultipleURIResponse;
+    Debug mDebug;
+	
+public:
+	LLAresListener(const std::string& name, 
+				   bool i = false,
+				   bool m = false
+				   ) : 
+		mName(name),
+		mImmediateResponse(i),
+		mMultipleURIResponse(m),
+        mDebug(stringize(*this))
+	{}
+
+	bool handle_event(const LLSD& event)
+	{
+		mDebug(STRINGIZE("LLAresListener called!: " << event));
+		mEvent = event;
+		if(mImmediateResponse)
+		{
+			sendReply();
+		}
+		return false;
+	}
+
+	void sendReply()
+	{
+		if(mEvent["op"].asString() == "rewriteURI")
+		{
+			LLSD result;
+			if(mMultipleURIResponse)
+			{
+				result.append(LLSD("login.foo.com"));
+			}
+			result.append(mEvent["uri"]);
+			LLEventPumps::instance().obtain(mEvent["reply"]).post(result);
+		}
+	}
+
+	LLBoundListener listenTo(LLEventPump& pump)
+    {
+        return pump.listen(mName, boost::bind(&LLAresListener::handle_event, this, _1));
+	}
+
+    friend std::ostream& operator<<(std::ostream& out, const LLAresListener& listener)
+    {
+        return out << "LLAresListener(" << listener.mName << ')';
+    }
+};
+
+class LLXMLRPCListener: public LLEventTrackable
+{
+	std::string mName;
+	LLSD mEvent;
+	bool mImmediateResponse;
+	LLSD mResponse;
+    Debug mDebug;
+
+public:
+	LLXMLRPCListener(const std::string& name, 
+					 bool i = false,
+					 const LLSD& response = LLSD()
+					 ) : 
+		mName(name),
+		mImmediateResponse(i),
+		mResponse(response),
+        mDebug(stringize(*this))
+	{
+		if(mResponse.isUndefined())
+		{
+			mResponse["status"] = "Complete"; // StatusComplete
+			mResponse["errorcode"] = 0;
+			mResponse["error"] = "dummy response";
+			mResponse["transfer_rate"] = 0;
+			mResponse["responses"]["login"] = true;
+		}
+	}
+
+	void setResponse(const LLSD& r) 
+	{ 
+		mResponse = r; 
+	}
+
+	bool handle_event(const LLSD& event)
+	{
+		mDebug(STRINGIZE("LLXMLRPCListener called!: " << event));
+		mEvent = event;
+		if(mImmediateResponse)
+		{
+			sendReply();
+		}
+		return false;
+	}
+
+	void sendReply()
+	{
+		LLEventPumps::instance().obtain(mEvent["reply"]).post(mResponse);
+	}
+
+	LLBoundListener listenTo(LLEventPump& pump)
+    {
+        return pump.listen(mName, boost::bind(&LLXMLRPCListener::handle_event, this, _1));
+	}
+
+    friend std::ostream& operator<<(std::ostream& out, const LLXMLRPCListener& listener)
+    {
+        return out << "LLXMLRPCListener(" << listener.mName << ')';
+    }
+};
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct llviewerlogin_data
+    {
+		llviewerlogin_data() :
+            pumps(LLEventPumps::instance())
+		{}
+		LLEventPumps& pumps;
+	};
+
+    typedef test_group<llviewerlogin_data> llviewerlogin_group;
+    typedef llviewerlogin_group::object llviewerlogin_object;
+    llviewerlogin_group llviewerlogingrp("llviewerlogin");
+
+    template<> template<>
+    void llviewerlogin_object::test<1>()
+    {
+        DEBUG;
+		// Testing login with immediate repsonses from Ares and XMLPRC
+		// The response from both requests will come before the post request exits.
+		// This tests an edge case of the login state handling.
+		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
+		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
+
+		bool respond_immediately = true;
+		// Have 'dummy ares' repsond immediately. 
+		LLAresListener dummyLLAres("dummy_llares", respond_immediately);
+		dummyLLAres.listenTo(llaresPump);
+
+		// Have dummy XMLRPC respond immediately.
+		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately);
+		dummyXMLRPC.listenTo(xmlrpcPump);
+
+		LLLogin login;
+
+		LoginListener listener("test_ear");
+		listener.listenTo(login.getEventPump());
+
+		LLSD credentials;
+		credentials["first"] = "foo";
+		credentials["last"] = "bar";
+		credentials["passwd"] = "secret";
+
+		login.connect("login.bar.com", credentials);
+
+		ensure_equals("Online state", listener.lastEvent()["state"].asString(), "online");
+	}
+
+    template<> template<>
+    void llviewerlogin_object::test<2>()
+    {
+        DEBUG;
+		// Tests a successful login in with delayed responses. 
+		// Also includes 'failure' that cause the login module
+		// To re-attempt connection, once from a basic failure
+		// and once from the 'indeterminate' response.
+
+		set_test_name("LLLogin multiple srv uris w/ success");
+
+		// Testing normal login procedure.
+		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
+		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
+
+		bool respond_immediately = false;
+		bool multiple_addresses = true;
+		LLAresListener dummyLLAres("dummy_llares", respond_immediately, multiple_addresses);
+		dummyLLAres.listenTo(llaresPump);
+
+		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
+		dummyXMLRPC.listenTo(xmlrpcPump);
+
+		LLLogin login;
+
+		LoginListener listener("test_ear");
+		listener.listenTo(login.getEventPump());
+
+		LLSD credentials;
+		credentials["first"] = "foo";
+		credentials["last"] = "bar";
+		credentials["passwd"] = "secret";
+
+		login.connect("login.bar.com", credentials);
+
+		ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest"); 
+
+		dummyLLAres.sendReply();
+
+		// Test Authenticating State prior to first response.
+		ensure_equals("Auth state 1", listener.lastEvent()["change"].asString(), "authenticating"); 
+		ensure_equals("Attempt 1", listener.lastEvent()["data"]["attempt"].asInteger(), 1); 
+		ensure_equals("URI 1", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.foo.com"); 
+
+		// First send emulated LLXMLRPCListener failure,
+		// this should return login to the authenticating step and increase the attempt 
+		// count.
+		LLSD data;
+		data["status"] = "OtherError"; 
+		data["errorcode"] = 0;
+		data["error"] = "dummy response";
+		data["transfer_rate"] = 0;
+		dummyXMLRPC.setResponse(data);
+		dummyXMLRPC.sendReply();
+
+		ensure_equals("Fail back to authenticate 1", listener.lastEvent()["change"].asString(), "authenticating"); 
+		ensure_equals("Attempt 2", listener.lastEvent()["data"]["attempt"].asInteger(), 2); 
+		ensure_equals("URI 2", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com"); 
+
+		// Now send the 'indeterminate' response.
+		data.clear();
+		data["status"] = "Complete"; // StatusComplete
+		data["errorcode"] = 0;
+		data["error"] = "dummy response";
+		data["transfer_rate"] = 0;
+		data["responses"]["login"] = "indeterminate";
+		data["next_url"] = "login.indeterminate.com";			
+		data["next_method"] = "test_login_method"; 			
+		dummyXMLRPC.setResponse(data);
+		dummyXMLRPC.sendReply();
+
+		ensure_equals("Fail back to authenticate 2", listener.lastEvent()["change"].asString(), "authenticating"); 
+		ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3); 
+		ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com"); 
+
+		// Finally let the auth succeed.
+		data.clear();
+		data["status"] = "Complete"; // StatusComplete
+		data["errorcode"] = 0;
+		data["error"] = "dummy response";
+		data["transfer_rate"] = 0;
+		data["responses"]["login"] = "true";
+		dummyXMLRPC.setResponse(data);
+		dummyXMLRPC.sendReply();
+
+		ensure_equals("Success state", listener.lastEvent()["state"].asString(), "online");
+
+		login.disconnect();
+
+		ensure_equals("Disconnected state", listener.lastEvent()["state"].asString(), "offline");
+	}
+
+    template<> template<>
+    void llviewerlogin_object::test<3>()
+    {
+        DEBUG;
+		// Test completed response, that fails to login.
+		set_test_name("LLLogin valid response, failure (eg. bad credentials)");
+
+		// Testing normal login procedure.
+		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
+		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
+
+		LLAresListener dummyLLAres("dummy_llares");
+		dummyLLAres.listenTo(llaresPump);
+
+		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
+		dummyXMLRPC.listenTo(xmlrpcPump);
+
+		LLLogin login;
+		LoginListener listener("test_ear");
+		listener.listenTo(login.getEventPump());
+
+		LLSD credentials;
+		credentials["first"] = "who";
+		credentials["last"] = "what";
+		credentials["passwd"] = "badpasswd";
+
+		login.connect("login.bar.com", credentials);
+
+		ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest"); 
+
+		dummyLLAres.sendReply();
+
+		ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating"); 
+
+		// Send the failed auth request reponse
+		LLSD data;
+		data["status"] = "Complete";
+		data["errorcode"] = 0;
+		data["error"] = "dummy response";
+		data["transfer_rate"] = 0;
+		data["responses"]["login"] = "false";
+		dummyXMLRPC.setResponse(data);
+		dummyXMLRPC.sendReply();
+
+		ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
+	}
+
+    template<> template<>
+    void llviewerlogin_object::test<4>()
+    {
+        DEBUG;
+		// Test incomplete response, that end the attempt.
+		set_test_name("LLLogin valid response, failure (eg. bad credentials)");
+
+		// Testing normal login procedure.
+		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
+		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
+
+		LLAresListener dummyLLAres("dummy_llares");
+		dummyLLAres.listenTo(llaresPump);
+
+		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
+		dummyXMLRPC.listenTo(xmlrpcPump);
+
+		LLLogin login;
+		LoginListener listener("test_ear");
+		listener.listenTo(login.getEventPump());
+
+		LLSD credentials;
+		credentials["first"] = "these";
+		credentials["last"] = "don't";
+		credentials["passwd"] = "matter";
+
+		login.connect("login.bar.com", credentials);
+
+		ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest"); 
+
+		dummyLLAres.sendReply();
+
+		ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating"); 
+
+		// Send the failed auth request reponse
+		LLSD data;
+		data["status"] = "OtherError";
+		data["errorcode"] = 0;
+		data["error"] = "dummy response";
+		data["transfer_rate"] = 0;
+		dummyXMLRPC.setResponse(data);
+		dummyXMLRPC.sendReply();
+
+		ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
+	}
+}
diff --git a/install.xml b/install.xml
index 44224664cae498d630fe64c1ef1eb4f9021739ec..2ab458d88b2b855202d951883432bd94abd29195 100644
--- a/install.xml
+++ b/install.xml
@@ -71,9 +71,9 @@
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>abd07d760cdc7d23da3b861f34b09c92</string>
+            <string>115d8ac44a91efdb173e9b3e478c46b6</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.8-darwin-20080812.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.7-darwin-20090805.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>
@@ -92,9 +92,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>b9d23a69a25fdeed96dcc3bf696b6514</string>
+            <string>a02619c1e30a3db02d3883bf1ad7a1e6</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.12-windows-20080806.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.8-windows-20090911.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -132,9 +132,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>6a53b02a07527de680f1336e20f74f08</string>
+            <string>4e2d4de03dce8a991a5727c15a284e8d</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.4.0-windows-20080723.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.3.0-windows-20090917.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -193,30 +193,30 @@
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>6be5bca5f4b031b1b79824da5cfd4ddf</string>
+            <string>74f3a765644927c93fa3bc7acc730552</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-darwin-20090702a.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-darwin-20090805.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>
             <key>md5sum</key>
-            <string>113ca35011c916660a8aa55bc1ca462a</string>
+            <string>8fb4151b883b5f5d2b12da19a6ff8e7d</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-linux-20090702.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-linux-20090804.tar.bz2</uri>
           </map>
           <key>linux64</key>
           <map>
             <key>md5sum</key>
-            <string>270f64d3aa416cec96f445d58dfcfb6d</string>
+            <string>77237f33b1740daef0dc1e6c801f68e1</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-linux64-20090702.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-linux64-20090804.tar.bz2</uri>
           </map>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>44d4fdf386742b94419c93ad2baa1616</string>
+            <string>4f05166629caa4c132a7448eefb8d592</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-windows-20090702.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-windows-20090917.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -254,9 +254,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>8c9d135f0e7cd1fae5681d4595942ee3</string>
+            <string>8dc4e818c2d6fbde76e9a5e34f4ffa72</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.16.4-windows-20090306.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.19.6-windows-20090917b.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -326,9 +326,9 @@
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>9c5603e328e9f543e0a599d6b25be973</string>
+            <string>c457a0a041ac4946265889a503d26c3d</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20080812.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20090805.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>
@@ -347,9 +347,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>cca5ca3759f645d4a124d4b96df7f717</string>
+            <string>5dbbdb4a9b5bec86d180ef20a5f8ccfb</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-windows-20080715.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-windows-20090917.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -450,9 +450,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>953027c7718176aace3fd0766e3c4a73</string>
+            <string>88980fd6d91ac541b62dea877ebe6ba6</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-windows-20090814.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-windows-20090917.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -583,6 +583,39 @@
           </map>
         </map>
       </map>
+      <key>googlemock</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright 2008, Google Inc.</string>
+        <key>description</key>
+        <string>Google C++ Mocking Framework (or Google Mock for short) is a library for writing and using C++ mock classes.</string>
+        <key>license</key>
+        <string>bsd</string>
+        <key>packages</key>
+        <map>
+          <key>darwin</key>
+          <map>
+            <key>md5sum</key>
+            <string>4863e9fea433d0a4be761ea5d3e8346a</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-darwin-20090626.tar.bz2</uri>
+          </map>
+          <key>linux</key>
+          <map>
+            <key>md5sum</key>
+            <string>877dabecf84339690191c6115c76366e</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-linux32-20090527.tar.bz2</uri>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>md5sum</key>
+            <string>f601a82ea91030974072da8924cae41e</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-windows-20090921.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>gstreamer</key>
       <map>
         <key>license</key>
@@ -705,9 +738,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>e40d2df9aaefb3bd57289fe96766353a</string>
+            <string>6a6bb0143a2561e3276dab4bcfa425ef</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-windows-20080723.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-windows-20090917a.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -859,9 +892,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>a3975dcdb9a3ba0ca179b673b5e9b55e</string>
+            <string>c781cd9846cf20afb90ac40ad1a0ce9d</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-windows-20090306.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-windows-20090917.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -929,9 +962,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>0edde7f54c0229cd6f615917198becaf</string>
+            <string>6c6282025d1b8cd9e70c0f858a14fdca</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-windows-20090920.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-windows-20091001.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1024,9 +1057,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>8ac100b5b711231b06be891c91cb68f3</string>
+            <string>f0df8a1e60991095e3adca1450b8c9c0</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-windows-20080723.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-windows-20090917.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1186,6 +1219,53 @@ anguage Infrstructure (CLI) international standard</string>
           </map>
         </map>
       </map>
+      <key>pth</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright (c) 1999-2006 Ralf S. Engelschall &lt;rse@gnu.org&gt;</string>
+        <key>description</key>
+        <string>Portable cooperative threads package, used to support Boost.Coroutine on Mac OS X 10.4</string>
+        <key>license</key>
+        <string>lgpl</string>
+        <key>packages</key>
+        <map>
+          <key>darwin</key>
+          <map>
+            <key>md5sum</key>
+            <string>216cb6217a06c64dfae30a55ab8b975c</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-darwin-20090923.tar.bz2</uri>
+          </map>
+          <key>linux</key>
+          <map>
+            <key>md5sum</key>
+            <string>c5c2f73847c126e679d925beab48c7d4</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-linux-20090427.tar.bz2</uri>
+          </map>
+          <key>linux32</key>
+          <map>
+            <key>md5sum</key>
+            <string>c5c2f73847c126e679d925beab48c7d4</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-linux32-20090427.tar.bz2</uri>
+          </map>
+          <key>linux64</key>
+          <map>
+            <key>md5sum</key>
+            <string>c5c2f73847c126e679d925beab48c7d4</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-linux64-20090427.tar.bz2</uri>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>md5sum</key>
+            <string>c5c2f73847c126e679d925beab48c7d4</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-windows-20090427.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>quicktime</key>
       <map>
         <key>copyright</key>
@@ -1341,9 +1421,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>789988ea1fd8615137f843fbbe5b6bfa</string>
+            <string>262629bcaa39dcf7266caa50da01a599</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-windows-20080723.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-windows-20091016.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1381,9 +1461,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>ddb09c2dd7d2caed1bd7cc1686c4214c</string>
+            <string>73baf52a740d151fddbc2a008369c462</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3-windows-20090505.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3-windows-20090921.tar.bz2</uri>
           </map>
         </map>
       </map>
diff --git a/scripts/install.py b/scripts/install.py
index 6278fba16cb5897f951fd543b76a7759df524c0a..78b8880b95ca09c0de1bc883394fa970e5efdb87 100755
--- a/scripts/install.py
+++ b/scripts/install.py
@@ -64,7 +64,6 @@ def add_indra_lib_path():
 base_dir = add_indra_lib_path()
 
 import copy
-import md5
 import optparse
 import os
 import platform
@@ -75,7 +74,12 @@ def add_indra_lib_path():
 import urllib2
 import urlparse
 
-from sets import Set as set, ImmutableSet as frozenset
+try:
+    # Python 2.6
+    from hashlib import md5
+except ImportError:
+    # Python 2.5 and earlier
+    from md5 import new as md5
 
 from indra.base import llsd
 from indra.util import helpformatter
@@ -106,7 +110,7 @@ def __str__(self):
         return "ifile{%s:%s}" % (self.pkgname, self.url)
 
     def _is_md5sum_match(self):
-        hasher = md5.new(file(self.filename, 'rb').read())
+        hasher = md5(file(self.filename, 'rb').read())
         if hasher.hexdigest() == self.md5sum:
             return  True
         return False
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index 8dce6bef6da677bcf3047c895fe8b1f4edc4d429..a5a99d79f08efb0debc4d911f872090f02ce9f0f 100644
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -5288,6 +5288,10 @@ version 2.0
 		{	AgentLegacyAccess		U8	}
 		{	AgentMaxAccess			U8	}
 	}
+	{
+		AgentInfo				Variable
+		{	Flags					U32	}
+	}
 }
 
 // ChildAgentAlive
diff --git a/scripts/update_version_files.py b/scripts/update_version_files.py
index 9081941521709e01df401be093179d5a7017f32f..ee1ce69a15bb5d865f3f6c6a4e0a647e15b23b43 100755
--- a/scripts/update_version_files.py
+++ b/scripts/update_version_files.py
@@ -241,23 +241,17 @@ def main():
         if update_server:
             server_version = new_version
     else:
-        # Assume we're updating just the build number
-        cl = '%s info "%s"' % (svn, src_root)
-        status, output = _getstatusoutput(cl)
-        if verbose:
-            print
-            print "svn info output:"
-            print "----------------"
-            print output
-
-        branch_match = svn_branch_re.search(output)
-        revision_match = svn_revision_re.search(output)
-        if not branch_match or not revision_match:
-            print "Failed to execute svn info, output follows:"
-            print output
+
+        if llversion.using_svn():
+            revision = llversion.get_svn_revision()
+            branch = llversion.get_svn_branch()
+        elif llversion.using_hg():
+            revision = llversion.get_hg_changeset()
+            branch = llversion.get_hg_repo()
+        else:
+            print >>sys.stderr, "ERROR: could not determine revision and branch"
             return -1
-        branch = branch_match.group(1)
-        revision = revision_match.group(1)
+        
         if skip_on_branch_re and skip_on_branch_re.match(branch):
             print "Release Candidate Build, leaving version files untouched."
             return 0