diff --git a/build.sh b/build.sh
index f9c6beefeded66430d40c4d0d7cd9c5c6be66bed..c5f74c23ee07ac283b76289af82d8d5fe2a2644c 100755
--- a/build.sh
+++ b/build.sh
@@ -59,10 +59,11 @@ pre_build()
     -t $variant \
     -G "$cmake_generator" \
    configure \
-	-DGRID:STRING="$viewer_grid" \
+    -DGRID:STRING="$viewer_grid" \
     -DVIEWER_CHANNEL:STRING="$viewer_channel" \
     -DVIEWER_LOGIN_CHANNEL:STRING="$login_channel" \
     -DINSTALL_PROPRIETARY:BOOL=ON \
+    -DRELEASE_CRASH_REPORTING:BOOL=ON \
     -DLOCALIZESETUP:BOOL=ON \
     -DPACKAGE:BOOL=ON \
     -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 740c2f470c6a39ee4e3ce4377a2738246d4d87fd..0954704c262dcf73e470909cc1b7bc57e537fdf6 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -61,19 +61,27 @@ Aimee Trescothick
 Alejandro Rosenthal
 	VWR-1184
 Aleric Inglewood
+	SNOW-240
 	SNOW-522
 	SNOW-626
 	SNOW-756
 	SNOW-764
 	VWR-10001
+	VWR-10579
 	VWR-10759
 	VWR-10837
 	VWR-12691
 	VWR-12984
 	VWR-13996
 	VWR-14426
+	VWR-24247
+	VWR-24251
+	VWR-24252
+	VWR-24254
+	VWR-24261
 	SNOW-84
 	SNOW-477
+	SNOW-744
 	SNOW-766
 	STORM-163
 Ales Beaumont
@@ -211,6 +219,8 @@ Catherine Pfeffer
 Celierra Darling
 	VWR-1274
 	VWR-6975
+Cron Stardust
+	VWR-10579
 Cypren Christenson
 	STORM-417
 Dale Glass
@@ -354,11 +364,14 @@ JB Kraft
 Joghert LeSabre
 	VWR-64
 Jonathan Yap
-	VWR-17801
+	STORM-596
+	STORM-523
 	STORM-616
 	STORM-679
-	STORM-596
+	STORM-737
 	STORM-726
+	VWR-17801
+	STORM-785
 Kage Pixel
 	VWR-11
 Ken March
@@ -587,6 +600,7 @@ Robin Cornelius
 	STORM-422
 	VWR-2488
 	VWR-9557
+	VWR-10579
 	VWR-11128
 	VWR-12533
 	VWR-12587
@@ -735,6 +749,8 @@ Tue Torok
 	CT-74
 Twisted Laws
 	SNOW-352
+	STORM-466
+	STORM-467
 Vadim Bigbear
 	VWR-2681
 Vector Hastings
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index db2cdb5ff8fa3f41e8f41621d3067f0797d80ca0..dbe0cf5cd051eb02b865210c6c39e104fc1caa6e 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -4,27 +4,28 @@
 
 include(Variables)
 
-
 # Portable compilation flags.
-
-if (EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
-  # The release build should only offer to send crash reports if we're
-  # building from a Linden internal source tree.
-  set(release_crash_reports 1)
-else (EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
-  set(release_crash_reports 0) 
-endif (EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
-
 set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1")
 set(CMAKE_CXX_FLAGS_RELEASE
-    "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=${release_crash_reports} -DNDEBUG") 
+    "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DNDEBUG") 
 
 set(CMAKE_CXX_FLAGS_RELWITHDEBINFO 
-    "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1")
+    "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1")
 
+# Configure crash reporting
+set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds")
+set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds")
 
-# Don't bother with a MinSizeRel build.
+if(RELEASE_CRASH_REPORTING)
+  set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DLL_SEND_CRASH_REPORTS=1")
+endif()
+
+if(NON_RELEASE_CRASH_REPORTING)
+  set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLL_SEND_CRASH_REPORTS=1")
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1")
+endif()  
 
+# Don't bother with a MinSizeRel build.
 set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
     "Supported build types." FORCE)
 
diff --git a/indra/cmake/BerkeleyDB.cmake b/indra/cmake/BerkeleyDB.cmake
index d98e79179d9f6c635d69473438408926901ef0ca..e3ca0fd77d62c55e08165c53ace8e9564526cf64 100644
--- a/indra/cmake/BerkeleyDB.cmake
+++ b/indra/cmake/BerkeleyDB.cmake
@@ -6,6 +6,11 @@ set(DB_FIND_REQUIRED ON)
 if (STANDALONE)
   include(FindBerkeleyDB)
 else (STANDALONE)
-  set(DB_LIBRARIES db-4.2)
+  if (LINUX)
+    # Need to add dependency pthread explicitely to support ld.gold.
+    set(DB_LIBRARIES db-4.2 pthread)
+  else (LINUX)
+    set(DB_LIBRARIES db-4.2)
+  endif (LINUX)
   set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 endif (STANDALONE)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 6470836286135d173fe4287d1504bbe0817d5959..3f421b270b92507fc3295cf14a99000de2e9595c 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -33,6 +33,7 @@ set(cmake_SOURCE_FILES
     FindMySQL.cmake
     FindOpenJPEG.cmake
     FindXmlRpcEpi.cmake
+    FindZLIB.cmake
     FMOD.cmake
     FreeType.cmake
     GStreamer010Plugin.cmake
diff --git a/indra/cmake/FindJsonCpp.cmake b/indra/cmake/FindJsonCpp.cmake
index 9d16f2aaabcfbdb88e7763f16d0ef38deb8580c4..cf84b309c1f64617aeb916d46fc89a8dcb26a419 100644
--- a/indra/cmake/FindJsonCpp.cmake
+++ b/indra/cmake/FindJsonCpp.cmake
@@ -21,7 +21,12 @@ EXEC_PROGRAM(${CMAKE_CXX_COMPILER}
             OUTPUT_STRIP_TRAILING_WHITESPACE
             )
 
+# Try to find a library that was compiled with the same compiler version as we currently use.
 SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson_linux-gcc-${_gcc_COMPILER_VERSION}_libmt.so)
+IF (STANDALONE)
+	# On standalone, assume that the system installed library was compiled with the used compiler.
+	SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson.so)
+ENDIF (STANDALONE)
 FIND_LIBRARY(JSONCPP_LIBRARY
   NAMES ${JSONCPP_NAMES}
   PATHS /usr/lib /usr/local/lib
diff --git a/indra/cmake/FindLLQtWebkit.cmake b/indra/cmake/FindLLQtWebkit.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..c747ec32a2850957f45ccb5fe239b6f995cb611c
--- /dev/null
+++ b/indra/cmake/FindLLQtWebkit.cmake
@@ -0,0 +1,62 @@
+# -*- cmake -*-
+
+# - Find llqtwebkit
+# Find the llqtwebkit includes and library
+# This module defines
+#  LLQTWEBKIT_INCLUDE_DIR, where to find llqtwebkit.h, etc.
+#  LLQTWEBKIT_LIBRARY, the llqtwebkit library with full path.
+#  LLQTWEBKIT_FOUND, If false, do not try to use llqtwebkit.
+# also defined, but not for general use are
+#  LLQTWEBKIT_LIBRARIES, the libraries needed to use llqtwebkit.
+#  LLQTWEBKIT_LIBRARY_DIRS, where to find the llqtwebkit library.
+#  LLQTWEBKIT_DEFINITIONS - You should add_definitions(${LLQTWEBKIT_DEFINITIONS})
+#      before compiling code that includes llqtwebkit library files.
+
+# Try to use pkg-config first.
+# This allows to have two different libllqtwebkit packages installed:
+# one for viewer 2.x and one for viewer 1.x.
+include(FindPkgConfig)
+if (PKG_CONFIG_FOUND)
+    if (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION)
+        set(_PACKAGE_ARGS libllqtwebkit>=${LLQtWebkit_FIND_VERSION} REQUIRED)
+    else (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION)
+        set(_PACKAGE_ARGS libllqtwebkit)
+    endif (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION)
+    if (NOT "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS "2.8")
+      # As virtually nobody will have a pkg-config file for this, do this check always quiet.
+      # Unfortunately cmake 2.8 or higher is required for pkg_check_modules to have a 'QUIET'.
+      set(_PACKAGE_ARGS ${_PACKAGE_ARGS} QUIET)
+    endif ()
+    pkg_check_modules(LLQTWEBKIT ${_PACKAGE_ARGS})
+endif (PKG_CONFIG_FOUND)
+set(LLQTWEBKIT_DEFINITIONS ${LLQTWEBKIT_CFLAGS_OTHER})
+
+find_path(LLQTWEBKIT_INCLUDE_DIR llqtwebkit.h NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_INCLUDE_DIRS})
+
+find_library(LLQTWEBKIT_LIBRARY NAMES llqtwebkit NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_LIBRARY_DIRS})
+
+if (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND)	# If pkg-config couldn't find it, pretend we don't have pkg-config.
+   set(LLQTWEBKIT_LIBRARIES llqtwebkit)
+   get_filename_component(LLQTWEBKIT_LIBRARY_DIRS ${LLQTWEBKIT_LIBRARY} PATH)
+endif (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND)
+
+# Handle the QUIETLY and REQUIRED arguments and set LLQTWEBKIT_FOUND
+# to TRUE if all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+  LLQTWEBKIT
+  DEFAULT_MSG
+  LLQTWEBKIT_LIBRARY
+  LLQTWEBKIT_INCLUDE_DIR
+  LLQTWEBKIT_LIBRARIES
+  LLQTWEBKIT_LIBRARY_DIRS
+  )
+
+mark_as_advanced(
+  LLQTWEBKIT_LIBRARY
+  LLQTWEBKIT_INCLUDE_DIR
+  LLQTWEBKIT_LIBRARIES
+  LLQTWEBKIT_LIBRARY_DIRS
+  LLQTWEBKIT_DEFINITIONS
+  )
+
diff --git a/indra/cmake/FindNDOF.cmake b/indra/cmake/FindNDOF.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6dcf590a53d5f77cb6614752d8f78f0ef0336f30
--- /dev/null
+++ b/indra/cmake/FindNDOF.cmake
@@ -0,0 +1,39 @@
+# -*- cmake -*-
+
+# - Find NDOF
+# Find the NDOF includes and library
+# This module defines
+#  NDOF_INCLUDE_DIR, where to find ndofdev_external.h, etc.
+#  NDOF_LIBRARY, the library needed to use NDOF.
+#  NDOF_FOUND, If false, do not try to use NDOF.
+
+find_path(NDOF_INCLUDE_DIR ndofdev_external.h
+  PATH_SUFFIXES ndofdev
+  )
+
+set(NDOF_NAMES ${NDOF_NAMES} ndofdev libndofdev)
+find_library(NDOF_LIBRARY
+  NAMES ${NDOF_NAMES}
+  )
+
+if (NDOF_LIBRARY AND NDOF_INCLUDE_DIR)
+  set(NDOF_FOUND "YES")
+else (NDOF_LIBRARY AND NDOF_INCLUDE_DIR)
+  set(NDOF_FOUND "NO")
+endif (NDOF_LIBRARY AND NDOF_INCLUDE_DIR)
+
+
+if (NDOF_FOUND)
+  if (NOT NDOF_FIND_QUIETLY)
+    message(STATUS "Found NDOF: Library in '${NDOF_LIBRARY}' and header in '${NDOF_INCLUDE_DIR}' ")
+  endif (NOT NDOF_FIND_QUIETLY)
+else (NDOF_FOUND)
+  if (NDOF_FIND_REQUIRED)
+    message(FATAL_ERROR " * * *\nCould not find NDOF library!\nIf you don't need Space Navigator Joystick support you can skip this test by configuring with -DNDOF:BOOL=OFF\n * * *")
+  endif (NDOF_FIND_REQUIRED)
+endif (NDOF_FOUND)
+
+mark_as_advanced(
+  NDOF_LIBRARY
+  NDOF_INCLUDE_DIR
+  )
diff --git a/indra/cmake/FindTut.cmake b/indra/cmake/FindTut.cmake
index b5d58f6396e63c265eafda0d9d6df0c0e6c1906a..c2a9f430534aa1ee7e50ab87ed0bbe6b0cb241a2 100644
--- a/indra/cmake/FindTut.cmake
+++ b/indra/cmake/FindTut.cmake
@@ -3,12 +3,11 @@
 # - Find Tut
 # Find the Tut unit test framework includes and library
 # This module defines
-#  TUT_INCLUDE_DIR, where to find tut.h, etc.
+#  TUT_INCLUDE_DIR, where to find tut/tut.hpp.
 #  TUT_FOUND, If false, do not try to use Tut.
 
-find_path(TUT_INCLUDE_DIR tut.h
-    /usr/local/include/
-    /usr/include
+find_path(TUT_INCLUDE_DIR tut/tut.hpp
+    NO_SYSTEM_ENVIRONMENT_PATH
     )
 
 if (TUT_INCLUDE_DIR)
diff --git a/indra/cmake/FindZLIB.cmake b/indra/cmake/FindZLIB.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6d630f1ba967e4d418965730b3032d4290f5c842
--- /dev/null
+++ b/indra/cmake/FindZLIB.cmake
@@ -0,0 +1,46 @@
+# -*- cmake -*-
+
+# - Find zlib
+# Find the ZLIB includes and library
+# This module defines
+#  ZLIB_INCLUDE_DIRS, where to find zlib.h, etc.
+#  ZLIB_LIBRARIES, the libraries needed to use zlib.
+#  ZLIB_FOUND, If false, do not try to use zlib.
+#
+# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x),
+# because it doesn't look up the version of zlib, resulting in a dramatic
+# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
+#
+# Note: Since this file is only used for standalone, the windows
+# specific parts were left out.
+
+FIND_PATH(ZLIB_INCLUDE_DIR zlib.h
+  NO_SYSTEM_ENVIRONMENT_PATH
+  )
+
+FIND_LIBRARY(ZLIB_LIBRARY z)
+
+if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+  SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
+  SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY})
+  SET(ZLIB_FOUND "YES")
+else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+  SET(ZLIB_FOUND "NO")
+endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+
+if (ZLIB_FOUND)
+  if (NOT ZLIB_FIND_QUIETLY)
+	message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}")
+	SET(ZLIB_FIND_QUIETLY TRUE)
+  endif (NOT ZLIB_FIND_QUIETLY)
+else (ZLIB_FOUND)
+  if (ZLIB_FIND_REQUIRED)
+	message(FATAL_ERROR "Could not find ZLIB library")
+  endif (ZLIB_FIND_REQUIRED)
+endif (ZLIB_FOUND)
+
+mark_as_advanced(
+  ZLIB_LIBRARY
+  ZLIB_INCLUDE_DIR
+  )
+
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 29e2492551cfd3f0b81c8708d860da14416ccf0c..62b764bb307debcee404eb7bc355f8b361cabadb 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -205,6 +205,9 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
   endif(TEST_DEBUG)
   ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})
   SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
+  if(STANDALONE)
+    SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
+  endif(STANDALONE)
 
   # Add link deps to the executable
   if(TEST_DEBUG)
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index d1ab264a413b8a3eaf263ea3bbef32e59ac42e9c..17e211cb9937eb8e5544423e1c3ddb03a675fabc 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -13,7 +13,14 @@ set(LLCOMMON_INCLUDE_DIRS
     ${Boost_INCLUDE_DIRS}
     )
 
-set(LLCOMMON_LIBRARIES llcommon)
+if (LINUX)
+    # In order to support using ld.gold on linux, we need to explicitely
+    # specify all libraries that llcommon uses.
+    # llcommon uses `clock_gettime' which is provided by librt on linux.
+    set(LLCOMMON_LIBRARIES llcommon rt)
+else (LINUX)
+    set(LLCOMMON_LIBRARIES llcommon)
+endif (LINUX)
 
 add_definitions(${TCMALLOC_FLAG})
 
diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake
index 9722f16c3c31ebc09fac22b4f5bda01c0ae312c1..7ee404b9bdfa68fc6d398c48a2549b4449fc84d9 100644
--- a/indra/cmake/LLPlugin.cmake
+++ b/indra/cmake/LLPlugin.cmake
@@ -5,4 +5,10 @@ set(LLPLUGIN_INCLUDE_DIRS
     ${LIBS_OPEN_DIR}/llplugin
     )
 
-set(LLPLUGIN_LIBRARIES llplugin)
+if (LINUX)
+    # In order to support using ld.gold on linux, we need to explicitely
+    # specify all libraries that llplugin uses.
+	set(LLPLUGIN_LIBRARIES llplugin pthread)
+else (LINUX)
+	set(LLPLUGIN_LIBRARIES llplugin)
+endif (LINUX)
diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake
index dad74e99b1bb7c8a4d79022938cb6df2d0ecb2bf..7a463d11907d9596e24ae1d2527a611459b4958d 100644
--- a/indra/cmake/NDOF.cmake
+++ b/indra/cmake/NDOF.cmake
@@ -1,14 +1,32 @@
 # -*- cmake -*-
 include(Prebuilt)
 
-use_prebuilt_binary(ndofdev)
+set(NDOF ON CACHE BOOL "Use NDOF space navigator joystick library.")
 
-if (WINDOWS OR DARWIN OR LINUX)
+if (NDOF)
+  if (STANDALONE)
+	set(NDOF_FIND_REQUIRED ON)
+	include(FindNDOF)
+  else (STANDALONE)
+	use_prebuilt_binary(ndofdev)
+
+	if (WINDOWS)
+	  set(NDOF_LIBRARY libndofdev)
+	elseif (DARWIN OR LINUX)
+	  set(NDOF_LIBRARY ndofdev)
+	endif (WINDOWS)
+
+	set(NDOF_INCLUDE_DIR ${ARCH_PREBUILT_DIRS}/include/ndofdev)
+	set(NDOF_FOUND 1)
+  endif (STANDALONE)
+endif (NDOF)
+
+if (NDOF_FOUND)
   add_definitions(-DLIB_NDOF=1)
-endif (WINDOWS OR DARWIN OR LINUX)
+  include_directories(${NDOF_INCLUDE_DIR})
+else (NDOF_FOUND)
+  message(STATUS "Building without N-DoF joystick support")
+  set(NDOF_INCLUDE_DIR "")
+  set(NDOF_LIBRARY "")
+endif (NDOF_FOUND)
 
-if (WINDOWS)
-  set(NDOF_LIBRARY libndofdev)
-elseif (DARWIN OR LINUX)
-  set(NDOF_LIBRARY ndofdev)
-endif (WINDOWS)
diff --git a/indra/cmake/Tut.cmake b/indra/cmake/Tut.cmake
index 784560471d503492a7daf43bfdaaba166de58bec..738c08c42fe6c10e3c82d0e48994d095e9744271 100644
--- a/indra/cmake/Tut.cmake
+++ b/indra/cmake/Tut.cmake
@@ -6,7 +6,6 @@ set(TUT_FIND_QUIETLY TRUE)
 
 if (STANDALONE)
   include(FindTut)
-  include_directories(${TUT_INCLUDE_DIR})
 else (STANDALONE)
   use_prebuilt_binary(tut)
 endif (STANDALONE)
diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake
index 12ba1b1b35b8f95f43f194c7fb3a35a0d12fb64f..1f5b0f5d84b65d8dd2bd937cc8f7bec1c4ef5a50 100644
--- a/indra/cmake/WebKitLibPlugin.cmake
+++ b/indra/cmake/WebKitLibPlugin.cmake
@@ -3,6 +3,29 @@ include(Linking)
 include(Prebuilt)
 
 if (STANDALONE)
+  # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny.
+  find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED)
+  include(${QT_USE_FILE})
+  set(QTDIR $ENV{QTDIR})
+  if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
+	message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; "
+	  "Qt is found by looking for qmake in your PATH. "
+	  "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, "
+	  "or unset QTDIR if the found Qt is correct.")
+	endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
+  find_package(LLQtWebkit REQUIRED QUIET)
+  # Add the plugins.
+  set(QT_PLUGIN_LIBRARIES)
+  foreach(qlibname qgif qjpeg)
+	find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH)
+	if (QT_PLUGIN_${qlibname})
+	  list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}})
+	else (QT_PLUGIN_${qtlibname})
+	  message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!")
+	endif (QT_PLUGIN_${qlibname})
+  endforeach(qlibname)
+  # qjpeg depends on libjpeg
+  list(APPEND QT_PLUGIN_LIBRARIES jpeg)
   set(WEBKITLIBPLUGIN OFF CACHE BOOL
       "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
 else (STANDALONE)
@@ -35,7 +58,7 @@ elseif (DARWIN)
       )
 elseif (LINUX)
   if (STANDALONE) 
-    set(WEBKIT_PLUGIN_LIBRARIES llqtwebkit)
+    set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES})
   else (STANDALONE)
     set(WEBKIT_PLUGIN_LIBRARIES
         llqtwebkit
diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py
index 786521c06805d6533afb378ee76bb57360cc9c85..da8ee6c545741a56a43d849f0f68420b4f3d2df9 100644
--- a/indra/lib/python/indra/util/test_win32_manifest.py
+++ b/indra/lib/python/indra/util/test_win32_manifest.py
@@ -52,20 +52,22 @@ def get_HKLM_registry_value(key_str, value_str):
         
 def find_vc_dir():
     supported_versions = (r'8.0', r'9.0')
+    supported_products = (r'VisualStudio', r'VCExpress')
     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)
+    for product in supported_products:
+        for version in supported_versions:
+            key_str = (r'SOFTWARE\Microsoft\%s\%s\Setup\VC' %
+                      (product, version))
             try:
-                return get_HKLM_registry_value(x64_key_str, value_str)
-            except:
-                print >> sys.stderr, "Didn't find MS VC version %s " % version
+                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 %s version %s " % (product,version)
         
     raise
 
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 66ec5bad2c55291b1d798811da15e454c3120b95..d1c44c94032851a19a4ab42f20006ce04a1eb1f4 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -28,6 +28,7 @@
 
 #include "linden_common.h"
 #include "llapr.h"
+#include "apr_dso.h"
 
 apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
 LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
@@ -279,14 +280,31 @@ bool ll_apr_warn_status(apr_status_t status)
 {
 	if(APR_SUCCESS == status) return false;
 	char buf[MAX_STRING];	/* Flawfinder: ignore */
-	apr_strerror(status, buf, MAX_STRING);
+	apr_strerror(status, buf, sizeof(buf));
 	LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
 	return true;
 }
 
+bool ll_apr_warn_status(apr_status_t status, apr_dso_handle_t *handle)
+{
+    bool result = ll_apr_warn_status(status);
+    // Despite observed truncation of actual Mac dylib load errors, increasing
+    // this buffer to more than MAX_STRING doesn't help: it appears that APR
+    // stores the output in a fixed 255-character internal buffer. (*sigh*)
+    char buf[MAX_STRING];           /* Flawfinder: ignore */
+    apr_dso_error(handle, buf, sizeof(buf));
+    LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
+    return result;
+}
+
 void ll_apr_assert_status(apr_status_t status)
 {
-	llassert(ll_apr_warn_status(status) == false);
+	llassert(! ll_apr_warn_status(status));
+}
+
+void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle)
+{
+    llassert(! ll_apr_warn_status(status, handle));
 }
 
 //---------------------------------------------------------------------
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 4930270af81c843ef24420d499e774989e09630b..af33ce666f1558193d3d2818cf0c3a5e98d6ee7a 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -53,6 +53,8 @@
 extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
 extern apr_thread_mutex_t* gCallStacksLogMutexp;
 
+struct apr_dso_handle_t;
+
 /** 
  * @brief initialize the common apr constructs -- apr itself, the
  * global pool, and a mutex.
@@ -259,8 +261,11 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
  * @return Returns <code>true</code> if status is an error condition.
  */
 bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
+/// There's a whole other APR error-message function if you pass a DSO handle.
+bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle);
 
 void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
+void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
 
 extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
 
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index 84a6620a77782b82cb764b0d1691ee9a52919bd9..97e2bdeb5754288521d26fe379b987f19312a2d0 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -475,7 +475,7 @@ void LLEventPump::stopListening(const std::string& name)
 *****************************************************************************/
 bool LLEventStream::post(const LLSD& event)
 {
-    if (! mEnabled)
+    if (! mEnabled || !mSignal)
     {
         return false;
     }
@@ -515,6 +515,8 @@ bool LLEventQueue::post(const LLSD& event)
 
 void LLEventQueue::flush()
 {
+	if(!mSignal) return;
+		
     // Consider the case when a given listener on this LLEventQueue posts yet
     // another event on the same queue. If we loop over mEventQueue directly,
     // we'll end up processing all those events during the same flush() call
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index 6834267d4b13550cefd1ef7c7fe535bb7a99b2b1..ea8c1a1107eef6c7f3b2be9cdbad5dce5d45c54c 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -3,12 +3,13 @@
 project(llimage)
 
 include(00-Common)
-include(LLAddBuildTest)
 include(LLCommon)
 include(LLImage)
 include(LLMath)
 include(LLVFS)
 include(ZLIB)
+include(LLAddBuildTest)
+include(Tut)
 
 include_directories(
     ${LLCOMMON_INCLUDE_DIRS}
@@ -63,4 +64,12 @@ target_link_libraries(llimage
     )
 
 # Add tests
-#ADD_BUILD_TEST(llimageworker llimage)
+if (LL_TESTS)
+  SET(llimage_TEST_SOURCE_FILES
+    llimageworker.cpp
+    )
+  LL_ADD_PROJECT_UNIT_TESTS(llimage "${llimage_TEST_SOURCE_FILES}")
+endif (LL_TESTS)
+
+
+
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
index a1092767092e86d1f46b81969dc59c80474af6f0..08476fb72cce4c4143d2805b7ed2c10d1f05007c 100644
--- a/indra/llimage/tests/llimageworker_test.cpp
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -26,10 +26,8 @@
  */
 
 // Precompiled header: almost always required for newview cpp files
-#include <list>
-#include <map>
-#include <algorithm>
-// Class to test
+#include "linden_common.h"
+// Class to test 
 #include "../llimageworker.h"
 // For timer class
 #include "../llcommon/lltimer.h"
@@ -44,7 +42,17 @@
 // * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
 // * A simulator for a class can be implemented here. Please comment and document thoroughly.
 
-LLImageBase::LLImageBase() {}
+LLImageBase::LLImageBase() 
+: mData(NULL),
+mDataSize(0),
+mWidth(0),
+mHeight(0),
+mComponents(0),
+mBadBufferAllocation(false),
+mAllowOverSize(false),
+mMemType(LLMemType::MTYPE_IMAGEBASE)
+{
+}
 LLImageBase::~LLImageBase() {}
 void LLImageBase::dump() { }
 void LLImageBase::sanityCheck() { }
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index 95e0997d5b40c343b188c59e36279731d9b5e96c..13b12c0928c27d4a542e40c90bd15edaabc5eaa9 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -90,6 +90,12 @@ void info_callback(const char* msg, void*)
 	lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl;
 }
 
+// Divide a by 2 to the power of b and round upwards
+int ceildivpow2(int a, int b)
+{
+	return (a + (1 << b) - 1) >> b;
+}
+
 
 LLImageJ2COJ::LLImageJ2COJ()
 	: LLImageJ2CImpl()
diff --git a/indra/llimagej2coj/llimagej2coj.h b/indra/llimagej2coj/llimagej2coj.h
index 7edacbe97c94563713219e12aa152ddbfbe90024..9476665ccbb57ed034ee4d4e594775f4539dc8f2 100644
--- a/indra/llimagej2coj/llimagej2coj.h
+++ b/indra/llimagej2coj/llimagej2coj.h
@@ -34,17 +34,11 @@ class LLImageJ2COJ : public LLImageJ2CImpl
 public:
 	LLImageJ2COJ();
 	virtual ~LLImageJ2COJ();
-
 protected:
 	/*virtual*/ BOOL getMetadata(LLImageJ2C &base);
 	/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
 	/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
 								BOOL reversible = FALSE);
-	int ceildivpow2(int a, int b)
-	{
-		// Divide a by b to the power of 2 and round upwards.
-		return (a + (1 << b) - 1) >> b;
-	}
 };
 
 #endif
diff --git a/indra/llkdu/CMakeLists.txt b/indra/llkdu/CMakeLists.txt
index b8b44b44fcadf27deee20120d75b858d30afe1ae..7ed1c6c694a23bb13d0fb643ef41445fe043b5af 100644
--- a/indra/llkdu/CMakeLists.txt
+++ b/indra/llkdu/CMakeLists.txt
@@ -42,4 +42,14 @@ list(APPEND llkdu_SOURCE_FILES ${llkdu_HEADER_FILES})
 if (USE_KDU)
   add_library (${LLKDU_LIBRARIES} ${llkdu_SOURCE_FILES})
   
+  # Add tests
+  if (LL_TESTS)
+    include(LLAddBuildTest)
+    include(Tut)
+    SET(llkdu_TEST_SOURCE_FILES
+      llimagej2ckdu.cpp
+      )
+    LL_ADD_PROJECT_UNIT_TESTS(llkdu "${llkdu_TEST_SOURCE_FILES}")
+  endif (LL_TESTS)
+
 endif (USE_KDU)
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 1a286d14066057683b9c7bf4bd7ba46138040f6d..10ea5685e86ca797d26da2a5a8f4767c7f933576 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -229,16 +229,17 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECod
 		mCodeStreamp = NULL;
 	}
 
-	if (!mInputp)
+	if (!mInputp && base.getData())
 	{
-		llassert(base.getData());
 		// The compressed data has been loaded
-		// Setup the source for the codestrea
+		// Setup the source for the codestream
 		mInputp = new LLKDUMemSource(base.getData(), data_size);
 	}
 
-	llassert(mInputp);
-	mInputp->reset();
+	if (mInputp)
+	{
+		mInputp->reset();
+	}
 	mCodeStreamp = new kdu_codestream;
 
 	mCodeStreamp->create(mInputp);
@@ -1017,7 +1018,7 @@ kdc_flow_control::kdc_flow_control (kdu_image_in_base *img_in, kdu_codestream co
         comp->ratio_counter = 0;
         comp->remaining_lines = comp->initial_lines = dims.size.y;
     }
-    assert(num_components > 0);
+    assert(num_components >= 0);
     
     tile.set_components_of_interest(num_components);
     max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
index 03f289f8b177849b91d6e687133ca12f50b2bebc..5628f69eeb6b44796af332978547f31bce0d2493 100644
--- a/indra/llkdu/llimagej2ckdu.h
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -50,17 +50,16 @@ class LLImageJ2CKDU : public LLImageJ2CImpl
 		MODE_RESILIENT = 1,
 		MODE_FUSSY = 2
 	};
-	
-public:
 	LLImageJ2CKDU();
 	virtual ~LLImageJ2CKDU();
-
+	
 protected:
 	/*virtual*/ BOOL getMetadata(LLImageJ2C &base);
 	/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
 	/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
 								BOOL reversible=FALSE);
 
+private:
 	void setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode);
 	void cleanupCodeStream();
 	BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ccee4bb647445c17babb176106096135abee1a4
--- /dev/null
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -0,0 +1,248 @@
+/** 
+ * @file llimagej2ckdu_test.cpp
+ * @author Merov Linden
+ * @date 2010-12-17
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+// Class to test 
+#include "../llimagej2ckdu.h"
+#include "../llkdumem.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes: 
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+// Stubb the LL Image Classes
+LLImageRaw::LLImageRaw() { }
+LLImageRaw::~LLImageRaw() { }
+U8* LLImageRaw::allocateData(S32 ) { return NULL; }
+void LLImageRaw::deleteData() { }
+U8* LLImageRaw::reallocateData(S32 ) { return NULL; }
+BOOL LLImageRaw::resize(U16, U16, S8) { return TRUE; } // this method always returns TRUE...
+
+LLImageBase::LLImageBase()
+: mData(NULL),
+mDataSize(0),
+mWidth(0),
+mHeight(0),
+mComponents(0),
+mBadBufferAllocation(false),
+mAllowOverSize(false),
+mMemType(LLMemType::MTYPE_IMAGEBASE)
+{ }
+LLImageBase::~LLImageBase() { }
+U8* LLImageBase::allocateData(S32 ) { return NULL; }
+void LLImageBase::deleteData() { }
+void LLImageBase::dump() { }
+const U8* LLImageBase::getData() const { return NULL; }
+U8* LLImageBase::getData() { return NULL; }
+U8* LLImageBase::reallocateData(S32 ) { return NULL; }
+void LLImageBase::sanityCheck() { }
+void LLImageBase::setSize(S32 , S32 , S32 ) { }
+
+LLImageJ2CImpl::~LLImageJ2CImpl() { }
+
+LLImageFormatted::LLImageFormatted(S8 ) { }
+LLImageFormatted::~LLImageFormatted() { }
+U8* LLImageFormatted::allocateData(S32 ) { return NULL; }
+S32 LLImageFormatted::calcDataSize(S32 ) { return 0; }
+S32 LLImageFormatted::calcDiscardLevelBytes(S32 ) { return 0; }
+BOOL LLImageFormatted::decodeChannels(LLImageRaw*, F32, S32, S32) { return FALSE; }
+BOOL LLImageFormatted::copyData(U8 *, S32) { return TRUE; }  // this method always returns TRUE...
+void LLImageFormatted::deleteData() { }
+void LLImageFormatted::dump() { }
+U8* LLImageFormatted::reallocateData(S32 ) { return NULL; }
+void LLImageFormatted::resetLastError() { }
+void LLImageFormatted::sanityCheck() { }
+void LLImageFormatted::setLastError(const std::string& , const std::string& ) { }
+
+LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C) { }
+LLImageJ2C::~LLImageJ2C() { }
+S32 LLImageJ2C::calcDataSize(S32 ) { return 0; }
+S32 LLImageJ2C::calcDiscardLevelBytes(S32 ) { return 0; }
+S32 LLImageJ2C::calcHeaderSize() { return 0; }
+BOOL LLImageJ2C::decode(LLImageRaw*, F32) { return FALSE; }
+BOOL LLImageJ2C::decodeChannels(LLImageRaw*, F32, S32, S32 ) { return FALSE; }
+void LLImageJ2C::decodeFailed() { }
+BOOL LLImageJ2C::encode(const LLImageRaw*, F32) { return FALSE; }
+S8  LLImageJ2C::getRawDiscardLevel() { return 0; }
+void LLImageJ2C::resetLastError() { }
+void LLImageJ2C::setLastError(const std::string&, const std::string&) { }
+BOOL LLImageJ2C::updateData() { return FALSE; }
+void LLImageJ2C::updateRawDiscardLevel() { }
+
+LLKDUMemIn::LLKDUMemIn(const U8*, const U32, const U16, const U16, const U8, siz_params*) { }
+LLKDUMemIn::~LLKDUMemIn() { }
+bool LLKDUMemIn::get(int, kdu_line_buf&, int) { return false; }
+
+// Stub Kakadu Library calls
+kdu_tile_comp kdu_tile::access_component(int ) { kdu_tile_comp a; return a; }
+void kdu_tile::close(kdu_thread_env* ) { }
+int kdu_tile::get_num_components() { return 0; }
+bool kdu_tile::get_ycc() { return false; }
+void kdu_tile::set_components_of_interest(int , const int* ) { }
+kdu_resolution kdu_tile_comp::access_resolution() { kdu_resolution a; return a; }
+int kdu_tile_comp::get_bit_depth(bool ) { return 8; }
+bool kdu_tile_comp::get_reversible() { return false; }
+kdu_subband kdu_resolution::access_subband(int ) { kdu_subband a; return a; }
+void kdu_resolution::get_dims(kdu_dims& ) { }
+int kdu_resolution::which() { return 0; }
+kdu_decoder::kdu_decoder(kdu_subband , kdu_sample_allocator*, bool , float, int, kdu_thread_env*, kdu_thread_queue*) { }
+kdu_synthesis::kdu_synthesis(kdu_resolution, kdu_sample_allocator*, bool, float, kdu_thread_env*, kdu_thread_queue*) { }
+kdu_params::kdu_params(const char*, bool, bool, bool, bool, bool) { }
+kdu_params::~kdu_params() { }
+void kdu_params::set(const char* , int , int , bool ) { }
+void kdu_params::set(const char* , int , int , int ) { }
+void kdu_params::finalize_all(bool ) { }
+void kdu_params::copy_from(kdu_params*, int, int, int, int, int, bool, bool, bool) { }
+bool kdu_params::parse_string(const char*) { return false; }
+bool kdu_params::get(const char*, int, int, bool&, bool, bool, bool) { return false; }
+bool kdu_params::get(const char*, int, int, float&, bool, bool, bool) { return false; }
+bool kdu_params::get(const char*, int, int, int&, bool, bool, bool) { return false; }
+kdu_params* kdu_params::access_relation(int, int, int, bool) { return NULL; }
+kdu_params* kdu_params::access_cluster(const char*) { return NULL; }
+void kdu_codestream::set_fast() { }
+void kdu_codestream::set_fussy() { }
+void kdu_codestream::get_dims(int, kdu_dims&, bool ) { }
+void kdu_codestream::change_appearance(bool, bool, bool) { }
+void kdu_codestream::get_tile_dims(kdu_coords, int, kdu_dims&, bool ) { }
+void kdu_codestream::destroy() { }
+void kdu_codestream::collect_timing_stats(int ) { }
+void kdu_codestream::set_max_bytes(kdu_long, bool, bool ) { }
+void kdu_codestream::get_valid_tiles(kdu_dims& ) { }
+void kdu_codestream::create(siz_params*, kdu_compressed_target*, kdu_dims*, int, kdu_long ) { }
+void kdu_codestream::create(kdu_compressed_source*, kdu_thread_env*) { }
+void kdu_codestream::apply_input_restrictions( int, int, int, int, kdu_dims*, kdu_component_access_mode ) { }
+void kdu_codestream::get_subsampling(int , kdu_coords&, bool ) { }
+void kdu_codestream::flush(kdu_long *, int , kdu_uint16 *, bool, bool, double, kdu_thread_env*) { }
+void kdu_codestream::set_resilient(bool ) { }
+int kdu_codestream::get_num_components(bool ) { return 0; }
+siz_params* kdu_codestream::access_siz() { return NULL; }
+kdu_tile kdu_codestream::open_tile(kdu_coords , kdu_thread_env* ) { kdu_tile a; return a; }
+kdu_codestream_comment kdu_codestream::add_comment() { kdu_codestream_comment a; return a; }
+bool kdu_codestream_comment::put_text(const char*) { return false; }
+void kdu_customize_warnings(kdu_message*) { }
+void kdu_customize_errors(kdu_message*) { }
+void kdu_convert_ycc_to_rgb(kdu_line_buf&, kdu_line_buf&, kdu_line_buf&, int) { }
+kdu_long kdu_multi_analysis::create(kdu_codestream, kdu_tile, bool, kdu_roi_image*, bool, int, kdu_thread_env*, kdu_thread_queue*, bool ) { kdu_long a = 0; return a; }
+siz_params::siz_params() : kdu_params(NULL, false, false, false, false, false) { }
+void siz_params::finalize(bool ) { }
+void siz_params::copy_with_xforms(kdu_params*, int, int, bool, bool, bool) { }
+int siz_params::write_marker_segment(kdu_output*, kdu_params*, int) { return 0; }
+bool siz_params::check_marker_segment(kdu_uint16, int, kdu_byte a[], int&) { return false; }
+bool siz_params::read_marker_segment(kdu_uint16, int, kdu_byte a[], int) { return false; }
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+	// Test wrapper declarations
+	struct llimagej2ckdu_test
+	{
+		// Derived test class
+		class LLTestImageJ2CKDU : public LLImageJ2CKDU
+		{
+		public:
+			// Provides public access to some protected methods for testing
+			BOOL callGetMetadata(LLImageJ2C &base) { return getMetadata(base); }
+			BOOL callDecodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+			{
+				return decodeImpl(base, raw_image, decode_time, first_channel, max_channel_count);
+			}
+			BOOL callEncodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text)
+			{
+				return encodeImpl(base, raw_image, comment_text);
+			}
+		};
+		// Instance to be tested
+		LLTestImageJ2CKDU* mImage;
+		
+		// Constructor and destructor of the test wrapper
+		llimagej2ckdu_test()
+		{
+			mImage = new LLTestImageJ2CKDU;
+		}
+		~llimagej2ckdu_test()
+		{
+			delete mImage;
+		}
+	};
+	
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<llimagej2ckdu_test> llimagej2ckdu_t;
+	typedef llimagej2ckdu_t::object llimagej2ckdu_object_t;
+	tut::llimagej2ckdu_t tut_llimagej2ckdu("LLImageJ2CKDU");
+	
+	// ---------------------------------------------------------------------------------------
+	// Test functions
+	// Notes:
+	// * Test as many as you possibly can without requiring a full blown simulation of everything
+	// * The tests are executed in sequence so the test instance state may change between calls
+	// * Remember that you cannot test private methods with tut
+	// ---------------------------------------------------------------------------------------
+
+	// Test 1 : test getMetadata()
+	template<> template<>
+	void llimagej2ckdu_object_t::test<1>()
+	{
+		LLImageJ2C* image = new LLImageJ2C();
+		BOOL res = mImage->callGetMetadata(*image);
+		// Trying to set up a data stream with all NIL values and stubbed KDU will "work" and return TRUE
+		// Note that is linking with KDU, that call will throw an exception and fail, returning FALSE
+		ensure("getMetadata() test failed", res == TRUE);
+	}
+
+	// Test 2 : test decodeImpl()
+	template<> template<>
+	void llimagej2ckdu_object_t::test<2>()
+	{
+		LLImageJ2C* image = new LLImageJ2C();
+		LLImageRaw* raw = new LLImageRaw();
+		BOOL res = mImage->callDecodeImpl(*image, *raw, 0.0, 0, 0);
+		// Decoding returns TRUE whenever there's nothing else to do, including if decoding failed, so we'll get TRUE here
+		ensure("decodeImpl() test failed", res == TRUE);
+	}
+
+	// Test 3 : test encodeImpl()
+	template<> template<>
+	void llimagej2ckdu_object_t::test<3>()
+	{
+		LLImageJ2C* image = new LLImageJ2C();
+		LLImageRaw* raw = new LLImageRaw();
+		BOOL res = mImage->callEncodeImpl(*image, *raw, NULL);
+		// Encoding returns TRUE unless an exception was raised, so we'll get TRUE here though nothing really was done
+		ensure("encodeImpl() test failed", res == TRUE);
+	}
+}
diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt
index d3a73058c4a7a6fbe0b87eabcfe263a65ef53468..1dc05e0b20ba95a29fd4377f610a763f9eefa67f 100644
--- a/indra/llplugin/CMakeLists.txt
+++ b/indra/llplugin/CMakeLists.txt
@@ -20,6 +20,7 @@ include_directories(
     ${LLRENDER_INCLUDE_DIRS}
     ${LLXML_INCLUDE_DIRS}
     ${LLWINDOW_INCLUDE_DIRS}
+    ${LLQTWEBKIT_INCLUDE_DIR}
     )
 
 set(llplugin_SOURCE_FILES
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 1265733bf5be3213a10d11280e6e5bf00e3db7ca..d30697e1784487c2f9694dae189b3d3ac9e11bf3 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2910,7 +2910,9 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
 	params.from_xui = true;
 	applyXUILayout(params, parent);
  	initFromParams(params);
-	
+	// chrome floaters don't take focus at all
+	setFocusRoot(!getIsChrome());
+
 	initFloater(params);
 	
 	LLMultiFloater* last_host = LLFloater::getFloaterHost();
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index bf3233f3862635f5872d7b12ba30b6bd45bc2362..4d2677fd91f062a2ea049ceefe7f22bb43c2ba45 100644
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -59,12 +59,13 @@ set(viewer_HEADER_FILES
 
 # Libraries on which this library depends, needed for Linux builds
 # Sort by high-level to low-level
-if (NOT LINUX OR VIEWER)
+if (LINUX AND VIEWER)
   set(llwindow_LINK_LIBRARIES
       ${UI_LIBRARIES}     # for GTK
       ${SDL_LIBRARY}
+      fontconfig          # For FCInit and other FC* functions.
       )
-endif (NOT LINUX OR VIEWER)
+endif (LINUX AND VIEWER)
 
 if (DARWIN)
   list(APPEND llwindow_SOURCE_FILES
diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt
index 05f12366066ccd8881b75291ca412f2ee24065fe..3b1f6795401cd2a35558e492a07688d470e3ea3a 100644
--- a/indra/media_plugins/webkit/CMakeLists.txt
+++ b/indra/media_plugins/webkit/CMakeLists.txt
@@ -27,6 +27,7 @@ include_directories(
     ${LLIMAGE_INCLUDE_DIRS}
     ${LLRENDER_INCLUDE_DIRS}
     ${LLWINDOW_INCLUDE_DIRS}
+    ${LLQTWEBKIT_INCLUDE_DIR}
 )
 
 
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1db532787aed51e5b55ead9c39465891c1b5263c..a61c35abd2046eaecbe2b2e7da7a5b88c0c9fdec 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1854,6 +1854,7 @@ if (PACKAGE)
     set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
   endif (LINUX)
 
+  if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
   if(CMAKE_CFG_INTDIR STREQUAL ".")
       set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
   else(CMAKE_CFG_INTDIR STREQUAL ".")
@@ -1872,11 +1873,12 @@ if (PACKAGE)
       "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms"
       "${VIEWER_SYMBOL_FILE}"
     DEPENDS generate_breakpad_symbols.py
-    VERBATIM
-  )
+        VERBATIM)
+
   add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}")
   add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}")
   add_dependencies(package generate_breakpad_symbols)
+  endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
 endif (PACKAGE)
 
 if (LL_TESTS)
@@ -1891,6 +1893,8 @@ if (LL_TESTS)
     llremoteparcelrequest.cpp
     llviewerhelputil.cpp
     llversioninfo.cpp
+    llworldmap.cpp
+    llworldmipmap.cpp
   )
 
   ##################################################
@@ -1978,8 +1982,6 @@ if (LL_TESTS)
 
   #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
   #ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
-  #ADD_VIEWER_BUILD_TEST(llworldmap viewer)
-  #ADD_VIEWER_BUILD_TEST(llworldmipmap viewer)
   #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
   #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
   #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 431331bc0f457e4427413c697ebbfb42577e7874..ef6f8fd3eee14dea0001feeae55a175a1cce4a35 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2612,7 +2612,7 @@
       <key>Value</key>
       <string>http://www.secondlife.com</string>
     </map>
-    <key>DisableCameraConstraints</key>
+  <key>DisableCameraConstraints</key>
     <map>
       <key>Comment</key>
       <string>Disable the normal bounds put on the camera by avatar position</string>
@@ -3950,7 +3950,7 @@
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
-      <string>Boolean</string>  
+      <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
     </map>
@@ -4791,6 +4791,17 @@
       <key>Value</key>
       <string>http://map.secondlife.com.s3.amazonaws.com/</string>
     </map>
+    <key>CurrentMapServerURL</key>
+    <map>
+      <key>Comment</key>
+      <string>Current Session World map URL</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string></string>
+    </map>
     <key>MapShowEvents</key>
     <map>
       <key>Comment</key>
@@ -10035,6 +10046,17 @@
       <key>Value</key>
       <real>500.0</real>
     </map>
+    <key>UpdaterMaximumBandwidth</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum allowable downstream bandwidth for updater service (kilo bits per second)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>500.0</real>
+    </map>
     <key>ToolTipDelay</key>
     <map>
       <key>Comment</key>
@@ -11135,16 +11157,16 @@
       <key>Value</key>
       <integer>15</integer>
     </map>
-    <key>UpdaterServiceActive</key>
+    <key>UpdaterServiceSetting</key>
     <map>
       <key>Comment</key>
-      <string>Enable or disable the updater service.</string>
+      <string>Configure updater service.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
-      <string>Boolean</string>
+      <string>U32</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>3</integer>
     </map>
     <key>UpdaterServiceCheckPeriod</key>
     <map>
@@ -12423,5 +12445,16 @@
       <key>Value</key>
       <string>name</string>
     </map>
+    <key>ReleaseNotesURL</key>
+    <map>
+      <key>Comment</key>
+      <string>Release notes URL template</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string>http://secondlife.com/app/releasenotes/?channel=[CHANNEL]&amp;version=[VERSION]</string>
+    </map>
 </map>
 </llsd>
diff --git a/indra/newview/app_settings/shaders/shader_heirarchy.txt b/indra/newview/app_settings/shaders/shader_hierarchy.txt
similarity index 100%
rename from indra/newview/app_settings/shaders/shader_heirarchy.txt
rename to indra/newview/app_settings/shaders/shader_hierarchy.txt
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index a95abd7dd185e55e8992b612dfbb20f393d61788..a82c3da4c568abf85d2f27034668ec0b7dc050d5 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -135,7 +135,7 @@ RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
 RenderMaxPartCount			1	4096
 RenderObjectBump			1	1
-RenderReflectionDetail		1	2
+RenderReflectionDetail		1	0
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTransparentWater		1	1
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index a52b32355de22ba0efbafb2451686a9cf8fdf8d4..a2cd4b834c0845ed899f975c40d3ebfa5a96aa30 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -134,7 +134,7 @@ RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
 RenderMaxPartCount			1	4096
 RenderObjectBump			1	1
-RenderReflectionDetail		1	2
+RenderReflectionDetail		1	0
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTransparentWater		1	1
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 6dabef53a846a54d69de2f6f83ed623c531c3e65..3ad7f4e89275cfbcb44fd5bc742ee296503e8376 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -133,7 +133,7 @@ RenderGlowResolutionPow		1	9
 RenderLightingDetail		1	1
 RenderMaxPartCount			1	4096
 RenderObjectBump			1	1
-RenderReflectionDetail		1	2
+RenderReflectionDetail		1	0
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTransparentWater		1	1
diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt
index a09ba17c6246535e031014482d732addb02f9114..38e6bb1e5e9d01ce083277708836f2ce21743db0 100644
--- a/indra/newview/featuretable_xp.txt
+++ b/indra/newview/featuretable_xp.txt
@@ -135,7 +135,7 @@ RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
 RenderMaxPartCount			1	4096
 RenderObjectBump			1	1
-RenderReflectionDetail		1	2
+RenderReflectionDetail		1	0
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTransparentWater		1	1
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 15f8e7bf4dd67ab7c0f7dd0c29cf6e1899e3b5db..f01d5ff1f539121e87b6c3ce373b9fbdb6e2e2d5 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -2695,6 +2695,9 @@ void LLAgentCamera::lookAtLastChat()
 		new_camera_pos -= delta_pos * 0.4f;
 		new_camera_pos += left * 0.3f;
 		new_camera_pos += up * 0.2f;
+
+		setFocusOnAvatar(FALSE, FALSE);
+
 		if (chatter_av->mHeadp)
 		{
 			setFocusGlobal(gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), gAgent.getLastChatter());
@@ -2705,7 +2708,6 @@ void LLAgentCamera::lookAtLastChat()
 			setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());
 			mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
 		}
-		setFocusOnAvatar(FALSE, TRUE);
 	}
 	else
 	{
@@ -2725,9 +2727,10 @@ void LLAgentCamera::lookAtLastChat()
 		new_camera_pos += left * 0.3f;
 		new_camera_pos += up * 0.2f;
 
+		setFocusOnAvatar(FALSE, FALSE);
+
 		setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());
 		mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
-		setFocusOnAvatar(FALSE, TRUE);
 	}
 }
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5c0c5adabe09ba791cb7b2f6039a56b1c32e46fe..3a98c23e05d70a2a4b43a32ebf6b05a666577a06 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -80,6 +80,8 @@
 #include "llfeaturemanager.h"
 #include "llurlmatch.h"
 #include "lltextutil.h"
+#include "lllogininstance.h"
+#include "llprogressview.h"
 
 #include "llweb.h"
 #include "llsecondlifeurls.h"
@@ -602,10 +604,14 @@ LLAppViewer::LLAppViewer() :
 	setupErrorHandling();
 	sInstance = this;
 	gLoggedInTime.stop();
+	
+	LLLoginInstance::instance().setUpdaterService(mUpdater.get());
 }
 
 LLAppViewer::~LLAppViewer()
 {
+	LLLoginInstance::instance().setUpdaterService(0);
+	
 	destroyMainloopTimeout();
 
 	// If we got to this destructor somehow, the app didn't hang.
@@ -2432,26 +2438,120 @@ bool LLAppViewer::initConfiguration()
 }
 
 namespace {
-    // *TODO - decide if there's a better place for this function.
+    // *TODO - decide if there's a better place for these functions.
     // do we need a file llupdaterui.cpp or something? -brad
+
+	void apply_update_callback(LLSD const & notification, LLSD const & response)
+	{
+		lldebugs << "LLUpdate user response: " << response << llendl;
+		if(response["OK_okcancelbuttons"].asBoolean())
+		{
+			llinfos << "LLUpdate restarting viewer" << llendl;
+			static const bool install_if_ready = true;
+			// *HACK - this lets us launch the installer immediately for now
+			LLUpdaterService().startChecking(install_if_ready);
+		}
+	}
+	
+	void apply_update_ok_callback(LLSD const & notification, LLSD const & response)
+	{
+		llinfos << "LLUpdate restarting viewer" << llendl;
+		static const bool install_if_ready = true;
+		// *HACK - this lets us launch the installer immediately for now
+		LLUpdaterService().startChecking(install_if_ready);
+	}
+	
+	void on_update_downloaded(LLSD const & data)
+	{
+		std::string notification_name;
+		void (*apply_callback)(LLSD const &, LLSD const &) = NULL;
+
+		if(data["required"].asBoolean())
+		{
+			apply_callback = &apply_update_ok_callback;
+			if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT)
+			{
+				// The user never saw the progress bar.
+				notification_name = "RequiredUpdateDownloadedVerboseDialog";
+			}
+			else
+			{
+				notification_name = "RequiredUpdateDownloadedDialog";
+			}
+		}
+		else
+		{
+			apply_callback = &apply_update_callback;
+			if(LLStartUp::getStartupState() < STATE_STARTED)
+			{
+				// CHOP-262 we need to use a different notification
+				// method prior to login.
+				notification_name = "DownloadBackgroundDialog";
+			}
+			else
+			{
+				notification_name = "DownloadBackgroundTip";
+			}
+		}
+
+		LLSD substitutions;
+		substitutions["VERSION"] = data["version"];
+
+		// truncate version at the rightmost '.' 
+		std::string version_short(data["version"]);
+		size_t short_length = version_short.rfind('.');
+		if (short_length != std::string::npos)
+		{
+			version_short.resize(short_length);
+		}
+
+		LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]");
+		relnotes_url.setArg("[VERSION_SHORT]", version_short);
+
+		// *TODO thread the update service's response through to this point
+		std::string const & channel = LLVersionInfo::getChannel();
+		boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free);
+
+		relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get());
+		relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL"));
+		substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString();
+
+		LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback);
+	}
+
+	void install_error_callback(LLSD const & notification, LLSD const & response)
+	{
+		LLAppViewer::instance()->forceQuit();
+	}
+	
     bool notify_update(LLSD const & evt)
     {
+		std::string notification_name;
 		switch (evt["type"].asInteger())
 		{
 			case LLUpdaterService::DOWNLOAD_COMPLETE:
-				LLNotificationsUtil::add("DownloadBackground");
+				on_update_downloaded(evt);
 				break;
 			case LLUpdaterService::INSTALL_ERROR:
-				LLNotificationsUtil::add("FailedUpdateInstall");
+				if(evt["required"].asBoolean()) {
+					LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback);
+				} else {
+					LLNotificationsUtil::add("FailedUpdateInstall");
+				}
 				break;
 			default:
-				llinfos << "unhandled update event " << evt << llendl;
 				break;
 		}
 
 		// let others also handle this event by default
         return false;
     }
+	
+	bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt)
+	{
+		updater->setBandwidthLimit(evt.asInteger() * (1024/8));
+		return false; // Let others receive this event.
+	};
 };
 
 void LLAppViewer::initUpdater()
@@ -2474,7 +2574,10 @@ void LLAppViewer::initUpdater()
 						 channel, 
 						 version);
  	mUpdater->setCheckPeriod(check_period);
-	if(gSavedSettings.getBOOL("UpdaterServiceActive"))
+	mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8));
+	gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()->
+		connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2));
+	if(gSavedSettings.getU32("UpdaterServiceSetting"))
 	{
 		bool install_if_ready = true;
 		mUpdater->startChecking(install_if_ready);
@@ -2901,8 +3004,10 @@ void LLAppViewer::handleViewerCrash()
 		pApp->removeMarkerFile(false);
 	}
 	
+#if LL_SEND_CRASH_REPORTS
 	// Call to pure virtual, handled by platform specific llappviewer instance.
 	pApp->handleCrashReporting(); 
+#endif
     
 	return;
 }
@@ -3113,7 +3218,7 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q
 
 void LLAppViewer::userQuit()
 {
-	if (gDisconnected)
+	if (gDisconnected || gViewerWindow->getProgressView()->getVisible())
 	{
 		requestQuit();
 	}
@@ -4629,6 +4734,35 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)
 		return;
 	}
 
+	LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL;
+#if ! defined(LL_WINDOWS)
+	{
+		std::string outfile("/tmp/lleventhost.file.out");
+		std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1");
+		int rc = system(command.c_str());
+		if (rc != 0)
+		{
+			LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL;
+		}
+		else
+		{
+			LL_INFOS("eventhost") << command << ':' << LL_ENDL;
+		}
+		{
+			std::ifstream reader(outfile.c_str());
+			std::string line;
+			while (std::getline(reader, line))
+			{
+				size_t len = line.length();
+				if (len && line[len-1] == '\n')
+					line.erase(len-1);
+				LL_INFOS("eventhost") << line << LL_ENDL;
+			}
+		}
+		remove(outfile.c_str());
+	}
+#endif // LL_WINDOWS
+
 	apr_dso_handle_t * eventhost_dso_handle = NULL;
 	apr_pool_t * eventhost_dso_memory_pool = NULL;
 
@@ -4637,13 +4771,13 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)
 	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(! ll_apr_warn_status(rv, eventhost_dso_handle));
 	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_apr_warn_status(rv, eventhost_dso_handle));
 	llassert_always(ll_plugin_start_func != NULL);
 
 	LLSD args;
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index 351b9ac5dad40a4423cfe24556ee7ba6acf5cccb..1b94d8cbcd2e7ccfe1bac70a41412eb07cc0f5f0 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -83,7 +83,6 @@ LLFloaterMap::~LLFloaterMap()
 BOOL LLFloaterMap::postBuild()
 {
 	mMap = getChild<LLNetMap>("Net Map");
-	mMap->setScale(gSavedSettings.getF32("MiniMapScale"));
 	mMap->setToolTipMsg(getString("ToolTipMsg"));	
 	sendChildToBack(mMap);
 	
@@ -288,7 +287,16 @@ void LLFloaterMap::handleZoom(const LLSD& userdata)
 	std::string level = userdata.asString();
 	
 	F32 scale = 0.0f;
-	if (level == std::string("close"))
+	if (level == std::string("default"))
+	{
+		LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale");
+		if(pvar)
+		{
+			pvar->resetToDefault();
+			scale = gSavedSettings.getF32("MiniMapScale");
+		}
+	}
+	else if (level == std::string("close"))
 		scale = LLNetMap::MAP_SCALE_MAX;
 	else if (level == std::string("medium"))
 		scale = LLNetMap::MAP_SCALE_MID;
@@ -296,7 +304,6 @@ void LLFloaterMap::handleZoom(const LLSD& userdata)
 		scale = LLNetMap::MAP_SCALE_MIN;
 	if (scale != 0.0f)
 	{
-		gSavedSettings.setF32("MiniMapScale", scale );
 		mMap->setScale(scale);
 	}
 }
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index bdc0dfa7e2f6f4bc57b30ba2f9e1d04980ae8257..f74ae92a7be67679acff65e255d8f6ad3008c8ec 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -470,7 +470,7 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
 }
 
 //static
-bool LLIMFloater::resetAllowedRectPadding(const LLSD& newvalue)
+bool LLIMFloater::resetAllowedRectPadding()
 {
 	//reset allowed rect right padding if "SidebarCameraMovement" option 
 	//or sidebar state changed
@@ -482,10 +482,10 @@ void LLIMFloater::getAllowedRect(LLRect& rect)
 {
 	if (sAllowedRectRightPadding == RECT_PADDING_NOT_INIT) //wasn't initialized
 	{
-		gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2));
+		gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding));
 
 		LLSideTray*	side_bar = LLSideTray::getInstance();
-		side_bar->getCollapseSignal().connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2));
+		side_bar->setVisibleWidthChangeCallback(boost::bind(&LLIMFloater::resetAllowedRectPadding));
 		sAllowedRectRightPadding = RECT_PADDING_NEED_RECALC;
 	}
 
@@ -500,10 +500,7 @@ void LLIMFloater::getAllowedRect(LLRect& rect)
 
 		if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)
 		{
-			LLSideTray*	side_bar = LLSideTray::getInstance();
-
-			if (side_bar->getVisible() && !side_bar->getCollapsed())
-				sAllowedRectRightPadding += side_bar->getRect().getWidth();
+			sAllowedRectRightPadding += LLSideTray::getInstance()->getVisibleWidth();
 		}
 	}
 	rect.mRight -= sAllowedRectRightPadding;
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index e80e45e64ae8c48fd3f56ad5cce0dfe5eb6c9aea..5158f6c1f788d76243b28ada549d9f848d89f721 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -156,7 +156,7 @@ class LLIMFloater : public LLTransientDockableFloater
 
 	static void closeHiddenIMToasts();
 
-	static bool resetAllowedRectPadding(const LLSD& newvalue);
+	static bool resetAllowedRectPadding();
 	//need to keep this static for performance issues
 	static S32 sAllowedRectRightPadding;
 
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index ab0acbae5062f116cadc5b117936c9ec9d413cc1..5108f6859220e4e158756847f52298c8e6a4d3d7 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -5344,11 +5344,6 @@ void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 
 	menuentry_vec_t disabled_items, items = getMenuItems();
 
-	items.erase(std::remove(items.begin(), items.end(), std::string("New Body Parts")), items.end());
-	items.erase(std::remove(items.begin(), items.end(), std::string("New Clothes")), items.end());
-	items.erase(std::remove(items.begin(), items.end(), std::string("New Note")), items.end());
-	items.erase(std::remove(items.begin(), items.end(), std::string("New Gesture")), items.end());
-	items.erase(std::remove(items.begin(), items.end(), std::string("New Script")), items.end());
 	items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end());
 
 	hide_context_entries(menu, items, disabled_items);
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 0546803784f190386de1b557a0322754cf906da8..d866db1829240ac0ffbae648b380cacdaf8f39cc 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -49,18 +49,421 @@
 #include "llnotifications.h"
 #include "llwindow.h"
 #include "llviewerwindow.h"
+#include "llprogressview.h"
 #if LL_LINUX || LL_SOLARIS
 #include "lltrans.h"
 #endif
 #include "llsecapi.h"
 #include "llstartup.h"
 #include "llmachineid.h"
+#include "llupdaterservice.h"
+#include "llevents.h"
+#include "llnotificationsutil.h"
+#include "llappviewer.h"
+
+#include <boost/scoped_ptr.hpp>
+#include <sstream>
+
+class LLLoginInstance::Disposable {
+public:
+	virtual ~Disposable() {}
+};
+
+namespace {
+	class MandatoryUpdateMachine:
+		public LLLoginInstance::Disposable
+	{
+	public:
+		MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService);
+		
+		void start(void);
+		
+	private:
+		class State;
+		class CheckingForUpdate;
+		class Error;
+		class ReadyToInstall; 
+		class StartingUpdaterService;
+		class WaitingForDownload;
+		
+		LLLoginInstance & mLoginInstance;
+		boost::scoped_ptr<State> mState;
+		LLUpdaterService & mUpdaterService;
+		
+		void setCurrentState(State * newState);
+	};
+
+	
+	class MandatoryUpdateMachine::State {
+	public:
+		virtual ~State() {}
+		virtual void enter(void) {}
+		virtual void exit(void) {}
+	};
+	
+	
+	class MandatoryUpdateMachine::CheckingForUpdate:
+	public MandatoryUpdateMachine::State
+	{
+	public:
+		CheckingForUpdate(MandatoryUpdateMachine & machine);
+		
+		virtual void enter(void);
+		virtual void exit(void);
+		
+	private:
+		LLTempBoundListener mConnection;
+		MandatoryUpdateMachine & mMachine;
+		LLProgressView * mProgressView;
+		
+		bool onEvent(LLSD const & event);
+	};
+	
+	
+	class MandatoryUpdateMachine::Error:
+	public MandatoryUpdateMachine::State
+	{
+	public:
+		Error(MandatoryUpdateMachine & machine);
+		
+		virtual void enter(void);
+		virtual void exit(void);
+		void onButtonClicked(const LLSD &, const LLSD &);
+		
+	private:
+		MandatoryUpdateMachine & mMachine;
+	};
+	
+	
+	class MandatoryUpdateMachine::ReadyToInstall:
+	public MandatoryUpdateMachine::State
+	{
+	public:
+		ReadyToInstall(MandatoryUpdateMachine & machine);
+		
+		virtual void enter(void);
+		virtual void exit(void);
+		
+	private:
+		MandatoryUpdateMachine & mMachine;
+	};
+	
+	
+	class MandatoryUpdateMachine::StartingUpdaterService:
+	public MandatoryUpdateMachine::State
+	{
+	public:
+		StartingUpdaterService(MandatoryUpdateMachine & machine);
+		
+		virtual void enter(void);
+		virtual void exit(void);
+		void onButtonClicked(const LLSD & uiform, const LLSD & result);
+	private:
+		MandatoryUpdateMachine & mMachine;
+	};
+	
+	
+	class MandatoryUpdateMachine::WaitingForDownload:
+		public MandatoryUpdateMachine::State
+	{
+	public:
+		WaitingForDownload(MandatoryUpdateMachine & machine);
+		
+		virtual void enter(void);
+		virtual void exit(void);
+		
+	private:
+		LLTempBoundListener mConnection;
+		MandatoryUpdateMachine & mMachine;
+		LLProgressView * mProgressView;
+		
+		bool onEvent(LLSD const & event);
+	};
+}
 
 static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
 static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
 
 std::string construct_start_string();
 
+
+
+// MandatoryUpdateMachine
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService):
+	mLoginInstance(loginInstance),
+	mUpdaterService(updaterService)
+{
+	; // No op.
+}
+
+
+void MandatoryUpdateMachine::start(void)
+{
+	llinfos << "starting manditory update machine" << llendl;
+	
+	if(mUpdaterService.isChecking()) {
+		switch(mUpdaterService.getState()) {
+			case LLUpdaterService::UP_TO_DATE:
+				mUpdaterService.stopChecking();
+				mUpdaterService.startChecking();
+				// Fall through.
+			case LLUpdaterService::INITIAL:
+			case LLUpdaterService::CHECKING_FOR_UPDATE:
+				setCurrentState(new CheckingForUpdate(*this));
+				break;
+			case LLUpdaterService::DOWNLOADING:
+				setCurrentState(new WaitingForDownload(*this));
+				break;
+			case LLUpdaterService::TERMINAL:
+				if(LLUpdaterService::updateReadyToInstall()) {
+					setCurrentState(new ReadyToInstall(*this));
+				} else {
+					setCurrentState(new Error(*this));
+				}
+				break;
+			case LLUpdaterService::FAILURE:
+				setCurrentState(new Error(*this));
+				break;
+			default:
+				llassert(!"unpossible case");
+				break;
+		}
+	} else {
+		setCurrentState(new StartingUpdaterService(*this));
+	}
+}
+
+
+void MandatoryUpdateMachine::setCurrentState(State * newStatePointer)
+{
+	{
+		boost::scoped_ptr<State> newState(newStatePointer);
+		if(mState != 0) mState->exit();
+		mState.swap(newState);
+		
+		// Old state will be deleted on exit from this block before the new state
+		// is entered.
+	}
+	if(mState != 0) mState->enter();
+}
+
+
+
+// MandatoryUpdateMachine::CheckingForUpdate
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::CheckingForUpdate::CheckingForUpdate(MandatoryUpdateMachine & machine):
+	mMachine(machine)
+{
+	; // No op.
+}
+
+
+void MandatoryUpdateMachine::CheckingForUpdate::enter(void)
+{
+	llinfos << "entering checking for update" << llendl;
+	
+	mProgressView = gViewerWindow->getProgressView();
+	mProgressView->setMessage("Looking for update...");
+	mProgressView->setText("There is a required update for your Second Life installation.");
+	mProgressView->setPercent(0);
+	mProgressView->setVisible(true);
+	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
+		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::CheckingForUpdate::onEvent, this, _1));
+}
+
+
+void MandatoryUpdateMachine::CheckingForUpdate::exit(void)
+{
+}
+
+
+bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event)
+{
+	if(event["type"].asInteger() == LLUpdaterService::STATE_CHANGE) {
+		switch(event["state"].asInteger()) {
+			case LLUpdaterService::DOWNLOADING:
+				mMachine.setCurrentState(new WaitingForDownload(mMachine));
+				break;
+			case LLUpdaterService::UP_TO_DATE:
+			case LLUpdaterService::TERMINAL:
+			case LLUpdaterService::FAILURE:
+				mProgressView->setVisible(false);
+				mMachine.setCurrentState(new Error(mMachine));
+				break;
+			case LLUpdaterService::INSTALLING:
+				llassert(!"can't possibly be installing");
+				break;
+			default:
+				break;
+		}
+	} else {
+		; // Ignore.
+	}
+	
+	return false;
+}
+
+
+
+// MandatoryUpdateMachine::Error
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine):
+	mMachine(machine)
+{
+	; // No op.
+}
+
+
+void MandatoryUpdateMachine::Error::enter(void)
+{
+	llinfos << "entering error" << llendl;
+	LLNotificationsUtil::add("FailedUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2));
+}
+
+
+void MandatoryUpdateMachine::Error::exit(void)
+{
+	LLAppViewer::instance()->forceQuit();
+}
+
+
+void MandatoryUpdateMachine::Error::onButtonClicked(const LLSD &, const LLSD &)
+{
+	mMachine.setCurrentState(0);
+}
+
+
+
+// MandatoryUpdateMachine::ReadyToInstall
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::ReadyToInstall::ReadyToInstall(MandatoryUpdateMachine & machine):
+	mMachine(machine)
+{
+	; // No op.
+}
+
+
+void MandatoryUpdateMachine::ReadyToInstall::enter(void)
+{
+	llinfos << "entering ready to install" << llendl;
+	// Open update ready dialog.
+}
+
+
+void MandatoryUpdateMachine::ReadyToInstall::exit(void)
+{
+	// Restart viewer.
+}
+
+
+
+// MandatoryUpdateMachine::StartingUpdaterService
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::StartingUpdaterService::StartingUpdaterService(MandatoryUpdateMachine & machine):
+	mMachine(machine)
+{
+	; // No op.
+}
+
+
+void MandatoryUpdateMachine::StartingUpdaterService::enter(void)
+{
+	llinfos << "entering start update service" << llendl;
+	LLNotificationsUtil::add("UpdaterServiceNotRunning", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked, this, _1, _2));
+}
+
+
+void MandatoryUpdateMachine::StartingUpdaterService::exit(void)
+{
+	; // No op.
+}
+
+
+void MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked(const LLSD & uiform, const LLSD & result)
+{
+	if(result["OK_okcancelbuttons"].asBoolean()) {
+		mMachine.mUpdaterService.startChecking(false);
+		mMachine.setCurrentState(new CheckingForUpdate(mMachine));
+	} else {
+		LLAppViewer::instance()->forceQuit();
+	}
+}
+
+
+
+// MandatoryUpdateMachine::WaitingForDownload
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::WaitingForDownload::WaitingForDownload(MandatoryUpdateMachine & machine):
+	mMachine(machine),
+	mProgressView(0)
+{
+	; // No op.
+}
+
+
+void MandatoryUpdateMachine::WaitingForDownload::enter(void)
+{
+	llinfos << "entering waiting for download" << llendl;
+	mProgressView = gViewerWindow->getProgressView();
+	mProgressView->setMessage("Downloading update...");
+	std::ostringstream stream;
+	stream << "There is a required update for your Second Life installation." << std::endl <<
+		"Version " << mMachine.mUpdaterService.updatedVersion();
+	mProgressView->setText(stream.str());
+	mProgressView->setPercent(0);
+	mProgressView->setVisible(true);
+	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
+		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::WaitingForDownload::onEvent, this, _1));
+}
+
+
+void MandatoryUpdateMachine::WaitingForDownload::exit(void)
+{
+	mProgressView->setVisible(false);
+}
+
+
+bool MandatoryUpdateMachine::WaitingForDownload::onEvent(LLSD const & event)
+{
+	switch(event["type"].asInteger()) {
+		case LLUpdaterService::DOWNLOAD_COMPLETE:
+			mMachine.setCurrentState(new ReadyToInstall(mMachine));
+			break;
+		case LLUpdaterService::DOWNLOAD_ERROR:
+			mMachine.setCurrentState(new Error(mMachine));
+			break;
+		case LLUpdaterService::PROGRESS: {
+			double downloadSize = event["download_size"].asReal();
+			double bytesDownloaded = event["bytes_downloaded"].asReal();
+			mProgressView->setPercent(100. * bytesDownloaded / downloadSize);
+			break;
+		}
+		default:
+			break;
+	}
+
+	return false;
+}
+
+
+
+// LLLoginInstance
+//-----------------------------------------------------------------------------
+
+
 LLLoginInstance::LLLoginInstance() :
 	mLoginModule(new LLLogin()),
 	mNotifications(NULL),
@@ -69,7 +472,8 @@ LLLoginInstance::LLLoginInstance() :
 	mSkipOptionalUpdate(false),
 	mAttemptComplete(false),
 	mTransferRate(0.0f),
-	mDispatcher("LLLoginInstance", "change")
+	mDispatcher("LLLoginInstance", "change"),
+	mUpdaterService(0)
 {
 	mLoginModule->getEventPump().listen("lllogininstance", 
 		boost::bind(&LLLoginInstance::handleLoginEvent, this, _1));
@@ -354,6 +758,15 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
 
 void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)
 {
+	if(mandatory)
+	{
+		gViewerWindow->setShowProgress(false);
+		MandatoryUpdateMachine * machine = new MandatoryUpdateMachine(*this, *mUpdaterService);
+		mUpdateStateMachine.reset(machine);
+		machine->start();
+		return;
+	}
+	
 	// store off config state, as we might quit soon
 	gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);	
 	LLUIColorTable::instance().saveUserSettings();
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index 159e05046c40767c01fc8a75bfb4d8025b044fad..b872d7d1b1a417b2e78025e4ba7f9aa2f34a4e6f 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -34,12 +34,15 @@
 class LLLogin;
 class LLEventStream;
 class LLNotificationsInterface;
+class LLUpdaterService;
 
 // This class hosts the login module and is used to 
 // negotiate user authentication attempts.
 class LLLoginInstance : public LLSingleton<LLLoginInstance>
 {
 public:
+	class Disposable;
+
 	LLLoginInstance();
 	~LLLoginInstance();
 
@@ -75,6 +78,7 @@ class LLLoginInstance : public LLSingleton<LLLoginInstance>
 	typedef boost::function<void()> UpdaterLauncherCallback;
 	void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }
 
+	void setUpdaterService(LLUpdaterService * updaterService) { mUpdaterService = updaterService; }
 private:
 	void constructAuthParams(LLPointer<LLCredential> user_credentials);
 	void updateApp(bool mandatory, const std::string& message);
@@ -104,6 +108,8 @@ class LLLoginInstance : public LLSingleton<LLLoginInstance>
 	int mLastExecEvent;
 	UpdaterLauncherCallback mUpdaterLauncher;
 	LLEventDispatcher mDispatcher;
+	LLUpdaterService * mUpdaterService;	
+	boost::scoped_ptr<Disposable> mUpdateStateMachine;
 };
 
 #endif
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index cebfac86e71effb2e97234041aeb6a07c977c003..de5439e4e03e5a88002a454a74e790cd503548db 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -527,7 +527,8 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 
 	if( nearby_chat->getVisible()
 		|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
-			&& gSavedSettings.getBOOL("UseChatBubbles") ) )
+			&& gSavedSettings.getBOOL("UseChatBubbles") )
+		|| !mChannel->getShowToasts() ) // to prevent toasts in Busy mode
 		return;//no need in toast if chat is visible or if bubble chat is enabled
 
 	// Handle irc styled messages for toast panel
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index f084002385abd6952fd9398c163e4d24ea2c47ac..1a8ec4991d7dedef4b1f47cf0440dfce89b213e4 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -94,10 +94,12 @@ LLNetMap::LLNetMap (const Params & p)
 	mToolTipMsg()
 {
 	mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
+	setScale(gSavedSettings.getF32("MiniMapScale"));
 }
 
 LLNetMap::~LLNetMap()
 {
+	gSavedSettings.setF32("MiniMapScale", mScale);
 }
 
 void LLNetMap::setScale( F32 scale )
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 457e2d2980afe17cb511066d4653bff19c7804e8..5f89097c1787c9f122d0adff740cee5af84e54c4 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -73,7 +73,6 @@
 #endif  // LL_WINDOWS
 
 #include "llsdserialize.h"
-#define USE_VIEWER_AUTH 0
 
 const S32 BLACK_BORDER_HEIGHT = 160;
 const S32 MAX_PASSWORD = 16;
@@ -190,10 +189,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 
 	buildFromFile( "panel_login.xml");
 	
-#if USE_VIEWER_AUTH
-	//leave room for the login menu bar
-	setRect(LLRect(0, rect.getHeight()-18, rect.getWidth(), 0)); 
-#endif
 	// Legacy login web page is hidden under the menu bar.
 	// Adjust reg-in-client web browser widget to not be hidden.
 	if (gSavedSettings.getBOOL("RegInClient"))
@@ -205,7 +200,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 		reshape(rect.getWidth(), rect.getHeight());
 	}
 
-#if !USE_VIEWER_AUTH
 	getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
 
 	// change z sort of clickable text to be behind buttons
@@ -245,7 +239,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 
 	LLTextBox* need_help_text = getChild<LLTextBox>("login_help");
 	need_help_text->setClickedCallback(onClickHelp, NULL);
-#endif    
 	
 	// get the web browser control
 	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
@@ -272,15 +265,9 @@ void LLPanelLogin::reshapeBrowser()
 	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
 	LLRect rect = gViewerWindow->getWindowRectScaled();
 	LLRect html_rect;
-#if USE_VIEWER_AUTH
-	html_rect.setCenterAndSize( 
-		rect.getCenterX() - 2, rect.getCenterY(), 
-		rect.getWidth() + 6, rect.getHeight());
-#else
 	html_rect.setCenterAndSize(
 		rect.getCenterX() - 2, rect.getCenterY() + 40,
 		rect.getWidth() + 6, rect.getHeight() - 78 );
-#endif
 	web_browser->setRect( html_rect );
 	web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE );
 	reshape( rect.getWidth(), rect.getHeight(), 1 );
@@ -303,7 +290,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )
 	else
 	// the site is not available (missing page, server down, other badness)
 	{
-#if !USE_VIEWER_AUTH
 		if ( web_browser )
 		{
 			// hide browser control (revealing default one)
@@ -312,16 +298,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )
 			// mark as unavailable
 			mHtmlAvailable = FALSE;
 		}
-#else
-
-		if ( web_browser )
-		{	
-			web_browser->navigateToLocalPage( "loading-error" , "index.html" );
-
-			// mark as available
-			mHtmlAvailable = TRUE;
-		}
-#endif
 	}
 }
 
@@ -361,7 +337,6 @@ void LLPanelLogin::draw()
 
 		if ( mHtmlAvailable )
 		{
-#if !USE_VIEWER_AUTH
 			if (getChild<LLView>("login_widgets")->getVisible())
 			{
 				// draw a background box in black
@@ -370,7 +345,6 @@ void LLPanelLogin::draw()
 				// just the blue background to the native client UI
 				mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());
 			}
-#endif
 		}
 		else
 		{
@@ -416,12 +390,6 @@ void LLPanelLogin::setFocus(BOOL b)
 // static
 void LLPanelLogin::giveFocus()
 {
-#if USE_VIEWER_AUTH
-	if (sInstance)
-	{
-		sInstance->setFocus(TRUE);
-	}
-#else
 	if( sInstance )
 	{
 		// Grab focus and move cursor to first blank input field
@@ -450,17 +418,18 @@ void LLPanelLogin::giveFocus()
 			edit->selectAll();
 		}
 	}
-#endif
 }
 
 // static
 void LLPanelLogin::showLoginWidgets()
 {
+	// *NOTE: Mani - This may or may not be obselete code.
+	// It seems to be part of the defunct? reg-in-client project.
 	sInstance->getChildView("login_widgets")->setVisible( true);
 	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
 	sInstance->reshapeBrowser();
 	// *TODO: Append all the usual login parameters, like first_login=Y etc.
-	std::string splash_screen_url = sInstance->getString("real_url");
+	std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();
 	web_browser->navigateTo( splash_screen_url, "text/html" );
 	LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit");
 	username_edit->setFocus(TRUE);
@@ -830,73 +799,6 @@ void LLPanelLogin::loadLoginPage()
 	curl_free(curl_grid);
 	gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
 	gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
-
-
-#if USE_VIEWER_AUTH
-	LLURLSimString::sInstance.parse();
-
-	std::string location;
-	std::string region;
-	std::string password;
-	
-	if (LLURLSimString::parse())
-	{
-		std::ostringstream oRegionStr;
-		location = "specify";
-		oRegionStr << LLURLSimString::sInstance.mSimName << "/" << LLURLSimString::sInstance.mX << "/"
-			 << LLURLSimString::sInstance.mY << "/"
-			 << LLURLSimString::sInstance.mZ;
-		region = oRegionStr.str();
-	}
-	else
-	{
-		location = gSavedSettings.getString("LoginLocation");
-	}
-	
-	std::string username;
-
-    if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
-    {
-        LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
-		username = cmd_line_login[0].asString() + " " + cmd_line_login[1];
-        password = cmd_line_login[2].asString();
-    }
-    	
-	
-	char* curl_region = curl_escape(region.c_str(), 0);
-
-	oStr <<"username=" << username <<
-		 "&location=" << location <<	"&region=" << curl_region;
-	
-	curl_free(curl_region);
-
-	if (!password.empty())
-	{
-		oStr << "&password=" << password;
-	}
-	else if (!(password = load_password_from_disk()).empty())
-	{
-		oStr << "&password=$1$" << password;
-	}
-	if (gAutoLogin)
-	{
-		oStr << "&auto_login=TRUE";
-	}
-	if (gSavedSettings.getBOOL("ShowStartLocation"))
-	{
-		oStr << "&show_start_location=TRUE";
-	}	
-	if (gSavedSettings.getBOOL("RememberPassword"))
-	{
-		oStr << "&remember_password=TRUE";
-	}	
-#ifndef	LL_RELEASE_FOR_DOWNLOAD
-	oStr << "&show_grid=TRUE";
-#else
-	if (gSavedSettings.getBOOL("ForceShowGrid"))
-		oStr << "&show_grid=TRUE";
-#endif
-#endif
 	
 	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
 
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 17433a557b91d805bf4bd601c67b5dfef2b13ce0..c83176d9800083d4640bae6668eb7fbcfea50824 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -506,9 +506,6 @@ void LLPanelMainInventory::onFilterSelected()
 		return;
 	}
 
-	BOOL recent_active = ("Recent Items" == mActivePanel->getName());
-	getChildView("add_btn_panel")->setVisible( !recent_active);
-
 	setFilterSubString(mFilterSubString);
 	LLInventoryFilter* filter = mActivePanel->getFilter();
 	LLFloaterInventoryFinder *finder = getFinder();
@@ -944,6 +941,11 @@ void LLPanelMainInventory::updateListCommands()
 
 void LLPanelMainInventory::onAddButtonClick()
 {
+// Gray out the "New Folder" option when the Recent tab is active as new folders will not be displayed
+// unless "Always show folders" is checked in the filter options.
+	bool recent_active = ("Recent Items" == mActivePanel->getName());
+	mMenuAdd->getChild<LLMenuItemGL>("New Folder")->setEnabled(!recent_active);
+
 	setUploadCostIfNeeded();
 
 	showActionMenu(mMenuAdd,"add_btn");
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 1869e92c8ce8528e861ddc636bb53b3efef005e1..00ac34efa5ce70cb9a6ba863fec87a190bbd3b35 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -753,6 +753,11 @@ void LLPanelPlaces::onOverflowButtonClicked()
 		// there is no landmark already pointing to that parcel in agent's inventory.
 		menu->getChild<LLMenuItemCallGL>("landmark")->setEnabled(is_agent_place_info_visible &&
 																 !LLLandmarkActions::landmarkAlreadyExists());
+		// STORM-411
+		// Creating landmarks for remote locations is impossible.
+		// So hide menu item "Make a Landmark" in "Teleport History Profile" panel.
+		menu->setItemVisible("landmark", mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE);
+		menu->arrangeAndClear();
 	}
 	else if (mPlaceInfoType == LANDMARK_INFO_TYPE && mLandmarkMenu != NULL)
 	{
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index db02d76139ec334841ae87c63e46b6a38f489812..31fde5d58aedfd401c40c46aa6069055ad420a11 100644
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -133,13 +133,13 @@ void LLProgressView::setVisible(BOOL visible)
 		mFadeTimer.start();
 	}
 	// showing progress view
-	else if (!getVisible() && visible)
+	else if (visible && (!getVisible() || mFadeTimer.getStarted()))
 	{
 		setFocus(TRUE);
 		mFadeTimer.stop();
 		mProgressTimer.start();
 		LLPanel::setVisible(TRUE);
-	}
+	} 
 }
 
 
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 0eeb89792bd70ee723b9447d08da9c666a6ce075..e3bc67a4147993880551d641918da4ee67d719eb 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -83,11 +83,10 @@ bool  LLScreenChannelBase::isHovering()
 	return mHoveredToast->isHovered();
 }
 
-bool LLScreenChannelBase::resetPositionAndSize(const LLSD& newvalue)
+void LLScreenChannelBase::resetPositionAndSize()
 {
 	LLRect rc = gViewerWindow->getWorldViewRectScaled();
 	updatePositionAndSize(rc, rc);
-	return true;
 }
 
 void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect)
@@ -99,10 +98,7 @@ void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect ne
 	if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE
 		&& LLSideTray::instanceCreated	())
 	{
-		LLSideTray*	side_bar = LLSideTray::getInstance();
-
-		if (side_bar->getVisible() && !side_bar->getCollapsed())
-			world_rect_padding += side_bar->getRect().getWidth();
+		world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();
 	}
 
 
@@ -133,7 +129,7 @@ void LLScreenChannelBase::init(S32 channel_left, S32 channel_right)
 	if(LLSideTray::instanceCreated())
 	{
 		LLSideTray*	side_bar = LLSideTray::getInstance();
-		side_bar->getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this, _2));
+		side_bar->setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this));
 	}
 
 	// top and bottom set by updateBottom()
@@ -214,10 +210,7 @@ void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_wo
 	if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE 
 		&& LLSideTray::instanceCreated	())
 	{
-		LLSideTray*	side_bar = LLSideTray::getInstance();
-
-		if (side_bar->getVisible() && !side_bar->getCollapsed())
-			world_rect_padding += side_bar->getRect().getWidth();
+		world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();
 	}
 
 
@@ -495,7 +488,7 @@ void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)
 //--------------------------------------------------------------------------
 void LLScreenChannel::redrawToasts()
 {
-	if(mToastList.size() == 0 || isHovering())
+	if(mToastList.size() == 0)
 		return;
 
 	switch(mToastAlignment)
@@ -841,8 +834,7 @@ void LLScreenChannel::onToastHover(LLToast* toast, bool mouse_enter)
 		}
 	}
 
-	if(!isHovering())
-		redrawToasts();
+	redrawToasts();
 }
 
 //--------------------------------------------------------------------------
diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h
index c536a21779e3305134a25e69b50380f7d70b9d5d..d207d139819cc63242e3c490f12bac8b6a2c0097 100644
--- a/indra/newview/llscreenchannel.h
+++ b/indra/newview/llscreenchannel.h
@@ -59,8 +59,8 @@ class LLScreenChannelBase : public LLUICtrl
 	// Channel's outfit-functions
 	// update channel's size and position in the World View
 	virtual void		updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect);
+	void				resetPositionAndSize();
 
-	bool resetPositionAndSize(const LLSD& newvalue);
 	// initialization of channel's shape and position
 	virtual void		init(S32 channel_left, S32 channel_right);
 
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 3bc3959e0bf039620af35190f875943818ad87c7..aef665a35cd4db8079689d71296109b8f8dc4c40 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -561,7 +561,7 @@ BOOL LLSideTray::postBuild()
 	{
 		if ((*it).channel)
 		{
-			getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel, _2));
+			setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel));
 		}
 	}
 
@@ -980,9 +980,6 @@ void LLSideTray::reflectCollapseChange()
 	}
 
 	gFloaterView->refresh();
-	
-	LLSD new_value = mCollapsed;
-	mCollapseSignal(this,new_value);
 }
 
 void LLSideTray::arrange()
@@ -1262,9 +1259,29 @@ bool		LLSideTray::isPanelActive(const std::string& panel_name)
 void	LLSideTray::updateSidetrayVisibility()
 {
 	// set visibility of parent container based on collapsed state
-	if (getParent())
+	LLView* parent = getParent();
+	if (parent)
 	{
-		getParent()->setVisible(!mCollapsed && !gAgentCamera.cameraMouselook());
+		bool old_visibility = parent->getVisible();
+		bool new_visibility = !mCollapsed && !gAgentCamera.cameraMouselook();
+
+		if (old_visibility != new_visibility)
+		{
+			parent->setVisible(new_visibility);
+
+			// Signal change of visible width.
+			llinfos << "Visible: " << new_visibility << llendl;
+			mVisibleWidthChangeSignal(this, new_visibility);
+		}
 	}
 }
 
+S32 LLSideTray::getVisibleWidth()
+{
+	return (isInVisibleChain() && !mCollapsed) ? getRect().getWidth() : 0;
+}
+
+void LLSideTray::setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb)
+{
+	mVisibleWidthChangeSignal.connect(cb);
+}
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 3c572dde9545a7e64ce088175b590a3954543dd5..184d78845f8a7fd7e88d26e00fe416394d87121f 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -165,9 +165,18 @@ class LLSideTray : public LLPanel, private LLDestroyClass<LLSideTray>
 	void		reshape			(S32 width, S32 height, BOOL called_from_parent = TRUE);
 
 
-	void		updateSidetrayVisibility();
+	/**
+	 * @return side tray width if it's visible and expanded, 0 otherwise.
+	 *
+	 * Not that width of the tab buttons is not included.
+	 *
+	 * @see setVisibleWidthChangeCallback()
+	 */
+	S32			getVisibleWidth();
+
+	void		setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb);
 
-	commit_signal_t& getCollapseSignal() { return mCollapseSignal; }
+	void		updateSidetrayVisibility();
 
 	void		handleLoginComplete();
 
@@ -216,7 +225,7 @@ class LLSideTray : public LLPanel, private LLDestroyClass<LLSideTray>
 	tab_order_vector_t				mOriginalTabOrder;
 	LLSideTrayTab*					mActiveTab;	
 	
-	commit_signal_t					mCollapseSignal;
+	commit_signal_t					mVisibleWidthChangeSignal;
 
 	LLButton*						mCollapseButton;
 	bool							mCollapsed;
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d945af0776f450376769e1ff1740a2a3b18970ca..611f9de2e6db8dcdb24f2edf9fe9789c0bcd6684 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3095,7 +3095,16 @@ bool process_login_success_response()
 	std::string map_server_url = response["map-server-url"];
 	if(!map_server_url.empty())
 	{
-		gSavedSettings.setString("MapServerURL", map_server_url); 
+		// We got an answer from the grid -> use that for map for the current session
+		gSavedSettings.setString("CurrentMapServerURL", map_server_url); 
+		LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL;
+	}
+	else
+	{
+		// No answer from the grid -> use the default setting for current session 
+		map_server_url = gSavedSettings.getString("MapServerURL"); 
+		gSavedSettings.setString("CurrentMapServerURL", map_server_url); 
+		LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;
 	}
 	
 	// Default male and female avatars allowing the user to choose their avatar on first login.
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 622d09c60015b0639258bf9a96b05de66c173668..8c5a52c1878b3ba475d7761b4d96325a643711fc 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -504,9 +504,10 @@ bool toggle_show_object_render_cost(const LLSD& newvalue)
 
 void toggle_updater_service_active(LLControlVariable* control, const LLSD& new_value)
 {
-    if(new_value.asBoolean())
+    if(new_value.asInteger())
     {
-        LLUpdaterService().startChecking();
+		LLUpdaterService update_service;
+		if(!update_service.isChecking()) update_service.startChecking();
     }
     else
     {
@@ -661,7 +662,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2));
 	gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2));
 	gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2));
-	gSavedSettings.getControl("UpdaterServiceActive")->getSignal()->connect(&toggle_updater_service_active);
+	gSavedSettings.getControl("UpdaterServiceSetting")->getSignal()->connect(&toggle_updater_service_active);
 	gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2));
 	gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2));
 }
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 7313463f1b862788df9250a4a3764408956642f1..7dc5d96689d4449471ee7a736ca676137f444bf4 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -171,6 +171,31 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] =
 	FALSE	// ControlYourCamera
 };
 
+// Extract channel and version from a string like "SL Web Viewer Beta 10.11.29.215604".
+// (channel: "SL Web Viewer Beta", version: "10.11.29.215604")
+static bool parse_version_info(const std::string& version_info, std::string& channel, std::string& ver)
+{
+	size_t last_space = version_info.rfind(" ");
+	channel = version_info;
+
+	if (last_space != std::string::npos)
+	{
+		try
+		{
+			ver = version_info.substr(last_space + 1);
+			channel.replace(last_space, ver.length() + 1, ""); // strip version
+		}
+		catch (std::out_of_range)
+		{
+			return false;
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
 bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
 {
 	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
@@ -3825,28 +3850,22 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)
 
 	if (!gLastVersionChannel.empty())
 	{
-		// work out the URL for this server's Release Notes
-		std::string url ="http://wiki.secondlife.com/wiki/Release_Notes/";
-		std::string server_version = version_channel;
-		std::vector<std::string> s_vect;
-		boost::algorithm::split(s_vect, server_version, isspace);
-		for(U32 i = 0; i < s_vect.size(); i++)
+		std::string url = regionp->getCapability("ServerReleaseNotes");
+		if (url.empty())
 		{
-			if (i != (s_vect.size() - 1))
-			{
-				if(i != (s_vect.size() - 2))
-				{
-				   url += s_vect[i] + "_";
-				}
-				else
-				{
-					url += s_vect[i] + "/";
-				}
-			}
-			else
+			// The capability hasn't arrived yet or is not supported,
+			// fall back to parsing server version channel.
+			std::string channel, ver;
+			if (!parse_version_info(version_channel, channel, ver))
 			{
-				url += s_vect[i].substr(0,4);
+				llwarns << "Failed to parse server version channel (" << version_channel << ")" << llendl;
 			}
+
+			url = gSavedSettings.getString("ReleaseNotesURL");
+			LLSD args;
+			args["CHANNEL"] = LLWeb::escapeURL(channel);
+			args["VERSION"] = LLWeb::escapeURL(ver);
+			LLStringUtil::format(url, args);
 		}
 
 		LLSD args;
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index b8fd9443218823139ba8959c99228b100b4e7e37..5eeb02b080409719e36de2205151a313fc430e13 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -186,11 +186,6 @@ class LLViewerWindow : public LLWindowCallbacks
 	/*virtual*/ std::string translateString(const char* tag,
 					const std::map<std::string, std::string>& args);
 	
-	// signal on bottom tray width changed
-	typedef boost::function<void (void)> bottom_tray_callback_t;
-	typedef boost::signals2::signal<void (void)> bottom_tray_signal_t;
-	bottom_tray_signal_t mOnBottomTrayWidthChanged;
-	boost::signals2::connection setOnBottomTrayWidthChanged(bottom_tray_callback_t cb) { return mOnBottomTrayWidthChanged.connect(cb); }
 	// signal on update of WorldView rect
 	typedef boost::function<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_callback_t;
 	typedef boost::signals2::signal<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_signal_t;
diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp
index be8298daab936af4d571a831640154e2f4b6f6cc..74ed844376e2fb58e2382ae82cfa1fddb38d15a8 100644
--- a/indra/newview/llworldmipmap.cpp
+++ b/indra/newview/llworldmipmap.cpp
@@ -181,8 +181,7 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32
 LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)
 {
 	// Get the grid coordinates
-	std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y);
-
+	std::string imageurl = gSavedSettings.getString("CurrentMapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y);
 
 	// DO NOT COMMIT!! DEBUG ONLY!!!
 	// Use a local jpeg for every tile to test map speed without S3 access
diff --git a/indra/newview/skins/default/xui/en/inspect_object.xml b/indra/newview/skins/default/xui/en/inspect_object.xml
index eb2e7ea7887fc79476e31c2234d38c9653cfb1b7..8d14c974b434b4ddef43e3b0a49a95732cbea132 100644
--- a/indra/newview/skins/default/xui/en/inspect_object.xml
+++ b/indra/newview/skins/default/xui/en/inspect_object.xml
@@ -76,13 +76,24 @@ L$30,000
   </text>
   <!-- Overlapping buttons for all default actions.  Show "Buy" if
   for sale, "Sit" if can sit, etc. -->
+  <icon
+   name="secure_browsing"
+   image_name="Lock"
+   left="0"
+   visible="false"
+   width="18"
+   height="18"
+   top="103"
+   tool_tip="Secure Browsing"
+   follows="left|top" />
    <text
    follows="all"
    font="SansSerifSmall"
    height="13"
    name="object_media_url"
-   width="220"
-   top_pad="0"
+   width="207"
+   left_pad="2"
+   top_delta="0"
    max_length = "50"
    use_ellipses="true">
    http://www.superdupertest.com
@@ -135,16 +146,6 @@ L$30,000
    name="open_btn"
    top_delta="0"
    width="80" />
-  <icon
-   name="secure_browsing"
-   image_name="Lock"
-   left_delta="80"
-   visible="false"
-   width="18"
-   height="18"
-   top_delta="0"
-   tool_tip="Secure Browsing"
-   follows="left|top" />
 
  <!--  non-overlapping buttons here -->
      <button
@@ -153,7 +154,7 @@ L$30,000
      label="More"
      layout="topleft"
      name="more_info_btn"
-     left_delta="10"
+     left_pad="10"
      top_delta="0"
      tab_stop="false"
      width="80" />
diff --git a/indra/newview/skins/default/xui/en/menu_mini_map.xml b/indra/newview/skins/default/xui/en/menu_mini_map.xml
index 8fe89d39343b3b75139bd74ca3ef921f7f4054e4..ea263d05ceff687978d60373687b44d8721e9c21 100644
--- a/indra/newview/skins/default/xui/en/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/en/menu_mini_map.xml
@@ -8,7 +8,7 @@
  top="724"
  visible="false"
  width="128">
-    <menu_item_call
+	<menu_item_call
      label="Zoom Close"
      name="Zoom Close">
         <menu_item_call.on_click
@@ -29,7 +29,14 @@
          function="Minimap.Zoom"
          parameter="far" />
     </menu_item_call>
-    <menu_item_separator />
+	<menu_item_call
+     label="Zoom Default"
+     name="Zoom Default">
+		<menu_item_call.on_click
+         function="Minimap.Zoom"
+         parameter="default" />
+	</menu_item_call>
+	<menu_item_separator />
     <menu_item_check
        label="Rotate Map"
        name="Rotate Map">
diff --git a/indra/newview/skins/default/xui/en/menu_place.xml b/indra/newview/skins/default/xui/en/menu_place.xml
index 1b96eb51f0ca2c6811bbafba0998a23e15274fbf..288811d2f6b020f3e1ee8aa5bf5d10748ad2b918 100644
--- a/indra/newview/skins/default/xui/en/menu_place.xml
+++ b/indra/newview/skins/default/xui/en/menu_place.xml
@@ -24,26 +24,4 @@
          function="Places.OverflowMenu.Enable"
          parameter="can_create_pick" />
     </menu_item_call>
-    <menu_item_separator
-     layout="topleft"/>
-    <menu_item_call
-     enabled="false"
-     label="Buy Pass"
-     layout="topleft"
-     name="pass">
-        <menu_item_call.on_click
-         function="Places.OverflowMenu.Action"
-         parameter="pass" />
-    </menu_item_call>
-    <menu_item_separator
-     layout="topleft"/>
-    <menu_item_call
-     enabled="false"
-     label="Edit"
-     layout="topleft"
-     name="edit">
-        <menu_item_call.on_click
-         function="Places.OverflowMenu.Action"
-         parameter="edit" />
-    </menu_item_call>
 </toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 11a4970488c797a37068a4faa7b3a11e1176cd0f..63c030b0687cd85f33fdadfe9b4f57ab400e77f7 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -2901,12 +2901,80 @@ http://secondlife.com/download.
      name="okbutton"
      yestext="OK"/>
   </notification>
+
   <notification
-   icon="notifytip.tga"
-   name="DownloadBackground"
-   type="notifytip">
-An updated version of [APP_NAME] has been downloaded.
-It will be applied the next time you restart [APP_NAME]
+   icon="alertmodal.tga"
+   name="FailedRequiredUpdateInstall"
+   type="alertmodal">
+We were unable to install a required update. 
+You will be unable to log in until [APP_NAME] has been updated.
+
+Please download and install the latest viewer from
+http://secondlife.com/download.
+    <usetemplate
+     name="okbutton"
+     yestext="Quit"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="UpdaterServiceNotRunning"
+   type="alertmodal">
+There is a required update for your Second Life Installation.
+
+You may download this update from http://www.secondlife.com/downloads
+or you can install it now.
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Quit Second Life"
+     yestext="Download and install now"/>
+  </notification>
+
+  <notification
+   icon="notify.tga"
+   name="DownloadBackgroundTip"
+   type="notify">
+We have downloaded an update to your [APP_NAME] installation.
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Later..."
+     yestext="Install now and restart [APP_NAME]"/>
+  </notification>
+
+  <notification
+ icon="alertmodal.tga"
+ name="DownloadBackgroundDialog"
+ type="alertmodal">
+We have downloaded an update to your [APP_NAME] installation.
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Later..."
+     yestext="Install now and restart [APP_NAME]"/>
+  </notification>
+  
+  <notification
+ icon="alertmodal.tga"
+ name="RequiredUpdateDownloadedVerboseDialog"
+ type="alertmodal">
+We have downloaded a required software update.
+Version [VERSION]
+
+We must restart [APP_NAME] to install the update.
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+  
+  <notification
+ icon="alertmodal.tga"
+ name="RequiredUpdateDownloadedDialog"
+ type="alertmodal">
+We must restart [APP_NAME] to install the update.
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
   </notification>
 
   <notification
diff --git a/indra/newview/skins/default/xui/en/panel_group_invite.xml b/indra/newview/skins/default/xui/en/panel_group_invite.xml
index 15a3191bdfcb48e43ffe7a54274040e3254c4fcc..cd834b61ce61230dd06315d08cc65502696aaac7 100644
--- a/indra/newview/skins/default/xui/en/panel_group_invite.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_invite.xml
@@ -94,7 +94,7 @@
      left_pad="2"
      name="cancel_button"
      top_delta="0"
-     width="70" />
+     width="65" />
 	 <string 
 	 name="GroupInvitation">
 	 Group Invitation
diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
index 1270a21710bfafc03a7b9c1be88f51588cc414e8..61d6cbb2d0e1c0d0936a5a14eb7c6ff9897706f0 100644
--- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
@@ -117,7 +117,7 @@
      name="map_button"
      top_delta="-4"
      left_pad="0"
-     width="60"
+     width="57"
      enabled="false" />
     <text
      type="string"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index b5c584920f89b73dfd95589f6e5dee6df3c288fb..257ed799da3e32f8971dc89f35c01b92e3c5a5a2 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -12,11 +12,7 @@ top="600"
      name="create_account_url">
        http://join.secondlife.com/
 </panel.string>
-<panel.string
-     name="real_url" translate="false">
-       http://secondlife.com/app/login/
-</panel.string>
-    <string name="reg_in_client_url" translate="false">
+<string name="reg_in_client_url" translate="false">
      http://secondlife.eniac15.lindenlab.com/reg-in-client/
 </string>
 <panel.string
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 584bd1ea9d88430cd70301cf557b9570287739c0..901a1257e08104ddb80dfc182ccb6d17666ef796 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -142,7 +142,7 @@
    layout="topleft"
    left="80"
    name="Cache location"
-   top_delta="40"
+   top_delta="20"
    width="300">
     Cache location:
   </text>
@@ -341,20 +341,41 @@
    name="web_proxy_port"
    top_delta="0"
    width="145" />
-
-  <check_box
-    top_delta="2"
-    enabled="true"
-    follows="left|top"
-    height="18"
-    initial_value="true"
-    control_name="UpdaterServiceActive"
-    label="Automatically download and install [APP_NAME] updates"
-    left="30"
-    mouse_opaque="true"
-    name="updater_service_active"
-    radio_style="false"
-    width="400"
-    top_pad="10"/>
-
+  <text
+     type="string"
+     length="1"
+     follows="left|top"
+     height="10"
+     layout="topleft"
+     left="30"
+     name="Software updates:"
+     mouse_opaque="false"
+     top_pad="5"
+     width="300">
+    Software updates:
+  </text>
+  <combo_box
+     control_name="UpdaterServiceSetting"
+     follows="left|top"
+     height="23"
+     layout="topleft"
+     left_delta="50"
+	 top_pad="5"
+     name="updater_service_combobox"
+     width="300">
+        <combo_box.item
+         label="Install automatically"
+         name="Install_automatically"
+         value="3" />
+      <!--
+        <combo_box.item
+         label="Ask before installing"
+         name="Install_ask"
+         value="1" />
+      -->
+        <combo_box.item
+         label="Download and install updates manually"
+         name="Install_manual"
+         value="0" />
+  </combo_box>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index da366f30aef79687850b22b734d8e380f433e25b..f0ce8b849a8c7a0698a4ab078ad826e7636668c3 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -296,6 +296,7 @@
 	<check_box
 		name="media_auto_play_btn"
 		control_name="ParcelMediaAutoPlayEnable"
+		enabled_control="AudioStreamingMedia"
 		value="true"
 		follows="left|bottom|right"
 		height="15"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 51fba470cb0653b6f5f76769dbfd7d5d51da99e7..752bb6ed3a03724cd290966def01c5a62eca4807 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1716,8 +1716,8 @@ integer llGetRegionAgentCount()
 Returns the number of avatars in the region
 	</string>
 	<string name="LSLTipText_llTextBox" translate="false">
-llTextBox(key avatar, string message, integer chat_channel
-Shows a dialog box on the avatar&apos;s screen with the message.
+llTextBox(key avatar, string message, integer chat_channel)
+Shows a window on the avatar&apos;s screen with the message.
 It contains a text box for input, and if entered that text is chatted on chat_channel.
 	</string>
 	<string name="LSLTipText_llGetAgentLanguage" translate="false">
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index 309e9e9ee3694f804b9a3ed8ed8e52a21e57a9f7..9e321db889941a0054cf133c03c2ba66ac8e582a 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -40,6 +40,7 @@
 
 #if defined(LL_WINDOWS)
 #pragma warning(disable: 4355)      // using 'this' in base-class ctor initializer expr
+#pragma warning(disable: 4702)      // disable 'unreachable code' so we can safely use skip().
 #endif
 
 // Constants
@@ -68,6 +69,7 @@ static bool gDisconnectCalled = false;
 
 #include "../llviewerwindow.h"
 void LLViewerWindow::setShowProgress(BOOL show) {}
+LLProgressView * LLViewerWindow::getProgressView(void) const { return 0; }
 
 LLViewerWindow* gViewerWindow;
 
@@ -184,6 +186,41 @@ void LLUIColorTable::saveUserSettings(void)const {}
 const std::string &LLVersionInfo::getChannelAndVersion() { return VIEWERLOGIN_VERSION_CHANNEL; }
 const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; }
 
+//-----------------------------------------------------------------------------
+#include "../llappviewer.h"
+void LLAppViewer::forceQuit(void) {}
+LLAppViewer * LLAppViewer::sInstance = 0;
+
+//-----------------------------------------------------------------------------
+#include "llnotificationsutil.h"
+LLNotificationPtr LLNotificationsUtil::add(const std::string& name, 
+					  const LLSD& substitutions, 
+					  const LLSD& payload, 
+					  boost::function<void (const LLSD&, const LLSD&)> functor) { return LLNotificationPtr((LLNotification*)0); }
+
+
+//-----------------------------------------------------------------------------
+#include "llupdaterservice.h"
+
+std::string const & LLUpdaterService::pumpName(void)
+{
+	static std::string wakka = "wakka wakka wakka";
+	return wakka;
+}
+bool LLUpdaterService::updateReadyToInstall(void) { return false; }
+void LLUpdaterService::initialize(const std::string& protocol_version,
+				const std::string& url, 
+				const std::string& path,
+				const std::string& channel,
+								  const std::string& version) {}
+
+void LLUpdaterService::setCheckPeriod(unsigned int seconds) {}
+void LLUpdaterService::startChecking(bool install_if_ready) {}
+void LLUpdaterService::stopChecking() {}
+bool LLUpdaterService::isChecking() { return false; }
+LLUpdaterService::eUpdaterState LLUpdaterService::getState() { return INITIAL; }
+std::string LLUpdaterService::updatedVersion() { return ""; }
+
 //-----------------------------------------------------------------------------
 #include "llnotifications.h"
 #include "llfloaterreg.h"
@@ -198,6 +235,12 @@ LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key,
 	return NULL;
 }
 
+//----------------------------------------------------------------------------
+#include "../llprogressview.h"
+void LLProgressView::setText(std::string const &){}
+void LLProgressView::setPercent(float){}
+void LLProgressView::setMessage(std::string const &){}
+
 //-----------------------------------------------------------------------------
 // LLNotifications
 class MockNotifications : public LLNotificationsInterface
@@ -435,6 +478,8 @@ namespace tut
     template<> template<>
     void lllogininstance_object::test<3>()
     {
+		skip();
+		
 		set_test_name("Test Mandatory Update User Accepts");
 
 		// Part 1 - Mandatory Update, with User accepts response.
@@ -462,6 +507,8 @@ namespace tut
 	template<> template<>
     void lllogininstance_object::test<4>()
     {
+		skip();
+		
 		set_test_name("Test Mandatory Update User Decline");
 
 		// Test connect with update needed.
diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp
index b976ac5ea900a9010d06b9da08498e1dd8480a8f..acc6e814bc7a196d1f071cc6c79d4a15b9f68123 100644
--- a/indra/newview/tests/llworldmap_test.cpp
+++ b/indra/newview/tests/llworldmap_test.cpp
@@ -25,13 +25,16 @@
  * $/LicenseInfo$
  */
 
-// Precompiled header: almost always required for newview cpp files
-#include "../llviewerprecompiledheaders.h"
-// Class to test
-#include "../llworldmap.h"
 // Dependencies
-#include "../llviewerimagelist.h"
+#include "linden_common.h"
+#include "llapr.h"
+#include "llsingleton.h"
+#include "lltrans.h"
+#include "lluistring.h"
+#include "../llviewertexture.h"
 #include "../llworldmapmessage.h"
+// Class to test
+#include "../llworldmap.h"
 // Tut header
 #include "../test/lltut.h"
 
@@ -44,34 +47,29 @@
 // * A simulator for a class can be implemented here. Please comment and document thoroughly.
 
 // Stub image calls
-LLViewerImageList::LLViewerImageList() { }
-LLViewerImageList::~LLViewerImageList() { }
-LLViewerImageList gImageList;
-LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
-												   BOOL usemipmaps,
-												   BOOL level_immediate,
-												   LLGLint internal_format,
-												   LLGLenum primary_format,
-												   LLHost request_from_host)
-{ return NULL; }
-void LLViewerImage::setBoostLevel(S32 level) { }
-void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { }
+void LLViewerTexture::setBoostLevel(S32 ) { }
+void LLViewerTexture::setAddressMode(LLTexUnit::eTextureAddressMode ) { }
+LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLUUID&, BOOL, LLViewerTexture::EBoostLevel, S8,
+																  LLGLint, LLGLenum, LLHost ) { return NULL; }
 
 // Stub related map calls
 LLWorldMapMessage::LLWorldMapMessage() { }
 LLWorldMapMessage::~LLWorldMapMessage() { }
 void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) { }
 void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) { }
+
 LLWorldMipmap::LLWorldMipmap() { }
 LLWorldMipmap::~LLWorldMipmap() { }
 void LLWorldMipmap::reset() { }
 void LLWorldMipmap::dropBoostLevels() { }
 void LLWorldMipmap::equalizeBoostLevels() { }
-LLPointer<LLViewerImage> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load)
-{ return NULL; }
+LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load) { return NULL; }
 
 // Stub other stuff
-BOOL gPacificDaylightTime;
+std::string LLTrans::getString(const std::string &, const LLStringUtil::format_map_t& ) { return std::string("test_trans"); }
+void LLUIString::updateResult() const { }
+void LLUIString::setArg(const std::string& , const std::string& ) { }
+void LLUIString::assign(const std::string& ) { }
 
 // End Stubbing
 // -------------------------------------------------------------------------------------------
@@ -237,7 +235,7 @@ namespace tut
 		// Test 9 : setLandForSaleImage() / getLandForSaleImage()
 		LLUUID id;
 		mSim->setLandForSaleImage(id);
-		LLPointer<LLViewerImage> image = mSim->getLandForSaleImage();
+		LLPointer<LLViewerFetchedTexture> image = mSim->getLandForSaleImage();
 		ensure("LLSimInfo::getLandForSaleImage() test failed", image.isNull());
 		// Test 10 : isPG()
 		mSim->setAccess(SIM_ACCESS_PG);
@@ -370,7 +368,7 @@ namespace tut
  		}
 		// Test 7 : getObjectsTile()
 		try {
-			LLPointer<LLViewerImage> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);
+			LLPointer<LLViewerFetchedTexture> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);
 			ensure("LLWorldMap::getObjectsTile() failed", image.isNull());
 		} catch (...) {
 			fail("LLWorldMap::getObjectsTile() test failed with exception");
diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp
index 54887ae219c1636b10e876025cef00ac2f9b2ac1..4c0959d1a939205a414fa5a8c7662529a713a07c 100644
--- a/indra/newview/tests/llworldmipmap_test.cpp
+++ b/indra/newview/tests/llworldmipmap_test.cpp
@@ -25,12 +25,12 @@
  * $/LicenseInfo$
  */
 
-// Precompiled header: almost always required for newview cpp files
-#include "../llviewerprecompiledheaders.h"
+// Dependencies
+#include "linden_common.h"
+#include "../llviewertexture.h"
+#include "../llviewercontrol.h"
 // Class to test
 #include "../llworldmipmap.h"
-// Dependencies
-#include "../llviewerimagelist.h"
 // Tut header
 #include "../test/lltut.h"
 
@@ -42,19 +42,14 @@
 // * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
 // * A simulator for a class can be implemented here. Please comment and document thoroughly.
 
-LLViewerImageList::LLViewerImageList() { }
-LLViewerImageList::~LLViewerImageList() { }
-
-LLViewerImageList gImageList;
+void LLViewerTexture::setBoostLevel(S32 ) { }
+LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string&, BOOL, LLViewerTexture::EBoostLevel, S8, 
+																		 LLGLint, LLGLenum, const LLUUID& ) { return NULL; }
 
-LLViewerImage* LLViewerImageList::getImageFromUrl(const std::string& url,
-												   BOOL usemipmaps,
-												   BOOL level_immediate,
-												   LLGLint internal_format,
-												   LLGLenum primary_format, 
-												   const LLUUID& force_id)
-{ return NULL; }
-void LLViewerImage::setBoostLevel(S32 level) { }
+LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name) { }
+LLControlGroup::~LLControlGroup() { }
+std::string LLControlGroup::getString(const std::string& ) { return std::string("test_url"); }
+LLControlGroup gSavedSettings("test_settings");
 
 // End Stubbing
 // -------------------------------------------------------------------------------------------
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 66c78a86c4e8d3ba17e9c0ef952c4f24d4d44b8a..e9eb3c188447b73ed11313459a250a2d05bebada 100644
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -27,6 +27,7 @@ include_directories(
     ${LLXML_INCLUDE_DIRS}
     ${LSCRIPT_INCLUDE_DIRS}
     ${GOOGLEMOCK_INCLUDE_DIRS}
+    ${TUT_INCLUDE_DIR}
     )
 
 set(test_SOURCE_FILES
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
index c17a50e24245aeb3d5846ab5fb569696b744dd7d..e88d1bf811d726056cf63c03ccb5a1910f20b3a4 100644
--- a/indra/viewer_components/updater/llupdatedownloader.cpp
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -24,17 +24,20 @@
  */
 
 #include "linden_common.h"
+
+#include "llupdatedownloader.h"
+
 #include <stdexcept>
 #include <boost/format.hpp>
 #include <boost/lexical_cast.hpp>
 #include <curl/curl.h>
 #include "lldir.h"
+#include "llevents.h"
 #include "llfile.h"
 #include "llmd5.h"
 #include "llsd.h"
 #include "llsdserialize.h"
 #include "llthread.h"
-#include "llupdatedownloader.h"
 #include "llupdaterservice.h"
 
 
@@ -45,18 +48,25 @@ class LLUpdateDownloader::Implementation:
 	Implementation(LLUpdateDownloader::Client & client);
 	~Implementation();
 	void cancel(void);
-	void download(LLURI const & uri, std::string const & hash);
+	void download(LLURI const & uri,
+				  std::string const & hash,
+				  std::string const & updateVersion,
+				  bool required);
 	bool isDownloading(void);
 	size_t onHeader(void * header, size_t size);
 	size_t onBody(void * header, size_t size);
+	int onProgress(double downloadSize, double bytesDownloaded);
 	void resume(void);
+	void setBandwidthLimit(U64 bytesPerSecond);
 	
 private:
+	curl_off_t mBandwidthLimit;
 	bool mCancelled;
 	LLUpdateDownloader::Client & mClient;
 	CURL * mCurl;
 	LLSD mDownloadData;
 	llofstream mDownloadStream;
+	unsigned char mDownloadPercent;
 	std::string mDownloadRecordPath;
 	curl_slist * mHeaderList;
 	
@@ -113,9 +123,12 @@ void LLUpdateDownloader::cancel(void)
 }
 
 
-void LLUpdateDownloader::download(LLURI const & uri, std::string const & hash)
+void LLUpdateDownloader::download(LLURI const & uri,
+								  std::string const & hash,
+								  std::string const & updateVersion,
+								  bool required)
 {
-	mImplementation->download(uri, hash);
+	mImplementation->download(uri, hash, updateVersion, required);
 }
 
 
@@ -131,6 +144,12 @@ void LLUpdateDownloader::resume(void)
 }
 
 
+void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond)
+{
+	mImplementation->setBandwidthLimit(bytesPerSecond);
+}
+
+
 
 // LLUpdateDownloader::Implementation
 //-----------------------------------------------------------------------------
@@ -149,14 +168,27 @@ namespace {
 		size_t bytes = blockSize * blocks;
 		return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onHeader(data, bytes);
 	}
+
+
+	int progress_callback(void * downloader,
+						  double dowloadTotal,
+						  double downloadNow,
+						  double uploadTotal,
+						  double uploadNow)
+	{
+		return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->
+			onProgress(dowloadTotal, downloadNow);
+	}
 }
 
 
 LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client):
 	LLThread("LLUpdateDownloader"),
+	mBandwidthLimit(0),
 	mCancelled(false),
 	mClient(client),
 	mCurl(0),
+	mDownloadPercent(0),
 	mHeaderList(0)
 {
 	CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case.
@@ -182,12 +214,17 @@ void LLUpdateDownloader::Implementation::cancel(void)
 }
 	
 
-void LLUpdateDownloader::Implementation::download(LLURI const & uri, std::string const & hash)
+void LLUpdateDownloader::Implementation::download(LLURI const & uri,
+												  std::string const & hash,
+												  std::string const & updateVersion,
+												  bool required)
 {
 	if(isDownloading()) mClient.downloadError("download in progress");
 
 	mDownloadRecordPath = downloadMarkerPath();
 	mDownloadData = LLSD();
+	mDownloadData["required"] = required;
+	mDownloadData["update_version"] = updateVersion;
 	try {
 		startDownloading(uri, hash);
 	} catch(DownloadError const & e) {
@@ -233,12 +270,18 @@ void LLUpdateDownloader::Implementation::resume(void)
 				resumeDownloading(fileStatus.st_size);
 			} else if(!validateDownload()) {
 				LLFile::remove(filePath);
-				download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString());
+				download(LLURI(mDownloadData["url"].asString()), 
+						 mDownloadData["hash"].asString(),
+						 mDownloadData["update_version"].asString(),
+						 mDownloadData["required"].asBoolean());
 			} else {
 				mClient.downloadComplete(mDownloadData);
 			}
 		} else {
-			download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString());
+			download(LLURI(mDownloadData["url"].asString()), 
+					 mDownloadData["hash"].asString(),
+					 mDownloadData["update_version"].asString(),
+					 mDownloadData["required"].asBoolean());
 		}
 	} catch(DownloadError & e) {
 		mClient.downloadError(e.what());
@@ -246,6 +289,20 @@ void LLUpdateDownloader::Implementation::resume(void)
 }
 
 
+void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond)
+{
+	if((mBandwidthLimit != bytesPerSecond) && isDownloading() && !mDownloadData["required"].asBoolean()) {
+		llassert(mCurl != 0);
+		mBandwidthLimit = bytesPerSecond;
+		CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
+		if(code != CURLE_OK) LL_WARNS("UpdateDownload") << 
+			"unable to change dowload bandwidth" << LL_ENDL;
+	} else {
+		mBandwidthLimit = bytesPerSecond;
+	}
+}
+
+
 size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)
 {
 	char const * headerPtr = reinterpret_cast<const char *> (buffer);
@@ -290,6 +347,30 @@ size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size)
 }
 
 
+int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double bytesDownloaded)
+{
+	int downloadPercent = static_cast<int>(100. * (bytesDownloaded / downloadSize));
+	if(downloadPercent > mDownloadPercent) {
+		mDownloadPercent = downloadPercent;
+		
+		LLSD event;
+		event["pump"] = LLUpdaterService::pumpName();
+		LLSD payload;
+		payload["type"] = LLSD(LLUpdaterService::PROGRESS);
+		payload["download_size"] = downloadSize;
+		payload["bytes_downloaded"] = bytesDownloaded;
+		event["payload"] = payload;
+		LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+		
+		LL_INFOS("UpdateDownload") << "progress event " << payload << LL_ENDL;
+	} else {
+		; // Keep events to a reasonalbe number.
+	}
+	
+	return 0;
+}
+
+
 void LLUpdateDownloader::Implementation::run(void)
 {
 	CURLcode code = curl_easy_perform(mCurl);
@@ -343,6 +424,14 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u
 	}
 	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true));
 	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str()));
+	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback));
+	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this));
+	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false));
+	// if it's a required update set the bandwidth limit to 0 (unlimited)
+	curl_off_t limit = mDownloadData["required"].asBoolean() ? 0 : mBandwidthLimit;
+	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, limit));
+	
+	mDownloadPercent = 0;
 }
 
 
diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h
index 1b3d7480fd1785747b5d5f6e5509667a03f791ac..0d635640cf2e1d6734f6745dbe51e5b132c94309 100644
--- a/indra/viewer_components/updater/llupdatedownloader.h
+++ b/indra/viewer_components/updater/llupdatedownloader.h
@@ -52,7 +52,10 @@ class LLUpdateDownloader
 	void cancel(void);
 	
 	// Start a new download.
-	void download(LLURI const & uri, std::string const & hash);
+	void download(LLURI const & uri,
+				  std::string const & hash, 
+				  std::string const & updateVersion,
+				  bool required=false);
 	
 	// Returns true if a download is in progress.
 	bool isDownloading(void);
@@ -60,6 +63,9 @@ class LLUpdateDownloader
 	// Resume a partial download.
 	void resume(void);
 	
+	// Set a limit on the dowload rate.
+	void setBandwidthLimit(U64 bytesPerSecond);
+	
 private:
 	boost::shared_ptr<Implementation> mImplementation;
 };
@@ -76,6 +82,7 @@ class LLUpdateDownloader::Client {
 	// url - source (remote) location
 	// hash - the md5 sum that should match the installer file.
 	// path - destination (local) location
+	// required - boolean indicating if this is a required update.
 	// size - the size of the installer in bytes
 	virtual void downloadComplete(LLSD const & data) = 0;
 	
diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp
index 6e69bcf28b8b9d201b701709855dd1e431162b73..d450c068ade8b4bc0c481505a8057a379ec83701 100644
--- a/indra/viewer_components/updater/llupdateinstaller.cpp
+++ b/indra/viewer_components/updater/llupdateinstaller.cpp
@@ -31,6 +31,12 @@
 #include "lldir.h"
 
 
+#if defined(LL_WINDOWS)
+#pragma warning(disable: 4702)      // disable 'unreachable code' so we can use lexical_cast (really!).
+#endif
+#include <boost/lexical_cast.hpp>
+
+
 namespace {
 	class RelocateError {};
 	
@@ -47,7 +53,10 @@ namespace {
 }
 
 
-int ll_install_update(std::string const & script, std::string const & updatePath, LLInstallScriptMode mode)
+int ll_install_update(std::string const & script,
+					  std::string const & updatePath,
+					  bool required,
+					  LLInstallScriptMode mode)
 {
 	std::string actualScriptPath;
 	switch(mode) {
@@ -73,6 +82,7 @@ int ll_install_update(std::string const & script, std::string const & updatePath
 	launcher.setExecutable(actualScriptPath);
 	launcher.addArgument(updatePath);
 	launcher.addArgument(ll_install_failed_marker_path().c_str());
+	launcher.addArgument(boost::lexical_cast<std::string>(required));
 	int result = launcher.launch();
 	launcher.orphan();
 	
diff --git a/indra/viewer_components/updater/llupdateinstaller.h b/indra/viewer_components/updater/llupdateinstaller.h
index 6ce08ce6fa51ece998fc77469b473c2fd3f3742d..fe5b1d19b52f2fb7b0651f5ec21acd21efac4ebb 100644
--- a/indra/viewer_components/updater/llupdateinstaller.h
+++ b/indra/viewer_components/updater/llupdateinstaller.h
@@ -42,9 +42,10 @@ enum LLInstallScriptMode {
 // that the current application terminate once this function is called.
 //
 int ll_install_update(
-					   std::string const & script, // Script to execute.
-					   std::string const & updatePath, // Path to update file.
-					   LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp?
+					  std::string const & script, // Script to execute.
+					  std::string const & updatePath, // Path to update file.
+					  bool required, // Is the update required.
+					  LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp?
 
 
 //
diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
index cc60eaead27a9ba49e5804bce09f4e415c277fb5..aa4983a3b6634984df873f706787e7a4a1c128d9 100644
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -25,10 +25,11 @@
 
 #include "linden_common.h"
 
+#include "llupdaterservice.h"
+
 #include "llupdatedownloader.h"
 #include "llevents.h"
 #include "lltimer.h"
-#include "llupdaterservice.h"
 #include "llupdatechecker.h"
 #include "llupdateinstaller.h"
 #include "llversionviewer.h"
@@ -98,6 +99,8 @@ class LLUpdaterServiceImpl :
 
 	LLUpdaterService::app_exit_callback_t mAppExitCallback;
 	
+	LLUpdaterService::eUpdaterState mState;
+	
 	LOG_CLASS(LLUpdaterServiceImpl);
 	
 public:
@@ -111,12 +114,15 @@ class LLUpdaterServiceImpl :
 				   const std::string& version);
 	
 	void setCheckPeriod(unsigned int seconds);
+	void setBandwidthLimit(U64 bytesPerSecond);
 
 	void startChecking(bool install_if_ready);
 	void stopChecking();
 	bool isChecking();
+	LLUpdaterService::eUpdaterState getState();
 	
 	void setAppExitCallback(LLUpdaterService::app_exit_callback_t aecb) { mAppExitCallback = aecb;}
+	std::string updatedVersion(void);
 
 	bool checkForInstall(bool launchInstaller); // Test if a local install is ready.
 	bool checkForResume(); // Test for resumeable d/l.
@@ -138,7 +144,10 @@ class LLUpdaterServiceImpl :
 	bool onMainLoop(LLSD const & event);
 
 private:
+	std::string mNewVersion;
+	
 	void restartTimer(unsigned int seconds);
+	void setState(LLUpdaterService::eUpdaterState state);
 	void stopTimer();
 };
 
@@ -149,7 +158,8 @@ LLUpdaterServiceImpl::LLUpdaterServiceImpl() :
 	mIsDownloading(false),
 	mCheckPeriod(0),
 	mUpdateChecker(*this),
-	mUpdateDownloader(*this)
+	mUpdateDownloader(*this),
+	mState(LLUpdaterService::INITIAL)
 {
 }
 
@@ -183,6 +193,11 @@ void LLUpdaterServiceImpl::setCheckPeriod(unsigned int seconds)
 	mCheckPeriod = seconds;
 }
 
+void LLUpdaterServiceImpl::setBandwidthLimit(U64 bytesPerSecond)
+{
+	mUpdateDownloader.setBandwidthLimit(bytesPerSecond);
+}
+
 void LLUpdaterServiceImpl::startChecking(bool install_if_ready)
 {
 	if(mUrl.empty() || mChannel.empty() || mVersion.empty())
@@ -201,10 +216,16 @@ void LLUpdaterServiceImpl::startChecking(bool install_if_ready)
 
 		if(!mIsDownloading)
 		{
+			setState(LLUpdaterService::CHECKING_FOR_UPDATE);
+			
 			// Checking can only occur during the mainloop.
 			// reset the timer to 0 so that the next mainloop event 
 			// triggers a check;
 			restartTimer(0); 
+		} 
+		else
+		{
+			setState(LLUpdaterService::DOWNLOADING);
 		}
 	}
 }
@@ -222,6 +243,8 @@ void LLUpdaterServiceImpl::stopChecking()
         mUpdateDownloader.cancel();
 		mIsDownloading = false;
     }
+	
+	setState(LLUpdaterService::TERMINAL);
 }
 
 bool LLUpdaterServiceImpl::isChecking()
@@ -229,6 +252,16 @@ bool LLUpdaterServiceImpl::isChecking()
 	return mIsChecking;
 }
 
+LLUpdaterService::eUpdaterState LLUpdaterServiceImpl::getState()
+{
+	return mState;
+}
+
+std::string LLUpdaterServiceImpl::updatedVersion(void)
+{
+	return mNewVersion;
+}
+
 bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller)
 {
 	bool foundInstall = false; // return true if install is found.
@@ -266,10 +299,13 @@ bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller)
 		{
 			if(launchInstaller)
 			{
+				setState(LLUpdaterService::INSTALLING);
+				
 				LLFile::remove(update_marker_path());
 
 				int result = ll_install_update(install_script_path(),
 											   update_info["path"].asString(),
+											   update_info["required"].asBoolean(),
 											   install_script_mode());	
 				
 				if((result == 0) && mAppExitCallback)
@@ -304,6 +340,7 @@ bool LLUpdaterServiceImpl::checkForResume()
 			if(download_info["current_version"].asString() == ll_get_version())
 			{
 				mIsDownloading = true;
+				mNewVersion = download_info["update_version"].asString();
 				mUpdateDownloader.resume();
 				result = true;
 			}
@@ -333,8 +370,11 @@ void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion,
 										  std::string const & hash)
 {
 	stopTimer();
+	mNewVersion = newVersion;
 	mIsDownloading = true;
-	mUpdateDownloader.download(uri, hash);
+	mUpdateDownloader.download(uri, hash, newVersion, false);
+	
+	setState(LLUpdaterService::DOWNLOADING);
 }
 
 void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
@@ -342,8 +382,11 @@ void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
 										  std::string const & hash)
 {
 	stopTimer();
+	mNewVersion = newVersion;
 	mIsDownloading = true;
-	mUpdateDownloader.download(uri, hash);
+	mUpdateDownloader.download(uri, hash, newVersion, true);
+	
+	setState(LLUpdaterService::DOWNLOADING);
 }
 
 void LLUpdaterServiceImpl::upToDate(void)
@@ -352,6 +395,8 @@ void LLUpdaterServiceImpl::upToDate(void)
 	{
 		restartTimer(mCheckPeriod);
 	}
+	
+	setState(LLUpdaterService::UP_TO_DATE);
 }
 
 void LLUpdaterServiceImpl::downloadComplete(LLSD const & data) 
@@ -367,8 +412,12 @@ void LLUpdaterServiceImpl::downloadComplete(LLSD const & data)
 	event["pump"] = LLUpdaterService::pumpName();
 	LLSD payload;
 	payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_COMPLETE);
+	payload["required"] = data["required"];
+	payload["version"] = mNewVersion;
 	event["payload"] = payload;
 	LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+	
+	setState(LLUpdaterService::TERMINAL);
 }
 
 void LLUpdaterServiceImpl::downloadError(std::string const & message) 
@@ -390,6 +439,8 @@ void LLUpdaterServiceImpl::downloadError(std::string const & message)
 	payload["message"] = message;
 	event["payload"] = payload;
 	LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+
+	setState(LLUpdaterService::FAILURE);
 }
 
 void LLUpdaterServiceImpl::restartTimer(unsigned int seconds)
@@ -402,6 +453,28 @@ void LLUpdaterServiceImpl::restartTimer(unsigned int seconds)
 		sListenerName, boost::bind(&LLUpdaterServiceImpl::onMainLoop, this, _1));
 }
 
+void LLUpdaterServiceImpl::setState(LLUpdaterService::eUpdaterState state)
+{
+	if(state != mState)
+	{
+		mState = state;
+		
+		LLSD event;
+		event["pump"] = LLUpdaterService::pumpName();
+		LLSD payload;
+		payload["type"] = LLSD(LLUpdaterService::STATE_CHANGE);
+		payload["state"] = state;
+		event["payload"] = payload;
+		LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+		
+		LL_INFOS("UpdaterService") << "setting state to " << state << LL_ENDL;
+	}
+	else 
+	{
+		; // State unchanged; noop.
+	}
+}
+
 void LLUpdaterServiceImpl::stopTimer()
 {
 	mTimer.stop();
@@ -417,6 +490,12 @@ bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event)
 		// Check for failed install.
 		if(LLFile::isfile(ll_install_failed_marker_path()))
 		{
+			int requiredValue = 0; 
+			{
+				llifstream stream(ll_install_failed_marker_path());
+				stream >> requiredValue;
+				if(stream.fail()) requiredValue = 0;
+			}
 			// TODO: notify the user.
 			llinfos << "found marker " << ll_install_failed_marker_path() << llendl;
 			llinfos << "last install attempt failed" << llendl;
@@ -424,11 +503,15 @@ bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event)
 			
 			LLSD event;
 			event["type"] = LLSD(LLUpdaterService::INSTALL_ERROR);
+			event["required"] = LLSD(requiredValue);
 			LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).post(event);
+			
+			setState(LLUpdaterService::TERMINAL);
 		}
 		else
 		{
 			mUpdateChecker.check(mProtocolVersion, mUrl, mPath, mChannel, mVersion);
+			setState(LLUpdaterService::CHECKING_FOR_UPDATE);
 		}
 	} 
 	else 
@@ -449,6 +532,11 @@ std::string const & LLUpdaterService::pumpName(void)
 	return name;
 }
 
+bool LLUpdaterService::updateReadyToInstall(void)
+{
+	return LLFile::isfile(update_marker_path());
+}
+
 LLUpdaterService::LLUpdaterService()
 {
 	if(gUpdater.expired())
@@ -480,6 +568,11 @@ void LLUpdaterService::setCheckPeriod(unsigned int seconds)
 {
 	mImpl->setCheckPeriod(seconds);
 }
+
+void LLUpdaterService::setBandwidthLimit(U64 bytesPerSecond)
+{
+	mImpl->setBandwidthLimit(bytesPerSecond);
+}
 	
 void LLUpdaterService::startChecking(bool install_if_ready)
 {
@@ -496,11 +589,21 @@ bool LLUpdaterService::isChecking()
 	return mImpl->isChecking();
 }
 
+LLUpdaterService::eUpdaterState LLUpdaterService::getState()
+{
+	return mImpl->getState();
+}
+
 void LLUpdaterService::setImplAppExitCallback(LLUpdaterService::app_exit_callback_t aecb)
 {
 	return mImpl->setAppExitCallback(aecb);
 }
 
+std::string LLUpdaterService::updatedVersion(void)
+{
+	return mImpl->updatedVersion();
+}
+
 
 std::string const & ll_get_version(void) {
 	static std::string version("");
diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h
index 752a6f834b4f93a7204a9e8573d30812f9d7de90..421481bc43d0adfe44ad6d6bb12dbd8bc22e2d93 100644
--- a/indra/viewer_components/updater/llupdaterservice.h
+++ b/indra/viewer_components/updater/llupdaterservice.h
@@ -43,12 +43,27 @@ class LLUpdaterService
 	// Name of the event pump through which update events will be delivered.
 	static std::string const & pumpName(void);
 	
+	// Returns true if an update has been completely downloaded and is now ready to install.
+	static bool updateReadyToInstall(void);
+	
 	// Type codes for events posted by this service.  Stored the event's 'type' element.
-	enum eUpdateEvent {
+	enum eUpdaterEvent {
 		INVALID,
 		DOWNLOAD_COMPLETE,
 		DOWNLOAD_ERROR,
-		INSTALL_ERROR
+		INSTALL_ERROR,
+		PROGRESS,
+		STATE_CHANGE
+	};
+	
+	enum eUpdaterState {
+		INITIAL,
+		CHECKING_FOR_UPDATE,
+		DOWNLOADING,
+		INSTALLING,
+		UP_TO_DATE,
+		TERMINAL,
+		FAILURE
 	};
 
 	LLUpdaterService();
@@ -61,10 +76,12 @@ class LLUpdaterService
 				    const std::string& version);
 
 	void setCheckPeriod(unsigned int seconds);
+	void setBandwidthLimit(U64 bytesPerSecond);
 	
 	void startChecking(bool install_if_ready = false);
 	void stopChecking();
 	bool isChecking();
+	eUpdaterState getState();
 
 	typedef boost::function<void (void)> app_exit_callback_t;
 	template <typename F>
@@ -73,6 +90,11 @@ class LLUpdaterService
 		app_exit_callback_t aecb = callable;
 		setImplAppExitCallback(aecb);
 	}
+	
+	// If an update is or has been downloaded, this method will return the
+	// version string for that update.  An empty string will be returned
+	// otherwise.
+	std::string updatedVersion(void);
 
 private:
 	boost::shared_ptr<LLUpdaterServiceImpl> mImpl;
diff --git a/indra/viewer_components/updater/scripts/darwin/update_install b/indra/viewer_components/updater/scripts/darwin/update_install
index 9df382f119122b852ba139e91aafc5fe37e522ce..6a95f96d86f520e5543ac3925544d55b7204716a 100644
--- a/indra/viewer_components/updater/scripts/darwin/update_install
+++ b/indra/viewer_components/updater/scripts/darwin/update_install
@@ -6,5 +6,5 @@
 #
 
 cd "$(dirname "$0")"
-../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer 2" -marker "$2" &
+(../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer 2"; if [ $? -ne 0 ]; then echo $3 >> "$2"; fi;) &
 exit 0
diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install
index a271926e25d1bd76008bebfa65cd8ff42e6a30d0..88451340eca36ace15d01f845bba765b9933a7aa 100644
--- a/indra/viewer_components/updater/scripts/linux/update_install
+++ b/indra/viewer_components/updater/scripts/linux/update_install
@@ -4,7 +4,7 @@ export LD_LIBRARY_PATH="$INSTALL_DIR/lib"
 bin/linux-updater.bin --file "$1" --dest "$INSTALL_DIR" --name "Second Life Viewer 2" --stringsdir "$INSTALL_DIR/skins/default/xui/en" --stringsfile "strings.xml"
 
 if [ $? -ne 0 ]
-   then touch "$2"
+   then echo $3 >> "$2"
 fi
 
 rm -f "$1"
diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat
index 42e148a707e11433798ac33e3d2e56e86acac394..96687226a8d3d243cdb268707a4eecefbb1d33e1 100644
--- a/indra/viewer_components/updater/scripts/windows/update_install.bat
+++ b/indra/viewer_components/updater/scripts/windows/update_install.bat
@@ -1,3 +1,3 @@
 start /WAIT %1 /SKIP_DIALOGS
-IF ERRORLEVEL 1 ECHO %ERRORLEVEL% > %2
+IF ERRORLEVEL 1 ECHO %3 > %2
 DEL %1
diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
index 04ed4e63640b24aab81ef74db2960cfe5dc7cbdb..5f8cd28f2976501f23f6eef2360ce4c228f6d215 100644
--- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
+++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
@@ -48,7 +48,7 @@ void LLUpdateChecker::check(std::string const & protocolVersion, std::string con
 								  std::string const & servicePath, std::string channel, std::string version)
 {}
 LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
-void LLUpdateDownloader::download(LLURI const & , std::string const &){}
+void LLUpdateDownloader::download(LLURI const & , std::string const &, std::string const &, bool){}
 
 class LLDir_Mock : public LLDir
 {
@@ -101,8 +101,9 @@ std::string LLUpdateDownloader::downloadMarkerPath(void)
 
 void LLUpdateDownloader::resume(void) {}
 void LLUpdateDownloader::cancel(void) {}
+void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {}
 
-int ll_install_update(std::string const &, std::string const &, LLInstallScriptMode)
+int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode)
 {
 	return 0;
 }
diff --git a/scripts/install.py b/scripts/install.py
index c2adf4d0a27ce79b9edfb4a28ea594141a13039b..d3bdf52283778899aab8476a71862f012389bb20 100755
--- a/scripts/install.py
+++ b/scripts/install.py
@@ -486,7 +486,7 @@ def _uninstall(self, installables):
         for filename in remove_file_list:
             print "rm",filename
             if not self._dryrun:
-                if os.path.exists(filename):
+                if os.path.lexists(filename):
                     remove_dir_set.add(os.path.dirname(filename))
                     try:
                         os.remove(filename)