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/indra/CMakeLists.txt b/indra/CMakeLists.txt
index d01e1869b6983dfbb1116499330bdbb783504e54..6d17a6f402efbf917fe8a24a51fa25fe70fbefb3 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -43,6 +43,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
 add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
 add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
+add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
 add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
 add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
@@ -53,10 +54,6 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llvfs)
 add_subdirectory(${LIBS_OPEN_PREFIX}llwindow)
 add_subdirectory(${LIBS_OPEN_PREFIX}llxml)
 
-if (EXISTS ${LIBS_CLOSED_DIR}llkdu)
-  add_subdirectory(${LIBS_CLOSED_PREFIX}llkdu)
-endif (EXISTS ${LIBS_CLOSED_DIR}llkdu)
-
 add_subdirectory(${LIBS_OPEN_PREFIX}lscript)
 
 if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
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/CURL.cmake b/indra/cmake/CURL.cmake
index 6e5fed4d5285e473d121d367c4da18ee15f76b18..9aba08e573df9bc636cdc6cd59f841f12228c72f 100644
--- a/indra/cmake/CURL.cmake
+++ b/indra/cmake/CURL.cmake
@@ -10,10 +10,10 @@ else (STANDALONE)
   use_prebuilt_binary(curl)
   if (WINDOWS)
     set(CURL_LIBRARIES 
-    debug libcurld
-    optimized libcurl)
+    debug libcurld.lib
+    optimized libcurl.lib)
   else (WINDOWS)
-    set(CURL_LIBRARIES curl)
+    set(CURL_LIBRARIES libcurl.a)
   endif (WINDOWS)
   set(CURL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 endif (STANDALONE)
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index e852cf463c03ed0cb07e3e0b9ed4b0ef5d386e21..176ae9787e5523abcc07c89b1465b6a9d25b3f4c 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -60,22 +60,6 @@ if(WINDOWS)
       set(release_files ${release_files} fmod.dll)
     endif (FMOD)
 
-    #*******************************
-    # LLKDU
-    set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
-    if(NOT EXISTS ${internal_llkdu_path})
-        if (EXISTS "${debug_src_dir}/llkdu.dll")
-            set(debug_llkdu_src "${debug_src_dir}/llkdu.dll")
-            set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/llkdu.dll")
-        endif (EXISTS "${debug_src_dir}/llkdu.dll")
-
-        if (EXISTS "${release_src_dir}/llkdu.dll")
-            set(release_llkdu_src "${release_src_dir}/llkdu.dll")
-            set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/llkdu.dll")
-            set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/llkdu.dll")
-        endif (EXISTS "${release_src_dir}/llkdu.dll")
-    endif (NOT EXISTS ${internal_llkdu_path})
-
 #*******************************
 # Copy MS C runtime dlls, required for packaging.
 # *TODO - Adapt this to support VC9
@@ -174,21 +158,6 @@ elseif(DARWIN)
     # fmod is statically linked on darwin
     set(fmod_files "")
 
-    #*******************************
-    # LLKDU
-    set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
-    if(NOT EXISTS ${internal_llkdu_path})
-        if (EXISTS "${debug_src_dir}/libllkdu.dylib")
-            set(debug_llkdu_src "${debug_src_dir}/libllkdu.dylib")
-            set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/libllkdu.dylib")
-        endif (EXISTS "${debug_src_dir}/libllkdu.dylib")
-
-        if (EXISTS "${release_src_dir}/libllkdu.dylib")
-            set(release_llkdu_src "${release_src_dir}/libllkdu.dylib")
-            set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/libllkdu.dylib")
-            set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/libllkdu.dylib")
-        endif (EXISTS "${release_src_dir}/libllkdu.dylib")
-    endif (NOT EXISTS ${internal_llkdu_path})
 elseif(LINUX)
     # linux is weird, multiple side by side configurations aren't supported
     # and we don't seem to have any debug shared libs built yet anyways...
@@ -242,21 +211,6 @@ elseif(LINUX)
       set(release_files ${release_files} "libfmod-3.75.so")
     endif (FMOD)
 
-    #*******************************
-    # LLKDU
-    set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
-    if(NOT EXISTS ${internal_llkdu_path})
-        if (EXISTS "${debug_src_dir}/libllkdu.so")
-            set(debug_llkdu_src "${debug_src_dir}/libllkdu.so")
-            set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/libllkdu.so")
-        endif (EXISTS "${debug_src_dir}/libllkdu.so")
-
-        if (EXISTS "${release_src_dir}/libllkdu.so")
-            set(release_llkdu_src "${release_src_dir}/libllkdu.so")
-            set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/libllkdu.so")
-            set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/libllkdu.so")
-        endif (EXISTS "${release_src_dir}/libllkdu.so")
-    endif(NOT EXISTS ${internal_llkdu_path})
 else(WINDOWS)
     message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...")
     set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux")
@@ -334,40 +288,29 @@ copy_if_different(
     )
 set(third_party_targets ${third_party_targets} ${out_targets})
 
-#*******************************
-# LLKDU
-set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
-if(NOT EXISTS ${internal_llkdu_path})
-    if (EXISTS "${debug_llkdu_src}")
-        ADD_CUSTOM_COMMAND(
-            OUTPUT  ${debug_llkdu_dst}
-            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${debug_llkdu_src} ${debug_llkdu_dst}
-            DEPENDS ${debug_llkdu_src}
-            COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_DEBUG}"
-            )
-        set(third_party_targets ${third_party_targets} $} ${debug_llkdu_dst})
-    endif (EXISTS "${debug_llkdu_src}")
-
-    if (EXISTS "${release_llkdu_src}")
-        ADD_CUSTOM_COMMAND(
-            OUTPUT  ${release_llkdu_dst}
-            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${release_llkdu_src} ${release_llkdu_dst}
-            DEPENDS ${release_llkdu_src}
-            COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_RELEASE}"
-            )
-        set(third_party_targets ${third_party_targets} ${release_llkdu_dst})
-
-        ADD_CUSTOM_COMMAND(
-            OUTPUT  ${relwithdebinfo_llkdu_dst}
-            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${release_llkdu_src} ${relwithdebinfo_llkdu_dst}
-            DEPENDS ${release_llkdu_src}
-            COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}"
-            )
-        set(third_party_targets ${third_party_targets} ${relwithdebinfo_llkdu_dst})
-    endif (EXISTS "${release_llkdu_src}")
-
-endif (NOT EXISTS ${internal_llkdu_path})
-
+if (FMOD_SDK_DIR)
+    copy_if_different(
+        ${FMOD_SDK_DIR} 
+        "${CMAKE_CURRENT_BINARY_DIR}/Debug"
+        out_targets 
+        ${fmod_files}
+        )
+    set(all_targets ${all_targets} ${out_targets})
+    copy_if_different(
+        ${FMOD_SDK_DIR} 
+        "${CMAKE_CURRENT_BINARY_DIR}/Release"
+        out_targets 
+        ${fmod_files}
+        )
+    set(all_targets ${all_targets} ${out_targets})
+    copy_if_different(
+        ${FMOD_SDK_DIR} 
+        "${CMAKE_CURRENT_BINARY_DIR}/RelWithDbgInfo"
+        out_targets 
+        ${fmod_files}
+        )
+    set(all_targets ${all_targets} ${out_targets})
+endif (FMOD_SDK_DIR)
 
 if(NOT STANDALONE)
   add_custom_target(
diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake
index 27c8ada686ea51ee75ec5d94926a879a04588fd7..f5cbad03a6174607ae5e7f0d29e21b5181d3812c 100644
--- a/indra/cmake/LLKDU.cmake
+++ b/indra/cmake/LLKDU.cmake
@@ -1,7 +1,20 @@
 # -*- cmake -*-
 include(Prebuilt)
 
+# USE_KDU can be set when launching cmake or develop.py as an option using the argument -DUSE_KDU:BOOL=ON
+# When building using proprietary binaries though (i.e. having access to LL private servers), we always build with KDU
 if (INSTALL_PROPRIETARY AND NOT STANDALONE)
-  use_prebuilt_binary(kdu)
-  set(LLKDU_LIBRARY llkdu)
+  set(USE_KDU ON)
 endif (INSTALL_PROPRIETARY AND NOT STANDALONE)
+
+if (USE_KDU)
+  use_prebuilt_binary(kdu)
+  if (WINDOWS)
+    set(KDU_LIBRARY kdu.lib)
+  else (WINDOWS)
+    set(KDU_LIBRARY libkdu.a)
+  endif (WINDOWS)
+  set(KDU_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/kdu)
+  set(LLKDU_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llkdu)
+  set(LLKDU_LIBRARIES llkdu)
+endif (USE_KDU)
diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt
index 452d37d3be7c6350efc9307be5489131b107328e..e0772e55ca35990697e0d7d103297eb0f665d8ad 100644
--- a/indra/integration_tests/llui_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llui_libtest/CMakeLists.txt
@@ -10,6 +10,7 @@ include(00-Common)
 include(LLCommon)
 include(LLImage)
 include(LLImageJ2COJ)   # ugh, needed for images
+include(LLKDU)
 include(LLMath)
 include(LLMessage)
 include(LLRender)
@@ -71,6 +72,11 @@ endif (DARWIN)
 target_link_libraries(llui_libtest
     llui
     llmessage
+    ${LLRENDER_LIBRARIES}
+    ${LLIMAGE_LIBRARIES}
+    ${LLKDU_LIBRARIES}
+    ${KDU_LIBRARY}
+    ${LLIMAGEJ2COJ_LIBRARIES}
     ${OS_LIBRARIES}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     )
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 a69621a57b3c53e1dc576427287c540b8fbd2e09..6834267d4b13550cefd1ef7c7fe535bb7a99b2b1 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -57,7 +57,6 @@ add_library (llimage ${llimage_SOURCE_FILES})
 # Sort by high-level to low-level
 target_link_libraries(llimage
     llcommon
-    llimagej2coj        # *HACK: In theory a noop for KDU builds?
     ${JPEG_LIBRARIES}
     ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 5c33b675ca3a64221ee46f48cb5869f14615e5e7..b46a99e03034160b3598e24427f3072f1f8fc692 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -52,13 +52,11 @@ LLMutex* LLImage::sMutex = NULL;
 void LLImage::initClass()
 {
 	sMutex = new LLMutex(NULL);
-	LLImageJ2C::openDSO();
 }
 
 //static
 void LLImage::cleanupClass()
 {
-	LLImageJ2C::closeDSO();
 	delete sMutex;
 	sMutex = NULL;
 }
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index d005aaf29fd7ca3359dd9d7efd6884a952b799aa..cb2a85fa917afa683954f342d45c488a3e284ec4 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -24,9 +24,6 @@
  */
 #include "linden_common.h"
 
-#include "apr_pools.h"
-#include "apr_dso.h"
-
 #include "lldir.h"
 #include "llimagej2c.h"
 #include "llmemtype.h"
@@ -37,18 +34,10 @@ typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)();
 typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*);
 typedef const char* (*EngineInfoLLImageJ2CFunction)();
 
-//some "private static" variables so we only attempt to load
-//dynamic libaries once
-CreateLLImageJ2CFunction j2cimpl_create_func;
-DestroyLLImageJ2CFunction j2cimpl_destroy_func;
-EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func;
-apr_pool_t *j2cimpl_dso_memory_pool;
-apr_dso_handle_t *j2cimpl_dso_handle;
-
-//Declare the prototype for theses functions here, their functionality
-//will be implemented in other files which define a derived LLImageJ2CImpl
-//but only ONE static library which has the implementation for this
-//function should ever be included
+// Declare the prototype for theses functions here. Their functionality
+// will be implemented in other files which define a derived LLImageJ2CImpl
+// but only ONE static library which has the implementation for these
+// functions should ever be included.
 LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl();
 void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl);
 const char* fallbackEngineInfoLLImageJ2CImpl();
@@ -57,121 +46,10 @@ const char* fallbackEngineInfoLLImageJ2CImpl();
 LLImageCompressionTester* LLImageJ2C::sTesterp = NULL ;
 const std::string sTesterName("ImageCompressionTester");
 
-//static
-//Loads the required "create", "destroy" and "engineinfo" functions needed
-void LLImageJ2C::openDSO()
-{
-	//attempt to load a DSO and get some functions from it
-	std::string dso_name;
-	std::string dso_path;
-
-	bool all_functions_loaded = false;
-	apr_status_t rv;
-
-#if LL_WINDOWS
-	dso_name = "llkdu.dll";
-#elif LL_DARWIN
-	dso_name = "libllkdu.dylib";
-#else
-	dso_name = "libllkdu.so";
-#endif
-
-	dso_path = gDirUtilp->findFile(dso_name,
-								   gDirUtilp->getAppRODataDir(),
-								   gDirUtilp->getExecutableDir());
-
-	j2cimpl_dso_handle      = NULL;
-	j2cimpl_dso_memory_pool = NULL;
-
-	//attempt to load the shared library
-	apr_pool_create(&j2cimpl_dso_memory_pool, NULL);
-	rv = apr_dso_load(&j2cimpl_dso_handle,
-					  dso_path.c_str(),
-					  j2cimpl_dso_memory_pool);
-
-	//now, check for success
-	if ( rv == APR_SUCCESS )
-	{
-		//found the dynamic library
-		//now we want to load the functions we're interested in
-		CreateLLImageJ2CFunction  create_func = NULL;
-		DestroyLLImageJ2CFunction dest_func = NULL;
-		EngineInfoLLImageJ2CFunction engineinfo_func = NULL;
-
-		rv = apr_dso_sym((apr_dso_handle_sym_t*)&create_func,
-						 j2cimpl_dso_handle,
-						 "createLLImageJ2CKDU");
-		if ( rv == APR_SUCCESS )
-		{
-			//we've loaded the create function ok
-			//we need to delete via the DSO too
-			//so lets check for a destruction function
-			rv = apr_dso_sym((apr_dso_handle_sym_t*)&dest_func,
-							 j2cimpl_dso_handle,
-							 "destroyLLImageJ2CKDU");
-			if ( rv == APR_SUCCESS )
-			{
-				//we've loaded the destroy function ok
-				rv = apr_dso_sym((apr_dso_handle_sym_t*)&engineinfo_func,
-						 j2cimpl_dso_handle,
-						 "engineInfoLLImageJ2CKDU");
-				if ( rv == APR_SUCCESS )
-				{
-					//ok, everything is loaded alright
-					j2cimpl_create_func  = create_func;
-					j2cimpl_destroy_func = dest_func;
-					j2cimpl_engineinfo_func = engineinfo_func;
-					all_functions_loaded = true;
-				}
-			}
-		}
-	}
-
-	if ( !all_functions_loaded )
-	{
-		//something went wrong with the DSO or function loading..
-		//fall back onto our satefy impl creation function
-
-#if 0
-		// precious verbose debugging, sadly we can't use our
-		// 'llinfos' stream etc. this early in the initialisation seq.
-		char errbuf[256];
-		fprintf(stderr, "failed to load syms from DSO %s (%s)\n",
-			dso_name.c_str(), dso_path.c_str());
-		apr_strerror(rv, errbuf, sizeof(errbuf));
-		fprintf(stderr, "error: %d, %s\n", rv, errbuf);
-		apr_dso_error(j2cimpl_dso_handle, errbuf, sizeof(errbuf));
-		fprintf(stderr, "dso-error: %d, %s\n", rv, errbuf);
-#endif
-
-		if ( j2cimpl_dso_handle )
-		{
-			apr_dso_unload(j2cimpl_dso_handle);
-			j2cimpl_dso_handle = NULL;
-		}
-
-		if ( j2cimpl_dso_memory_pool )
-		{
-			apr_pool_destroy(j2cimpl_dso_memory_pool);
-			j2cimpl_dso_memory_pool = NULL;
-		}
-	}
-}
-
-//static
-void LLImageJ2C::closeDSO()
-{
-	if ( j2cimpl_dso_handle ) apr_dso_unload(j2cimpl_dso_handle);
-	if (j2cimpl_dso_memory_pool) apr_pool_destroy(j2cimpl_dso_memory_pool);
-}
-
 //static
 std::string LLImageJ2C::getEngineInfo()
 {
-	if (!j2cimpl_engineinfo_func)
-		j2cimpl_engineinfo_func = fallbackEngineInfoLLImageJ2CImpl;
-
-	return j2cimpl_engineinfo_func();
+    return fallbackEngineInfoLLImageJ2CImpl();
 }
 
 LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),
@@ -181,20 +59,7 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),
 							mReversible(FALSE),
 							mAreaUsedForDataSizeCalcs(0)
 {
-	//We assume here that if we wanted to create via
-	//a dynamic library that the approriate open calls were made
-	//before any calls to this constructor.
-
-	//Therefore, a NULL creation function pointer here means
-	//we either did not want to create using functions from the dynamic
-	//library or there were issues loading it, either way
-	//use our fall back
-	if ( !j2cimpl_create_func )
-	{
-		j2cimpl_create_func = fallbackCreateLLImageJ2CImpl;
-	}
-
-	mImpl = j2cimpl_create_func();
+	mImpl = fallbackCreateLLImageJ2CImpl();
 
 	// Clear data size table
 	for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++)
@@ -217,22 +82,9 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),
 // virtual
 LLImageJ2C::~LLImageJ2C()
 {
-	//We assume here that if we wanted to destroy via
-	//a dynamic library that the approriate open calls were made
-	//before any calls to this destructor.
-
-	//Therefore, a NULL creation function pointer here means
-	//we either did not want to destroy using functions from the dynamic
-	//library or there were issues loading it, either way
-	//use our fall back
-	if ( !j2cimpl_destroy_func )
-	{
-		j2cimpl_destroy_func = fallbackDestroyLLImageJ2CImpl;
-	}
-
 	if ( mImpl )
 	{
-		j2cimpl_destroy_func(mImpl);
+        fallbackDestroyLLImageJ2CImpl(mImpl);
 	}
 }
 
diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h
index cc3dabd7d8b14a86ed8bc1cd5fc1310d3950413c..dd5bec8b2e2cc0bfb8086d99c587ed7bb84e0fa0 100644
--- a/indra/llimage/llimagej2c.h
+++ b/indra/llimage/llimagej2c.h
@@ -72,8 +72,6 @@ class LLImageJ2C : public LLImageFormatted
 	static S32 calcHeaderSizeJ2C();
 	static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate = 0.f);
 
-	static void openDSO();
-	static void closeDSO();
 	static std::string getEngineInfo();
 
 protected:
diff --git a/indra/llinventory/llnotecard.cpp b/indra/llinventory/llnotecard.cpp
index 62829c284f4dd764f12e1ae4e984546a0ea38995..69152cefe078a75c034e329f5194387a6d0d731b 100644
--- a/indra/llinventory/llnotecard.cpp
+++ b/indra/llinventory/llnotecard.cpp
@@ -199,7 +199,7 @@ bool LLNotecard::importStream(std::istream& str)
 		return FALSE;
 	}
 
-	if(text_len > mMaxText)
+	if(text_len > mMaxText || text_len < 0)
 	{
 		llwarns << "Invalid Linden text length: " << text_len << llendl;
 		return FALSE;
diff --git a/indra/llkdu/CMakeLists.txt b/indra/llkdu/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b8b44b44fcadf27deee20120d75b858d30afe1ae
--- /dev/null
+++ b/indra/llkdu/CMakeLists.txt
@@ -0,0 +1,45 @@
+# -*- cmake -*-
+
+project(llkdu)
+
+# Visual Studio 2005 has a dumb bug that causes it to fail compilation
+# of KDU if building with both optimisation and /WS (treat warnings as
+# errors), even when the specific warnings that make it croak are
+# disabled.
+
+#set(VS_DISABLE_FATAL_WARNINGS ON)
+
+include(00-Common)
+include(LLCommon)
+include(LLImage)
+include(LLKDU)
+include(LLMath)
+
+include_directories(
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLIMAGE_INCLUDE_DIRS}
+    ${KDU_INCLUDE_DIR}
+    ${LLMATH_INCLUDE_DIRS}
+    )
+
+set(llkdu_SOURCE_FILES
+    llimagej2ckdu.cpp
+    llkdumem.cpp
+    )
+
+set(llkdu_HEADER_FILES
+    CMakeLists.txt
+	
+    llimagej2ckdu.h
+    llkdumem.h
+    )
+
+set_source_files_properties(${llkdu_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llkdu_SOURCE_FILES ${llkdu_HEADER_FILES})
+
+if (USE_KDU)
+  add_library (${LLKDU_LIBRARIES} ${llkdu_SOURCE_FILES})
+  
+endif (USE_KDU)
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1a286d14066057683b9c7bf4bd7ba46138040f6d
--- /dev/null
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -0,0 +1,1084 @@
+ /** 
+ * @file llimagej2ckdu.cpp
+ * @brief This is an implementation of JPEG2000 encode/decode using Kakadu
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llimagej2ckdu.h"
+
+#include "lltimer.h"
+#include "llpointer.h"
+#include "llkdumem.h"
+
+
+class kdc_flow_control {
+	
+public: // Member functions
+    kdc_flow_control(kdu_image_in_base *img_in, kdu_codestream codestream);
+    ~kdc_flow_control();
+    bool advance_components();
+    void process_components();
+	
+private: // Data
+    
+    struct kdc_component_flow_control {
+    public: // Data
+        kdu_image_in_base *reader;
+        int vert_subsampling;
+        int ratio_counter;  /*  Initialized to 0, decremented by `count_delta';
+                                when < 0, a new line must be processed, after
+                                which it is incremented by `vert_subsampling'.  */
+        int initial_lines;
+        int remaining_lines;
+        kdu_line_buf *line;
+    };
+    
+    kdu_codestream codestream;
+    kdu_dims valid_tile_indices;
+    kdu_coords tile_idx;
+    kdu_tile tile;
+    int num_components;
+    kdc_component_flow_control *components;
+    int count_delta; // Holds the minimum of the `vert_subsampling' fields
+    kdu_multi_analysis engine;
+    kdu_long max_buffer_memory;
+};
+
+//
+// Kakadu specific implementation
+//
+void set_default_colour_weights(kdu_params *siz);
+
+const char* engineInfoLLImageJ2CKDU()
+{
+	return "KDU v6.4.1";
+}
+
+LLImageJ2CKDU* createLLImageJ2CKDU()
+{
+	return new LLImageJ2CKDU();
+}
+
+void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu)
+{
+	delete kdu;
+	kdu = NULL;
+}
+
+LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
+{
+	return new LLImageJ2CKDU();
+}
+
+void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl)
+{
+	delete impl;
+	impl = NULL;
+}
+
+const char* fallbackEngineInfoLLImageJ2CImpl()
+{
+	return engineInfoLLImageJ2CKDU();
+}
+
+class LLKDUDecodeState
+{
+public:
+
+	S32 mNumComponents;
+	BOOL mUseYCC;
+	kdu_dims mDims;
+	kdu_sample_allocator mAllocator;
+	kdu_tile_comp mComps[4];
+	kdu_line_buf mLines[4];
+	kdu_pull_ifc mEngines[4];
+	bool mReversible[4]; // Some components may be reversible and others not.
+	int mBitDepths[4]; // Original bit-depth may be quite different from 8.
+
+	kdu_tile mTile;
+	kdu_byte *mBuf;
+	S32 mRowGap;
+
+	LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
+	~LLKDUDecodeState();
+	BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
+
+public:
+	int *AssignLayerBytes(siz_params *siz, int &num_specs);
+
+	void setupCodeStream(BOOL keep_codestream, LLImageJ2CKDU::ECodeStreamMode mode);
+	BOOL initDecode(LLImageRaw &raw_image, F32 decode_time, LLImageJ2CKDU::ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
+};
+
+void ll_kdu_error( void )
+{
+	// *FIX: This exception is bad, bad, bad. It gets thrown from a
+	// destructor which can lead to immediate program termination!
+	throw "ll_kdu_error() throwing an exception";
+}
+
+// Stuff for new kdu error handling
+class LLKDUMessageWarning : public kdu_message
+{
+public:
+	/*virtual*/ void put_text(const char *s);
+	/*virtual*/ void put_text(const kdu_uint16 *s);
+
+	static LLKDUMessageWarning sDefaultMessage;
+};
+
+class LLKDUMessageError : public kdu_message
+{
+public:
+	/*virtual*/ void put_text(const char *s);
+	/*virtual*/ void put_text(const kdu_uint16 *s);
+	/*virtual*/ void flush(bool end_of_message=false);
+	static LLKDUMessageError sDefaultMessage;
+};
+
+void LLKDUMessageWarning::put_text(const char *s)
+{
+	llinfos << "KDU Warning: " << s << llendl;
+}
+
+void LLKDUMessageWarning::put_text(const kdu_uint16 *s)
+{
+	llinfos << "KDU Warning: " << s << llendl;
+}
+
+void LLKDUMessageError::put_text(const char *s)
+{
+	llinfos << "KDU Error: " << s << llendl;
+}
+
+void LLKDUMessageError::put_text(const kdu_uint16 *s)
+{
+	llinfos << "KDU Error: " << s << llendl;
+}
+
+void LLKDUMessageError::flush(bool end_of_message)
+{
+	if( end_of_message ) 
+	{
+		throw "KDU throwing an exception";
+	}
+}
+
+LLKDUMessageWarning LLKDUMessageWarning::sDefaultMessage;
+LLKDUMessageError	LLKDUMessageError::sDefaultMessage;
+static bool kdu_message_initialized = false;
+
+LLImageJ2CKDU::LLImageJ2CKDU() : LLImageJ2CImpl(),
+mInputp(NULL),
+mCodeStreamp(NULL),
+mTPosp(NULL),
+mTileIndicesp(NULL),
+mRawImagep(NULL),
+mDecodeState(NULL)
+{
+}
+
+LLImageJ2CKDU::~LLImageJ2CKDU()
+{
+	cleanupCodeStream(); // in case destroyed before decode completed
+}
+
+// Stuff for new simple decode
+void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision);
+
+void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode)
+{
+	S32 data_size = base.getDataSize();
+	S32 max_bytes = base.getMaxBytes() ? base.getMaxBytes() : data_size;
+
+	//
+	//  Initialization
+	//
+	if (!kdu_message_initialized)
+	{
+		kdu_message_initialized = true;
+		kdu_customize_errors(&LLKDUMessageError::sDefaultMessage);
+		kdu_customize_warnings(&LLKDUMessageWarning::sDefaultMessage);
+	}
+
+	if (mCodeStreamp)
+	{
+		mCodeStreamp->destroy();
+		delete mCodeStreamp;
+		mCodeStreamp = NULL;
+	}
+
+	if (!mInputp)
+	{
+		llassert(base.getData());
+		// The compressed data has been loaded
+		// Setup the source for the codestrea
+		mInputp = new LLKDUMemSource(base.getData(), data_size);
+	}
+
+	llassert(mInputp);
+	mInputp->reset();
+	mCodeStreamp = new kdu_codestream;
+
+	mCodeStreamp->create(mInputp);
+
+	// Set the maximum number of bytes to use from the codestream
+	mCodeStreamp->set_max_bytes(max_bytes);
+
+	//    If you want to flip or rotate the image for some reason, change
+	// the resolution, or identify a restricted region of interest, this is
+	// the place to do it.  You may use "kdu_codestream::change_appearance"
+	// and "kdu_codestream::apply_input_restrictions" for this purpose.
+	//    If you wish to truncate the code-stream prior to decompression, you
+	// may use "kdu_codestream::set_max_bytes".
+	//    If you wish to retain all compressed data so that the material
+	// can be decompressed multiple times, possibly with different appearance
+	// parameters, you should call "kdu_codestream::set_persistent" here.
+	//    There are a variety of other features which must be enabled at
+	// this point if you want to take advantage of them.  See the
+	// descriptions appearing with the "kdu_codestream" interface functions
+	// in "kdu_compressed.h" for an itemized account of these capabilities.
+
+	switch( mode )
+	{
+	case MODE_FAST:
+		mCodeStreamp->set_fast();
+		break;
+	case MODE_RESILIENT:
+		mCodeStreamp->set_resilient();
+		break;
+	case MODE_FUSSY:
+		mCodeStreamp->set_fussy();
+		break;
+	default:
+		llassert(0);
+		mCodeStreamp->set_fast();
+	}
+
+	kdu_dims dims;
+	mCodeStreamp->get_dims(0,dims);
+
+	S32 components = mCodeStreamp->get_num_components();
+
+	if (components >= 3)
+	{ // Check that components have consistent dimensions (for PPM file)
+		kdu_dims dims1; mCodeStreamp->get_dims(1,dims1);
+		kdu_dims dims2; mCodeStreamp->get_dims(2,dims2);
+		if ((dims1 != dims) || (dims2 != dims))
+		{
+			llerrs << "Components don't have matching dimensions!" << llendl;
+		}
+	}
+
+	base.setSize(dims.size.x, dims.size.y, components);
+
+	if (!keep_codestream)
+	{
+		mCodeStreamp->destroy();
+		delete mCodeStreamp;
+		mCodeStreamp = NULL;
+		delete mInputp;
+		mInputp = NULL;
+	}
+}
+
+void LLImageJ2CKDU::cleanupCodeStream()
+{
+	delete mInputp;
+	mInputp = NULL;
+
+	delete mDecodeState;
+	mDecodeState = NULL;
+
+	if (mCodeStreamp)
+	{
+		mCodeStreamp->destroy();
+		delete mCodeStreamp;
+		mCodeStreamp = NULL;
+	}
+
+	delete mTPosp;
+	mTPosp = NULL;
+
+	delete mTileIndicesp;
+	mTileIndicesp = NULL;
+}
+
+BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count )
+{
+	base.resetLastError();
+
+	// *FIX: kdu calls our callback function if there's an error, and then bombs.
+	// To regain control, we throw an exception, and catch it here.
+	try
+	{
+		base.updateRawDiscardLevel();
+		setupCodeStream(base, TRUE, mode);
+
+		mRawImagep = &raw_image;
+		mCodeStreamp->change_appearance(false, true, false);
+		mCodeStreamp->apply_input_restrictions(first_channel,max_channel_count,base.getRawDiscardLevel(),0,NULL);
+
+		kdu_dims dims; mCodeStreamp->get_dims(0,dims);
+		S32 channels = base.getComponents() - first_channel;
+		if( channels > max_channel_count )
+		{
+			channels = max_channel_count;
+		}
+		raw_image.resize(dims.size.x, dims.size.y, channels);
+
+		//	llinfos << "Resizing to " << dims.size.x << ":" << dims.size.y << llendl;
+		if (!mTileIndicesp)
+		{
+			mTileIndicesp = new kdu_dims;
+		}
+		mCodeStreamp->get_valid_tiles(*mTileIndicesp);
+		if (!mTPosp)
+		{
+			mTPosp = new kdu_coords;
+			mTPosp->y = 0;
+			mTPosp->x = 0;
+		}
+	}
+	catch (const char* msg)
+	{
+		base.setLastError(ll_safe_string(msg));
+		return FALSE;
+	}
+	catch (...)
+	{
+		base.setLastError("Unknown J2C error");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+// Returns TRUE to mean done, whether successful or not.
+BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+{
+	ECodeStreamMode mode = MODE_FAST;
+
+	LLTimer decode_timer;
+
+	if (!mCodeStreamp)
+	{
+		if (!initDecode(base, raw_image, decode_time, mode, first_channel, max_channel_count))
+		{
+			// Initializing the J2C decode failed, bail out.
+			cleanupCodeStream();
+			return TRUE; // done
+		}
+	}
+
+	// These can probably be grabbed from what's saved in the class.
+	kdu_dims dims;
+	mCodeStreamp->get_dims(0,dims);
+
+	// Now we are ready to walk through the tiles processing them one-by-one.
+	kdu_byte *buffer = raw_image.getData();
+
+	while (mTPosp->y < mTileIndicesp->size.y)
+	{
+		while (mTPosp->x < mTileIndicesp->size.x)
+		{
+			try
+			{
+				if (!mDecodeState)
+				{
+					kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp)+mTileIndicesp->pos);
+
+					// Find the region of the buffer occupied by this
+					// tile.  Note that we have no control over
+					// sub-sampling factors which might have been used
+					// during compression and so it can happen that tiles
+					// (at the image component level) actually have
+					// different dimensions.  For this reason, we cannot
+					// figure out the buffer region occupied by a tile
+					// directly from the tile indices.  Instead, we query
+					// the highest resolution of the first tile-component
+					// concerning its location and size on the canvas --
+					// the `dims' object already holds the location and
+					// size of the entire image component on the same
+					// canvas coordinate system.  Comparing the two tells
+					// us where the current tile is in the buffer.
+					S32 channels = base.getComponents() - first_channel;
+					if( channels > max_channel_count )
+					{
+						channels = max_channel_count;
+					}
+					kdu_resolution res = tile.access_component(0).access_resolution();
+					kdu_dims tile_dims; res.get_dims(tile_dims);
+					kdu_coords offset = tile_dims.pos - dims.pos;
+					int row_gap = channels*dims.size.x; // inter-row separation
+					kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels;
+					mDecodeState = new LLKDUDecodeState(tile, buf, row_gap);
+				}
+				// Do the actual processing
+				F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32();
+				// This is where we do the actual decode.  If we run out of time, return false.
+				if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f)))
+				{
+					delete mDecodeState;
+					mDecodeState = NULL;
+				}
+				else
+				{
+					// Not finished decoding yet.
+					//					setLastError("Ran out of time while decoding");
+					return FALSE;
+				}
+			}
+			catch( const char* msg )
+			{
+				base.setLastError(ll_safe_string(msg));
+				base.decodeFailed();
+				cleanupCodeStream();
+				return TRUE; // done
+			}
+			catch( ... )
+			{
+				base.setLastError( "Unknown J2C error" );
+				base.decodeFailed();
+				cleanupCodeStream();
+				return TRUE; // done
+			}
+
+
+			mTPosp->x++;
+		}
+		mTPosp->y++;
+		mTPosp->x = 0;
+	}
+
+	cleanupCodeStream();
+
+	return TRUE;
+}
+
+
+BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible)
+{
+	// Collect simple arguments.
+	bool transpose, vflip, hflip;
+	bool allow_rate_prediction, mem, quiet, no_weights;
+	int cpu_iterations;
+	std::ostream *record_stream;
+
+	transpose = false;
+	record_stream = NULL;
+	allow_rate_prediction = true;
+	no_weights = false;
+	cpu_iterations = -1;
+	mem = false;
+	quiet = false;
+	vflip = true;
+	hflip = false;
+
+	try
+	{
+		// Set up input image files.
+		siz_params siz;
+		
+		// Should set rate someplace here.
+		LLKDUMemIn mem_in(raw_image.getData(),
+			raw_image.getDataSize(),
+			raw_image.getWidth(),
+			raw_image.getHeight(),
+			raw_image.getComponents(),
+			&siz);
+
+		base.setSize(raw_image.getWidth(), raw_image.getHeight(), raw_image.getComponents());
+
+		int num_components = raw_image.getComponents();
+
+		siz.set(Scomponents,0,0,num_components);
+		siz.set(Sdims,0,0,base.getHeight());  // Height of first image component
+		siz.set(Sdims,0,1,base.getWidth());   // Width of first image component
+		siz.set(Sprecision,0,0,8);  // Image samples have original bit-depth of 8
+		siz.set(Ssigned,0,0,false); // Image samples are originally unsigned
+
+		kdu_params *siz_ref = &siz; siz_ref->finalize();
+		siz_params transformed_siz; // Use this one to construct code-strea
+		transformed_siz.copy_from(&siz,-1,-1,-1,0,transpose,false,false);
+
+		// Construct the `kdu_codestream' object and parse all remaining arguments.
+
+		U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
+		if (max_output_size < 1000)
+		{
+			max_output_size = 1000;
+		}
+		U8 *output_buffer = new U8[max_output_size];
+
+		U32 output_size = max_output_size; // gets modified
+		LLKDUMemTarget output(output_buffer, output_size, base.getWidth()*base.getHeight()*base.getComponents());
+		if (output_size > max_output_size)
+		{
+			llerrs << llformat("LLImageJ2C::encode output_size(%d) > max_output_size(%d)",
+				output_size,max_output_size) << llendl;
+		}
+
+		kdu_codestream codestream;
+		codestream.create(&transformed_siz,&output);
+
+		if (comment_text)
+		{
+			// Set the comments for the codestream
+			kdu_codestream_comment comment = codestream.add_comment();
+			comment.put_text(comment_text);
+		}
+
+		// Set codestream options
+		int num_layer_specs = 0;
+
+		kdu_long layer_bytes[64];
+		U32 max_bytes = 0;
+
+		if ((num_components >= 3) && !no_weights)
+		{
+			set_default_colour_weights(codestream.access_siz());
+		}
+
+		if (reversible)
+		{
+			// If we're doing reversible, assume we're not using quality layers.
+			// Yes, I know this is incorrect!
+			codestream.access_siz()->parse_string("Creversible=yes");
+			codestream.access_siz()->parse_string("Clayers=1");
+			num_layer_specs = 1;
+			layer_bytes[0] = 0;
+		}
+		else
+		{
+			// Rate is the argument passed into the LLImageJ2C which
+			// specifies the target compression rate.  The default is 8:1.
+			// Possibly if max_bytes < 500, we should just use the default setting?
+			if (base.mRate != 0.f)
+			{
+				max_bytes = (U32)(base.mRate*base.getWidth()*base.getHeight()*base.getComponents());
+			}
+			else
+			{
+				max_bytes = (U32)(base.getWidth()*base.getHeight()*base.getComponents()*0.125);
+			}
+
+			const U32 min_bytes = FIRST_PACKET_SIZE;
+			if (max_bytes > min_bytes)
+			{
+				U32 i;
+				// This code is where we specify the target number of bytes for
+				// each layer.  Not sure if we should do this for small images
+				// or not.  The goal is to have this roughly align with
+				// different quality levels that we decode at.
+				for (i = min_bytes; i < max_bytes; i*=4)
+				{
+					if (i == min_bytes * 4)
+					{
+						i = 2000;
+					}
+					layer_bytes[num_layer_specs] = i;
+					num_layer_specs++;
+				}
+				layer_bytes[num_layer_specs] = max_bytes;
+				num_layer_specs++;
+
+				std::string layer_string = llformat("Clayers=%d",num_layer_specs);
+				codestream.access_siz()->parse_string(layer_string.c_str());
+			}
+			else
+			{
+				layer_bytes[0] = min_bytes;
+				num_layer_specs = 1;
+				std::string layer_string = llformat("Clayers=%d",num_layer_specs);
+				codestream.access_siz()->parse_string(layer_string.c_str());
+			}
+		}
+		codestream.access_siz()->finalize_all();
+		if (cpu_iterations >= 0)
+		{
+			codestream.collect_timing_stats(cpu_iterations);
+		}
+		codestream.change_appearance(transpose,vflip,hflip);
+
+		// Now we are ready for sample data processing.
+        kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream);
+        bool done = false;
+        while (!done)
+        { 
+            // Process line by line
+            done = true;
+            if (tile->advance_components())
+            {
+                done = false;
+                tile->process_components();
+            }
+        }
+
+		// Produce the compressed output
+        codestream.flush(layer_bytes,num_layer_specs);
+
+		// Cleanup
+        delete tile;
+
+		codestream.destroy();
+		if (record_stream != NULL)
+		{
+			delete record_stream;
+		}
+
+		// Now that we're done encoding, create the new data buffer for the compressed
+		// image and stick it there.
+
+		base.copyData(output_buffer, output_size);
+		base.updateData(); // set width, height
+		delete[] output_buffer;
+	}
+	catch(const char* msg)
+	{
+		base.setLastError(ll_safe_string(msg));
+		return FALSE;
+	}
+	catch( ... )
+	{
+		base.setLastError( "Unknown J2C error" );
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+BOOL LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
+{
+	// *FIX: kdu calls our callback function if there's an error, and
+	// then bombs.  To regain control, we throw an exception, and
+	// catch it here.
+	try
+	{
+		setupCodeStream(base, FALSE, MODE_FAST);
+		return TRUE;
+	}
+	catch( const char* msg )
+	{
+		base.setLastError(ll_safe_string(msg));
+		return FALSE;
+	}
+	catch( ... )
+	{
+		base.setLastError( "Unknown J2C error" );
+		return FALSE;
+	}
+}
+
+void set_default_colour_weights(kdu_params *siz)
+{
+	kdu_params *cod = siz->access_cluster(COD_params);
+	assert(cod != NULL);
+
+	bool can_use_ycc = true;
+	bool rev0=false;
+	int depth0=0, sub_x0=1, sub_y0=1;
+	for (int c=0; c < 3; c++)
+	{
+		int depth=0; siz->get(Sprecision,c,0,depth);
+		int sub_y=1; siz->get(Ssampling,c,0,sub_y);
+		int sub_x=1; siz->get(Ssampling,c,1,sub_x);
+		kdu_params *coc = cod->access_relation(-1,c);
+		bool rev=false; coc->get(Creversible,0,0,rev);
+		if (c == 0)
+		{ rev0=rev; depth0=depth; sub_x0=sub_x; sub_y0=sub_y; }
+		else if ((rev != rev0) || (depth != depth0) ||
+			(sub_x != sub_x0) || (sub_y != sub_y0))
+			can_use_ycc = false;
+	}
+	if (!can_use_ycc)
+		return;
+
+	bool use_ycc;
+	if (!cod->get(Cycc,0,0,use_ycc))
+		cod->set(Cycc,0,0,use_ycc=true);
+	if (!use_ycc)
+		return;
+	float weight;
+	if (cod->get(Clev_weights,0,0,weight) ||
+		cod->get(Cband_weights,0,0,weight))
+		return; // Weights already specified explicitly.
+
+	/* These example weights are adapted from numbers generated by Marcus Nadenau
+	at EPFL, for a viewing distance of 15 cm and a display resolution of
+	300 DPI. */
+
+	cod->parse_string("Cband_weights:C0="
+		"{0.0901},{0.2758},{0.2758},"
+		"{0.7018},{0.8378},{0.8378},{1}");
+	cod->parse_string("Cband_weights:C1="
+		"{0.0263},{0.0863},{0.0863},"
+		"{0.1362},{0.2564},{0.2564},"
+		"{0.3346},{0.4691},{0.4691},"
+		"{0.5444},{0.6523},{0.6523},"
+		"{0.7078},{0.7797},{0.7797},{1}");
+	cod->parse_string("Cband_weights:C2="
+		"{0.0773},{0.1835},{0.1835},"
+		"{0.2598},{0.4130},{0.4130},"
+		"{0.5040},{0.6464},{0.6464},"
+		"{0.7220},{0.8254},{0.8254},"
+		"{0.8769},{0.9424},{0.9424},{1}");
+}
+
+/******************************************************************************/
+/*                              transfer_bytes                                */
+/******************************************************************************/
+
+void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision)
+/* Transfers source samples from the supplied line buffer into the output
+byte buffer, spacing successive output samples apart by `gap' bytes
+(to allow for interleaving of colour components).  The function performs
+all necessary level shifting, type conversion, rounding and truncation. */
+{
+	int width = src.get_width();
+	if (src.get_buf32() != NULL)
+	{ // Decompressed samples have a 32-bit representation (integer or float)
+		assert(precision >= 8); // Else would have used 16 bit representation
+		kdu_sample32 *sp = src.get_buf32();
+		if (!src.is_absolute())
+		{ // Transferring normalized floating point data.
+			float scale16 = (float)(1<<16);
+			kdu_int32 val;
+
+			for (; width > 0; width--, sp++, dest+=gap)
+			{
+				val = (kdu_int32)(sp->fval*scale16);
+				val = (val+128)>>8; // May be faster than true rounding
+				val += 128;
+				if (val & ((-1)<<8))
+				{
+					val = (val<0)?0:255;
+				}
+				*dest = (kdu_byte) val;
+			}
+		}
+		else
+		{ // Transferring 32-bit absolute integers.
+			kdu_int32 val;
+			kdu_int32 downshift = precision-8;
+			kdu_int32 offset = (1<<downshift)>>1;
+
+			for (; width > 0; width--, sp++, dest+=gap)
+			{
+				val = sp->ival;
+				val = (val+offset)>>downshift;
+				val += 128;
+				if (val & ((-1)<<8))
+				{
+					val = (val<0)?0:255;
+				}
+				*dest = (kdu_byte) val;
+			}
+		}
+	}
+	else
+	{ // Source data is 16 bits.
+		kdu_sample16 *sp = src.get_buf16();
+		if (!src.is_absolute())
+		{ // Transferring 16-bit fixed point quantities
+			kdu_int16 val;
+
+			if (precision >= 8)
+			{ // Can essentially ignore the bit-depth.
+				for (; width > 0; width--, sp++, dest+=gap)
+				{
+					val = sp->ival;
+					val += (1<<(KDU_FIX_POINT-8))>>1;
+					val >>= (KDU_FIX_POINT-8);
+					val += 128;
+					if (val & ((-1)<<8))
+					{
+						val = (val<0)?0:255;
+					}
+					*dest = (kdu_byte) val;
+				}
+			}
+			else
+			{ // Need to force zeros into one or more least significant bits.
+				kdu_int16 downshift = KDU_FIX_POINT-precision;
+				kdu_int16 upshift = 8-precision;
+				kdu_int16 offset = 1<<(downshift-1);
+
+				for (; width > 0; width--, sp++, dest+=gap)
+				{
+					val = sp->ival;
+					val = (val+offset)>>downshift;
+					val <<= upshift;
+					val += 128;
+					if (val & ((-1)<<8))
+					{
+						val = (val<0)?0:(256-(1<<upshift));
+					}
+					*dest = (kdu_byte) val;
+				}
+			}
+		}
+		else
+		{ // Transferring 16-bit absolute integers.
+			kdu_int16 val;
+
+			if (precision >= 8)
+			{
+				kdu_int16 downshift = precision-8;
+				kdu_int16 offset = (1<<downshift)>>1;
+
+				for (; width > 0; width--, sp++, dest+=gap)
+				{
+					val = sp->ival;
+					val = (val+offset)>>downshift;
+					val += 128;
+					if (val & ((-1)<<8))
+					{
+						val = (val<0)?0:255;
+					}
+					*dest = (kdu_byte) val;
+				}
+			}
+			else
+			{
+				kdu_int16 upshift = 8-precision;
+
+				for (; width > 0; width--, sp++, dest+=gap)
+				{
+					val = sp->ival;
+					val <<= upshift;
+					val += 128;
+					if (val & ((-1)<<8))
+					{
+						val = (val<0)?0:(256-(1<<upshift));
+					}
+					*dest = (kdu_byte) val;
+				}
+			}
+		}
+	}
+}
+
+LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap)
+{
+	S32 c;
+
+	mTile = tile;
+	mBuf = buf;
+	mRowGap = row_gap;
+
+	mNumComponents = tile.get_num_components();
+
+	llassert(mNumComponents<=4);
+	mUseYCC = tile.get_ycc();
+
+	for (c=0; c<4; ++c)
+	{
+		mReversible[c] = false;
+		mBitDepths[c] = 0;
+	}
+
+	// Open tile-components and create processing engines and resources
+	for (c=0; c < mNumComponents; c++)
+	{
+		mComps[c] = mTile.access_component(c);
+		mReversible[c] = mComps[c].get_reversible();
+		mBitDepths[c] = mComps[c].get_bit_depth();
+		kdu_resolution res = mComps[c].access_resolution(); // Get top resolution
+		kdu_dims comp_dims; res.get_dims(comp_dims);
+		if (c == 0)
+		{
+			mDims = comp_dims;
+		}
+		else
+		{
+			llassert(mDims == comp_dims); // Safety check; the caller has ensured this
+		}
+		bool use_shorts = (mComps[c].get_bit_depth(true) <= 16);
+		mLines[c].pre_create(&mAllocator,mDims.size.x,mReversible[c],use_shorts);
+		if (res.which() == 0) // No DWT levels used
+		{
+			mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,use_shorts);
+		}
+		else
+		{
+			mEngines[c] = kdu_synthesis(res,&mAllocator,use_shorts);
+		}
+	}
+	mAllocator.finalize(); // Actually creates buffering resources
+	for (c=0; c < mNumComponents; c++)
+	{
+		mLines[c].create(); // Grabs resources from the allocator.
+	}
+}
+
+LLKDUDecodeState::~LLKDUDecodeState()
+{
+	S32 c;
+	// Cleanup
+	for (c=0; c < mNumComponents; c++)
+	{
+		mEngines[c].destroy(); // engines are interfaces; no default destructors
+	}
+
+	mTile.close();
+}
+
+BOOL LLKDUDecodeState::processTileDecode(F32 decode_time, BOOL limit_time)
+/* Decompresses a tile, writing the data into the supplied byte buffer.
+The buffer contains interleaved image components, if there are any.
+Although you may think of the buffer as belonging entirely to this tile,
+the `buf' pointer may actually point into a larger buffer representing
+multiple tiles.  For this reason, `row_gap' is needed to identify the
+separation between consecutive rows in the real buffer. */
+{
+	S32 c;
+	// Now walk through the lines of the buffer, recovering them from the
+	// relevant tile-component processing engines.
+
+	LLTimer decode_timer;
+	while (mDims.size.y--)
+	{
+		for (c=0; c < mNumComponents; c++)
+		{
+			mEngines[c].pull(mLines[c],true);
+		}
+		if ((mNumComponents >= 3) && mUseYCC)
+		{
+			kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
+		}
+		for (c=0; c < mNumComponents; c++)
+		{
+			transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
+		}
+		mBuf += mRowGap;
+		if (mDims.size.y % 10)
+		{
+			if (limit_time && decode_timer.getElapsedTimeF32() > decode_time)
+			{
+				return FALSE;
+			}
+		}
+	}
+	return TRUE;
+}
+
+// kdc_flow_control 
+
+kdc_flow_control::kdc_flow_control (kdu_image_in_base *img_in, kdu_codestream codestream)
+{
+    int n;
+    
+    this->codestream = codestream;
+    codestream.get_valid_tiles(valid_tile_indices);
+    tile_idx = valid_tile_indices.pos;
+    tile = codestream.open_tile(tile_idx,NULL);
+    
+    // Set up the individual components
+    num_components = codestream.get_num_components(true);
+    components = new kdc_component_flow_control[num_components];
+    count_delta = 0;
+    kdc_component_flow_control *comp = components;
+    for (n = 0; n < num_components; n++, comp++)
+    {
+        comp->line = NULL;
+        comp->reader = img_in;
+        kdu_coords subsampling;  
+        codestream.get_subsampling(n,subsampling,true);
+        kdu_dims dims;  
+        codestream.get_tile_dims(tile_idx,n,dims,true);
+        comp->vert_subsampling = subsampling.y;
+        if ((n == 0) || (comp->vert_subsampling < count_delta))
+        {
+            count_delta = comp->vert_subsampling;
+        }
+        comp->ratio_counter = 0;
+        comp->remaining_lines = comp->initial_lines = dims.size.y;
+    }
+    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);
+}
+
+kdc_flow_control::~kdc_flow_control()
+{
+    if (components != NULL)
+        delete[] components;
+    if (engine.exists())
+        engine.destroy();
+}
+
+bool kdc_flow_control::advance_components()
+{
+    bool found_line = false;
+    while (!found_line)
+    {
+        bool all_done = true;
+        kdc_component_flow_control *comp = components;
+        for (int n = 0; n < num_components; n++, comp++)
+        {
+            assert(comp->ratio_counter >= 0);
+            if (comp->remaining_lines > 0)
+            {
+                all_done = false;
+                comp->ratio_counter -= count_delta;
+                if (comp->ratio_counter < 0)
+                {
+                    found_line = true;
+                    comp->line = engine.exchange_line(n,NULL,NULL);
+                    assert(comp->line != NULL);
+					if (comp->line->get_width())
+					{
+						comp->reader->get(n,*(comp->line),0);
+					}
+                }
+            }
+        }
+        if (all_done)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+void kdc_flow_control::process_components()
+{
+    kdc_component_flow_control *comp = components;
+    for (int n = 0; n < num_components; n++, comp++)
+    {
+        if (comp->ratio_counter < 0)
+        {
+            comp->ratio_counter += comp->vert_subsampling;
+            assert(comp->ratio_counter >= 0);
+            assert(comp->remaining_lines > 0);
+            comp->remaining_lines--;
+            assert(comp->line != NULL);
+            engine.exchange_line(n,comp->line,NULL);
+            comp->line = NULL;
+        }
+    }
+}
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
new file mode 100644
index 0000000000000000000000000000000000000000..03f289f8b177849b91d6e687133ca12f50b2bebc
--- /dev/null
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -0,0 +1,91 @@
+/** 
+ * @file llimagej2ckdu.h
+ * @brief This is an implementation of JPEG2000 encode/decode using Kakadu
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLIMAGEJ2CKDU_H
+#define LL_LLIMAGEJ2CKDU_H
+
+#include "llimagej2c.h"
+
+//
+// KDU core header files
+//
+#include "kdu_elementary.h"
+#include "kdu_messaging.h"
+#include "kdu_params.h"
+#include "kdu_compressed.h"
+#include "kdu_sample_processing.h"
+
+class LLKDUDecodeState;
+class LLKDUMemSource;
+
+class LLImageJ2CKDU : public LLImageJ2CImpl
+{	
+public:
+	enum ECodeStreamMode 
+	{
+		MODE_FAST = 0,
+		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);
+
+	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 );
+
+	// Encode variable
+	LLKDUMemSource *mInputp;
+	kdu_codestream *mCodeStreamp;
+	kdu_coords *mTPosp; // tile position
+	kdu_dims *mTileIndicesp;
+
+	// Temporary variables for in-progress decodes...
+	LLImageRaw *mRawImagep;
+	LLKDUDecodeState *mDecodeState;
+};
+
+#if LL_WINDOWS
+# define LLSYMEXPORT __declspec(dllexport)
+#elif LL_LINUX
+# define LLSYMEXPORT __attribute__ ((visibility("default")))
+#else
+# define LLSYMEXPORT
+#endif
+
+extern "C" LLSYMEXPORT const char* engineInfoLLImageJ2CKDU();
+extern "C" LLSYMEXPORT LLImageJ2CKDU* createLLImageJ2CKDU();
+extern "C" LLSYMEXPORT void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu);
+
+#endif
diff --git a/indra/llkdu/llkdumem.cpp b/indra/llkdu/llkdumem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1f549cbbe0daa23c0f439f976bc60ef55ce9f818
--- /dev/null
+++ b/indra/llkdu/llkdumem.cpp
@@ -0,0 +1,196 @@
+ /** 
+ * @file llkdumem.cpp
+ * @brief Helper class for kdu memory management
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llkdumem.h"
+#include "llerror.h"
+
+#if defined(LL_WINDOWS)
+# pragma warning(disable: 4702) // unreachable code
+#endif
+
+LLKDUMemIn::LLKDUMemIn(const U8 *data,
+					   const U32 size,
+					   const U16 width,
+					   const U16 height,
+					   const U8 in_num_components,
+					   siz_params *siz)
+{
+	U8 n;
+
+	first_comp_idx = 0;
+	rows = height;
+	cols = width;
+	num_components = in_num_components;
+	alignment_bytes = 0;
+
+	for (n=0; n<3; ++n)
+	{
+		precision[n] = 0;
+	}
+
+	for (n=0; n < num_components; ++n)
+	{
+		siz->set(Sdims,n,0,rows);
+		siz->set(Sdims,n,1,cols);
+		siz->set(Ssigned,n,0,false);
+		siz->set(Sprecision,n,0,8);
+	}
+	incomplete_lines = NULL;
+	free_lines = NULL;
+	num_unread_rows = rows;
+
+	mData = data;
+	mDataSize = size;
+	mCurPos = 0;
+}
+
+LLKDUMemIn::~LLKDUMemIn()
+{
+	if ((num_unread_rows > 0) || (incomplete_lines != NULL))
+	{
+		kdu_warning w;
+		w << "Not all rows of image components "
+			<< first_comp_idx << " through "
+			<< first_comp_idx+num_components-1
+			<< " were consumed!";
+	}
+	image_line_buf *tmp;
+	while ((tmp=incomplete_lines) != NULL)
+    {
+		incomplete_lines = tmp->next;
+		delete tmp; 
+	}
+	while ((tmp=free_lines) != NULL)
+    {
+		free_lines = tmp->next;
+		delete tmp;
+	}
+}
+
+
+bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum)
+{
+	int idx = comp_idx - this->first_comp_idx;
+	assert((idx >= 0) && (idx < num_components));
+	x_tnum = x_tnum*num_components+idx;
+	image_line_buf *scan, *prev=NULL;
+	for (scan=incomplete_lines; scan != NULL; prev=scan, scan=scan->next)
+    {
+		assert(scan->next_x_tnum >= x_tnum);
+		if (scan->next_x_tnum == x_tnum)
+		{
+			break;
+		}
+    }
+	if (scan == NULL)
+    { // Need to read a new image line.
+		assert(x_tnum == 0); // Must consume in very specific order.
+		if (num_unread_rows == 0)
+		{
+	        return false;
+		}
+		if ((scan = free_lines) == NULL)
+		{
+			scan = new image_line_buf(cols+3,num_components);
+		}
+		free_lines = scan->next;
+		if (prev == NULL)
+		{
+	        incomplete_lines = scan;
+		}
+		else
+		{
+			prev->next = scan;
+		}
+
+		// Copy from image buffer into scan.
+		memcpy(scan->buf, mData+mCurPos, cols*num_components);
+		mCurPos += cols*num_components;
+
+		num_unread_rows--;
+		scan->accessed_samples = 0;
+		scan->next_x_tnum = 0;
+    }
+
+	assert((cols-scan->accessed_samples) >= line.get_width());
+
+	int comp_offset = idx;
+	kdu_byte *sp = scan->buf+num_components*scan->accessed_samples + comp_offset;
+	int n=line.get_width();
+
+	if (line.get_buf32() != NULL)
+	{
+		kdu_sample32 *dp = line.get_buf32();
+		if (line.is_absolute())
+		{ // 32-bit absolute integers
+			for (; n > 0; n--, sp+=num_components, dp++)
+			{
+				dp->ival = ((kdu_int32)(*sp)) - 128;
+			}
+		}
+		else
+		{ // true 32-bit floats
+			for (; n > 0; n--, sp+=num_components, dp++)
+			{
+				dp->fval = (((float)(*sp)) / 256.0F) - 0.5F;
+			}
+		}
+	}
+	else
+    {
+		kdu_sample16 *dp = line.get_buf16();
+		if (line.is_absolute())
+		{ // 16-bit absolute integers
+			for (; n > 0; n--, sp+=num_components, dp++)
+			{
+				dp->ival = ((kdu_int16)(*sp)) - 128;
+			}
+		}
+		else
+		{ // 16-bit normalized representation.
+			for (; n > 0; n--, sp+=num_components, dp++)
+			{
+				dp->ival = (((kdu_int16)(*sp)) - 128) << (KDU_FIX_POINT-8);
+			}
+		}
+    }
+
+	scan->next_x_tnum++;
+	if (idx == (num_components-1))
+	{
+		scan->accessed_samples += line.get_width();
+	}
+	if (scan->accessed_samples == cols)
+	{ // Send empty line to free list.
+		assert(scan == incomplete_lines);
+		incomplete_lines = scan->next;
+		scan->next = free_lines;
+		free_lines = scan;
+	}
+
+  return true;
+}
diff --git a/indra/llkdu/llkdumem.h b/indra/llkdu/llkdumem.h
new file mode 100644
index 0000000000000000000000000000000000000000..7064de4408d682aa87972804c592cfd917646bfd
--- /dev/null
+++ b/indra/llkdu/llkdumem.h
@@ -0,0 +1,145 @@
+/** 
+ * @file llkdumem.h
+ * @brief Helper class for kdu memory management
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLKDUMEM_H
+#define LL_LLKDUMEM_H
+
+// Support classes for reading and writing from memory buffers in KDU
+#include "kdu_image.h"
+#include "kdu_elementary.h"
+#include "kdu_messaging.h"
+#include "kdu_params.h"
+#include "kdu_compressed.h"
+#include "kdu_sample_processing.h"
+#include "image_local.h"
+#include "stdtypes.h"
+
+class LLKDUMemSource: public kdu_compressed_source
+{
+public: // Member functions
+	LLKDUMemSource(U8 *input_buffer, U32 size)
+	{
+		mData = input_buffer;
+		mSize = size;
+		mCurPos = 0;
+	}
+
+    ~LLKDUMemSource()
+	{
+	}
+
+    int read(kdu_byte *buf, int num_bytes)
+	{
+		U32 num_out;
+		num_out = num_bytes;
+
+		if ((mSize - mCurPos) < (U32)num_bytes)
+		{
+			num_out = mSize -mCurPos;
+		}
+		memcpy(buf, mData + mCurPos, num_out);
+		mCurPos += num_out;
+		return num_out;
+	}
+
+	void reset()
+	{
+		mCurPos = 0;
+	}
+
+private: // Data
+	U8 *mData;
+	U32 mSize;
+	U32 mCurPos;
+};
+
+class LLKDUMemTarget: public kdu_compressed_target
+{
+public: // Member functions
+	LLKDUMemTarget(U8 *output_buffer, U32 &output_size, const U32 buffer_size)
+	{
+		mData = output_buffer;
+		mSize = buffer_size;
+		mCurPos = 0;
+		mOutputSize = &output_size;
+	}
+
+    ~LLKDUMemTarget()
+    {
+	}
+
+    bool write(const kdu_byte *buf, int num_bytes)
+	{
+		U32 num_out;
+		num_out = num_bytes;
+
+		if ((mSize - mCurPos) < (U32)num_bytes)
+		{
+			num_out = mSize - mCurPos;
+			memcpy(mData + mCurPos, buf, num_out);
+			return false;
+		}
+		memcpy(mData + mCurPos, buf, num_out);
+		mCurPos += num_out;
+		*mOutputSize = mCurPos;
+		return true;
+	}
+	
+private: // Data
+	U8 *mData;
+	U32 mSize;
+	U32 mCurPos;
+	U32 *mOutputSize;
+};
+
+class LLKDUMemIn : public kdu_image_in_base
+{
+public: // Member functions
+    LLKDUMemIn(const U8 *data,
+				const U32 size,
+				const U16 rows,
+				const U16 cols,
+				U8 in_num_components,
+				siz_params *siz);
+    ~LLKDUMemIn();
+
+    bool get(int comp_idx, kdu_line_buf &line, int x_tnum);
+
+private: // Data
+	const U8 *mData;
+    int first_comp_idx;
+    int num_components;
+    int rows, cols;
+    int alignment_bytes; // Number of 0's at end of each line.
+    int precision[3];
+    image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
+    image_line_buf *free_lines;
+    int num_unread_rows;
+
+	U32 mCurPos;
+	U32 mDataSize;
+};
+#endif
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 69ed0fb09c1406ab8fa7c16d27f3d5f7ed992434..595c470a195cfb12ee9425db6910548be5e99882 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -160,7 +160,7 @@ void LLPluginClassMedia::idle(void)
 		mPlugin->idle();
 	}
 	
-	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()))
+	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
 	{
 		// Can't process a size change at this time
 	}
@@ -522,7 +522,15 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
 			}
 		break;
 	}
-	
+
+#if LL_DARWIN	
+	if(modifiers & MASK_ALT)
+	{
+		// Option-key modified characters should be handled by the unicode input path instead of this one.
+		result = false;
+	}
+#endif
+
 	if(result)
 	{
 		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
@@ -674,7 +682,21 @@ void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
 	message.setValue("file", file);
-	if(mPlugin->isBlocked())
+	if(mPlugin && mPlugin->isBlocked())
+	{
+		// If the plugin sent a blocking pick-file request, the response should unblock it.
+		message.setValueBoolean("blocking_response", true);
+	}
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
+	message.setValueBoolean("ok", ok);
+	message.setValue("username", username);
+	message.setValue("password", password);
+	if(mPlugin && mPlugin->isBlocked())
 	{
 		// If the plugin sent a blocking pick-file request, the response should unblock it.
 		message.setValueBoolean("blocking_response", true);
@@ -947,6 +969,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 		{
 			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
 		}
+		else if(message_name == "auth_request")
+		{
+			mAuthURL = message.getValue("url");
+			mAuthRealm = message.getValue("realm");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
+		}
 		else
 		{
 			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
@@ -1019,6 +1047,15 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 				
 			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
 		}
+		else if(message_name == "link_hovered")
+		{
+			// text is not currently used -- the tooltip hover text is taken from the "title".
+			mHoverLink = message.getValue("link");
+			mHoverText = message.getValue("title");
+			// message.getValue("text");
+				
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
+		}
 		else
 		{
 			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
@@ -1192,6 +1229,20 @@ void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
 	sendMessage(message);
 }
 
+void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
+	message.setValueBoolean("ignore", ignore);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
+	message.setValue("path", path);
+	sendMessage(message);
+}
+
 void LLPluginClassMedia::crashPlugin()
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 9cb67fe9091b0f018d0cc19504add6e2caea6a86..c826e13c4078abca91df7eb338a5155415c32c97 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -85,6 +85,8 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	
 	void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; };
 	
+	void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; };
+	
 	// Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent.
 	// This will initially be false, and will also be false for some time after setSize while the resize is processed.
 	// Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values
@@ -159,6 +161,8 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	
 	void sendPickFileResponse(const std::string &file);
 
+	void sendAuthResponse(bool ok, const std::string &username, const std::string &password);
+
 	// Valid after a MEDIA_EVENT_CURSOR_CHANGED event
 	std::string getCursorName() const { return mCursorName; };
 
@@ -198,6 +202,8 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	void setBrowserUserAgent(const std::string& user_agent);
 	void proxyWindowOpened(const std::string &target, const std::string &uuid);
 	void proxyWindowClosed(const std::string &uuid);
+	void ignore_ssl_cert_errors(bool ignore);
+	void addCertificateFilePath(const std::string& path);
 	
 	// This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE
 	std::string	getNavigateURI() const { return mNavigateURI; };
@@ -231,7 +237,15 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	S32 getGeometryY() const { return mGeometryY; };
 	S32 getGeometryWidth() const { return mGeometryWidth; };
 	S32 getGeometryHeight() const { return mGeometryHeight; };
+	
+	// These are valid during MEDIA_EVENT_AUTH_REQUEST
+	std::string	getAuthURL() const { return mAuthURL; };
+	std::string	getAuthRealm() const { return mAuthRealm; };
 
+	// These are valid during MEDIA_EVENT_LINK_HOVERED
+	std::string	getHoverText() const { return mHoverText; };
+	std::string	getHoverLink() const { return mHoverLink; };
+	
 	std::string getMediaName() const { return mMediaName; };
 	std::string getMediaDescription() const { return mMediaDescription; };
 
@@ -369,6 +383,10 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	S32				mGeometryY;
 	S32				mGeometryWidth;
 	S32				mGeometryHeight;
+	std::string		mAuthURL;
+	std::string		mAuthRealm;
+	std::string		mHoverText;
+	std::string		mHoverLink;
 	
 	/////////////////////////////////////////
 	// media_time class
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index c9efff216c076292fc3237c9de81962efc563c11..42e93cc6d7e12da5b69b30cd8d516b33fefa673e 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -59,7 +59,11 @@ class LLPluginClassMediaOwner
 		MEDIA_EVENT_GEOMETRY_CHANGE,		// The plugin requested its window geometry be changed (per the javascript window interface)
 		
 		MEDIA_EVENT_PLUGIN_FAILED_LAUNCH,	// The plugin failed to launch 
-		MEDIA_EVENT_PLUGIN_FAILED			// The plugin died unexpectedly
+		MEDIA_EVENT_PLUGIN_FAILED,			// The plugin died unexpectedly
+
+		MEDIA_EVENT_AUTH_REQUEST,			// The plugin wants to display an auth dialog
+
+		MEDIA_EVENT_LINK_HOVERED			// Got a "link hovered" event from the plugin
 		
 	} EMediaEvent;
 	
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 864f3f699e26096acd7b6746533f8f50e5ada495..33ab2e93b5cf8c7b0f4c3fc692421395880f736e 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -111,6 +111,7 @@ set(llui_SOURCE_FILES
     llviewmodel.cpp
     llview.cpp
     llviewquery.cpp
+    llwindowshade.cpp
     )
     
 set(llui_HEADER_FILES
@@ -210,6 +211,7 @@ set(llui_HEADER_FILES
     llviewmodel.h
     llview.h
     llviewquery.h
+    llwindowshade.h
     )
 
 set_source_files_properties(${llui_HEADER_FILES}
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index ac30fce39236297601fafae6939a792f030ec055..19ac4c58a851be16bd8f8e734b048a0ebaf26508 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -38,6 +38,12 @@
 static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");
 static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel");
 
+void LLLayoutStack::OrientationNames::declareValues()
+{
+	declare("horizontal", HORIZONTAL);
+	declare("vertical", VERTICAL);
+}
+
 //
 // LLLayoutPanel
 //
@@ -47,47 +53,47 @@ LLLayoutPanel::LLLayoutPanel(const Params& p)
  	mMaxDim(p.max_dim), 
  	mAutoResize(p.auto_resize),
  	mUserResize(p.user_resize),
-		mCollapsed(FALSE),
-		mCollapseAmt(0.f),
-		mVisibleAmt(1.f), // default to fully visible
-		mResizeBar(NULL) 
-	{
+	mCollapsed(FALSE),
+	mCollapseAmt(0.f),
+	mVisibleAmt(1.f), // default to fully visible
+	mResizeBar(NULL) 
+{
 	// panels initialized as hidden should not start out partially visible
 	if (!getVisible())
-		{
+	{
 		mVisibleAmt = 0.f;
-		}
-		}
+	}
+}
 
 void LLLayoutPanel::initFromParams(const Params& p)
-		{
+{
 	LLPanel::initFromParams(p);
 	setFollowsNone();
-	}
+}
 
 
 LLLayoutPanel::~LLLayoutPanel()
-	{
-		// probably not necessary, but...
-		delete mResizeBar;
-		mResizeBar = NULL;
-	}
+{
+	// probably not necessary, but...
+	delete mResizeBar;
+	mResizeBar = NULL;
+}
 	
 F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)
-	{
+{
 	if (orientation == LLLayoutStack::HORIZONTAL)
-		{
-			F32 collapse_amt = 
-			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));
-			return mVisibleAmt * collapse_amt;
-		}
-		else
+	{
+		F32 collapse_amt = 
+		clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));
+		return mVisibleAmt * collapse_amt;
+	}
+	else
 	{
 			F32 collapse_amt = 
 			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight())));
 			return mVisibleAmt * collapse_amt;
-		}
 	}
+}
 
 //
 // LLLayoutStack
@@ -109,7 +115,7 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
 	mMinWidth(0),
 	mMinHeight(0),
 	mPanelSpacing(p.border_size),
-	mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),
+	mOrientation(p.orientation),
 	mAnimate(p.animate),
 	mAnimatedThisFrame(false),
 	mClip(p.clip),
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 2fc6164d7ad02847338f32fadf5e1d76df36da39..4ac8ef0ee9a66ccd299d56fbf85bcabd293bd9e9 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -37,12 +37,24 @@ class LLLayoutPanel;
 class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
 {
 public:
+	typedef enum e_layout_orientation
+	{
+		HORIZONTAL,
+		VERTICAL
+	} ELayoutOrientation;
+
+	struct OrientationNames
+	:	public LLInitParam::TypeValuesHelper<ELayoutOrientation, OrientationNames>
+	{
+		static void declareValues();
+	};
+
 	struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry>
 	{};
 
 	struct Params : public LLInitParam::Block<Params, LLView::Params>
 	{
-		Mandatory<std::string>	orientation;
+		Mandatory<ELayoutOrientation, OrientationNames>	orientation;
 		Optional<S32>			border_size;
 		Optional<bool>			animate,
 								clip;
@@ -54,12 +66,6 @@ class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
 
 	typedef LayoutStackRegistry child_registry_t;
 
-	typedef enum e_layout_orientation
-	{
-		HORIZONTAL,
-		VERTICAL
-	} ELayoutOrientation;
-
 	virtual ~LLLayoutStack();
 
 	/*virtual*/ void draw();
@@ -171,6 +177,9 @@ friend class LLUICtrlFactory;
 	~LLLayoutPanel();
 
 	void initFromParams(const Params& p);
+	void setMinDim(S32 value) { mMinDim = value; }
+	void setMaxDim(S32 value) { mMaxDim = value; }
+
 protected:
 	LLLayoutPanel(const Params& p)	;
 
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index aed391c780ef79cf2b4c1a3325b1028cf974ea8b..7e348656a92a63fa5d2755af8e9bfdc280f9798f 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -88,6 +88,7 @@ LLLineEditor::Params::Params()
 	revert_on_esc("revert_on_esc", true),
 	commit_on_focus_lost("commit_on_focus_lost", true),
 	ignore_tab("ignore_tab", true),
+	is_password("is_password", false),
 	cursor_color("cursor_color"),
 	text_color("text_color"),
 	text_readonly_color("text_readonly_color"),
@@ -129,7 +130,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
 	mBorderThickness( 0 ),
 	mIgnoreArrowKeys( FALSE ),
 	mIgnoreTab( p.ignore_tab ),
-	mDrawAsterixes( FALSE ),
+	mDrawAsterixes( p.is_password ),
 	mSelectAllonFocusReceived( p.select_on_focus ),
 	mPassDelete(FALSE),
 	mReadOnly(FALSE),
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index ce2dfdeeb8e74f6648f7094ca22160f679d41dca..723423a5b9c2e8ffd46850672109db076356bc11 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -85,7 +85,8 @@ class LLLineEditor
 		Optional<bool>					select_on_focus,
 										revert_on_esc,
 										commit_on_focus_lost,
-										ignore_tab;
+										ignore_tab,
+										is_password;
 
 		// colors
 		Optional<LLUIColor>				cursor_color,
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index c347e1579257f163cd6f176c44b7e2068eb70987..cd0f0e36b0509d5d40bc311b4d5f8c2be8589ac7 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -82,6 +82,7 @@ LLNotificationForm::FormButton::FormButton()
 
 LLNotificationForm::FormInput::FormInput()
 :	type("type"),
+	text("text"),
 	max_length_chars("max_length_chars"),
 	width("width", 0),
 	value("value")
@@ -421,7 +422,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
 		it != end_it;
 		++it)
 	{
-		mUniqueContext.push_back(it->key);
+		mUniqueContext.push_back(it->value);
 	}
 	
 	lldebugs << "notification \"" << mName << "\": tag count is " << p.tags.size() << llendl;
@@ -792,13 +793,19 @@ bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
 	{
 		const LLSD& these_substitutions = this->getSubstitutions();
 		const LLSD& those_substitutions = that->getSubstitutions();
+		const LLSD& this_payload = this->getPayload();
+		const LLSD& that_payload = that->getPayload();
 
 		// highlander bit sez there can only be one of these
 		for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end();
 			it != end_it;
 			++it)
 		{
-			if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString())
+			// if templates differ in either substitution strings or payload with the given field name
+			// then they are considered inequivalent
+			// use of get() avoids converting the LLSD value to a map as the [] operator would
+			if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString()
+				|| this_payload.get(*it).asString() != that_payload.get(*it).asString())
 			{
 				return false;
 			}
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index f8f44699587ce70ed42a4b39c8b49dcaddd7e1db..34d3537781ba66df29fa789df743739e507605ed 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -195,6 +195,7 @@ class LLNotificationForm
 		Mandatory<std::string>	type;
 		Optional<S32>			width;
 		Optional<S32>			max_length_chars;
+		Optional<std::string>	text;
 
 		Optional<std::string>	value;
 		FormInput();
diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h
index 5a6ab40a2e4e0160de10e58d978a706092aeb520..eff572b553f0c5413d3ee6f5c846de13f92c6a5e 100644
--- a/indra/llui/llnotificationtemplate.h
+++ b/indra/llui/llnotificationtemplate.h
@@ -74,11 +74,13 @@ struct LLNotificationTemplate
 
 	struct UniquenessContext : public LLInitParam::Block<UniquenessContext>
 	{
-		Mandatory<std::string>	key;
+		Mandatory<std::string>	value;
 
 		UniquenessContext()
-		:	key("key")
-		{}
+		:	value("value")
+		{
+			addSynonym(value, "key");
+		}
 		
 	};
 
@@ -88,7 +90,7 @@ struct LLNotificationTemplate
 		// this idiom allows 
 		// <notification unique="true">
 		// as well as
-		// <notification> <unique> <context key=""/> </unique>...
+		// <notification> <unique> <context></context> </unique>...
 		Optional<bool>			dummy_val;
 	public:
 		Multiple<UniquenessContext>	contexts;
@@ -243,8 +245,8 @@ struct LLNotificationTemplate
     // (used for things like progress indications, or repeating warnings
     // like "the grid is going down in N minutes")
     bool mUnique;
-    // if we want to be unique only if a certain part of the payload is constant
-    // specify the field names for the payload. The notification will only be
+    // if we want to be unique only if a certain part of the payload or substitutions args
+	// are constant specify the field names for the payload. The notification will only be
     // combined if all of the fields named in the context are identical in the
     // new and the old notification; otherwise, the notification will be
     // duplicated. This is to support suppressing duplicate offers from the same
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index afd60cbb3ee0491096d43e612b86eef82ea9c42d..0a06b5e74f6b38480b9f1e3df73b9fd69687c2a8 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -827,7 +827,7 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot()
 {
 	LLUICtrl* focus_root = NULL;
 	LLUICtrl* next_view = this;
-	while(next_view)
+	while(next_view && next_view->hasTabStop())
 	{
 		if (next_view->isFocusRoot())
 		{
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index a5d8e31640ea23ca846294e4cdaec7cb40db9c52..d2bbd663b85b3175cf44739fadfa458a511ea165 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -413,14 +413,9 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	
 	LLControlVariable *findControl(const std::string& name);
 
-    // Moved setValue(), getValue(), setControlValue(), setControlName(),
-    // controlListener() to LLUICtrl because an LLView is NOT assumed to
-    // contain a value. If that's what you want, use LLUICtrl instead.
-//	virtual bool	handleEvent(LLPointer<LLEvent> event, const LLSD& userdata);
-
 	const child_list_t*	getChildList() const { return &mChildList; }
-	const child_list_const_iter_t	beginChild()  { return mChildList.begin(); }
-	const child_list_const_iter_t	endChild()  { return mChildList.end(); }
+	child_list_const_iter_t	beginChild() const { return mChildList.begin(); }
+	child_list_const_iter_t	endChild() const { return mChildList.end(); }
 
 	// LLMouseHandler functions
 	//  Default behavior is to pass events to children
diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..77e94385d424eedb561bf3837e1a10096bfa86eb
--- /dev/null
+++ b/indra/llui/llwindowshade.cpp
@@ -0,0 +1,328 @@
+/**
+ * @file LLWindowShade.cpp
+ * @brief Notification dialog that slides down and optionally disabled a piece of UI
+ *
+ * $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"
+#include "llwindowshade.h"
+
+#include "lllayoutstack.h"
+#include "lltextbox.h"
+#include "lliconctrl.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "lllineeditor.h"
+
+const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30;
+const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100;
+
+LLWindowShade::Params::Params()
+:	bg_image("bg_image"),
+	modal("modal", false),
+	text_color("text_color"),
+	can_close("can_close", true)
+{
+	mouse_opaque = false;
+}
+
+LLWindowShade::LLWindowShade(const LLWindowShade::Params& params)
+:	LLUICtrl(params),
+	mNotification(params.notification),
+	mModal(params.modal),
+	mFormHeight(0),
+	mTextColor(params.text_color)
+{
+	setFocusRoot(true);
+}
+
+void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
+{
+	LLUICtrl::initFromParams(params);
+
+	LLLayoutStack::Params layout_p;
+	layout_p.name = "notification_stack";
+	layout_p.rect = params.rect;
+	layout_p.follows.flags = FOLLOWS_ALL;
+	layout_p.mouse_opaque = false;
+	layout_p.orientation = LLLayoutStack::VERTICAL;
+	layout_p.border_size = 0;
+
+	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
+	addChild(stackp);
+
+	LLLayoutPanel::Params panel_p;
+	panel_p.rect = LLRect(0, 30, 800, 0);
+	panel_p.name = "notification_area";
+	panel_p.visible = false;
+	panel_p.user_resize = false;
+	panel_p.background_visible = true;
+	panel_p.bg_alpha_image = params.bg_image;
+	panel_p.auto_resize = false;
+	LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+	stackp->addChild(notification_panel);
+
+	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+	panel_p.auto_resize = true;
+	panel_p.user_resize = false;
+	panel_p.rect = params.rect;
+	panel_p.name = "background_area";
+	panel_p.mouse_opaque = false;
+	panel_p.background_visible = false;
+	panel_p.bg_alpha_color = LLColor4(0.f, 0.f, 0.f, 0.2f);
+	LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+	stackp->addChild(dummy_panel);
+
+	layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>();
+	layout_p.rect = LLRect(0, 30, 800, 0);
+	layout_p.follows.flags = FOLLOWS_ALL;
+	layout_p.orientation = LLLayoutStack::HORIZONTAL;
+	stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
+	notification_panel->addChild(stackp);
+
+	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+	panel_p.rect.height = 30;
+	LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+	stackp->addChild(panel);
+
+	LLIconCtrl::Params icon_p;
+	icon_p.name = "notification_icon";
+	icon_p.rect = LLRect(5, 23, 21, 8);
+	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
+
+	LLTextBox::Params text_p;
+	text_p.rect = LLRect(31, 20, panel->getRect().getWidth() - 5, 0);
+	text_p.follows.flags = FOLLOWS_ALL;
+	text_p.text_color = mTextColor;
+	text_p.font = LLFontGL::getFontSansSerifSmall();
+	text_p.font.style = "BOLD";
+	text_p.name = "notification_text";
+	text_p.use_ellipses = true;
+	text_p.wrap = true;
+	panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
+
+	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+	panel_p.auto_resize = false;
+	panel_p.user_resize = false;
+	panel_p.name="form_elements";
+	panel_p.rect = LLRect(0, 30, 130, 0);
+	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+	stackp->addChild(form_elements_panel);
+
+	if (params.can_close)
+	{
+		panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+		panel_p.auto_resize = false;
+		panel_p.user_resize = false;
+		panel_p.rect = LLRect(0, 30, 25, 0);
+		LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+		stackp->addChild(close_panel);
+
+		LLButton::Params button_p;
+		button_p.name = "close_notification";
+		button_p.rect = LLRect(5, 23, 21, 7);
+		button_p.image_color.control="DkGray_66";
+		button_p.image_unselected.name="Icon_Close_Foreground";
+		button_p.image_selected.name="Icon_Close_Press";
+		button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this);
+
+		close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
+	}
+
+	LLSD payload = mNotification->getPayload();
+
+	LLNotificationFormPtr formp = mNotification->getForm();
+	LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area");
+	notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon());
+	notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage());
+	notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage());
+
+	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); 
+	LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements");
+	form_elements.deleteAllChildren();
+
+	const S32 FORM_PADDING_HORIZONTAL = 10;
+	const S32 FORM_PADDING_VERTICAL = 3;
+	const S32 WIDGET_HEIGHT = 24;
+	const S32 LINE_EDITOR_WIDTH = 120;
+	S32 cur_x = FORM_PADDING_HORIZONTAL;
+	S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT;
+	S32 form_width = cur_x;
+
+	if (ignore_type != LLNotificationForm::IGNORE_NO)
+	{
+		LLCheckBoxCtrl::Params checkbox_p;
+		checkbox_p.name = "ignore_check";
+		checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
+		checkbox_p.label = formp->getIgnoreMessage();
+		checkbox_p.label_text.text_color = LLColor4::black;
+		checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1);
+		checkbox_p.initial_value = formp->getIgnored();
+
+		LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
+		check->setRect(check->getBoundingRect());
+		form_elements.addChild(check);
+		cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL;
+		form_width = llmax(form_width, cur_x);
+	}
+
+	for (S32 i = 0; i < formp->getNumElements(); i++)
+	{
+		LLSD form_element = formp->getElement(i);
+		std::string type = form_element["type"].asString();
+		if (type == "button")
+		{
+			LLButton::Params button_p;
+			button_p.name = form_element["name"];
+			button_p.label = form_element["text"];
+			button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
+			button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString());
+			button_p.auto_resize = true;
+
+			LLButton* button = LLUICtrlFactory::create<LLButton>(button_p);
+			button->autoResize();
+			form_elements.addChild(button);
+
+			if (form_element["default"].asBoolean())
+			{
+				form_elements.setDefaultBtn(button);
+			}
+
+			cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
+			form_width = llmax(form_width, cur_x);
+		}
+		else if (type == "text" || type == "password")
+		{
+			// if not at beginning of line...
+			if (cur_x != FORM_PADDING_HORIZONTAL)
+			{
+				// start new line
+				cur_x = FORM_PADDING_HORIZONTAL;
+				cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
+			}
+			LLTextBox::Params label_p;
+			label_p.name = form_element["name"].asString() + "_label";
+			label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
+			label_p.initial_value = form_element["text"];
+			label_p.text_color = mTextColor;
+			label_p.font_valign = LLFontGL::VCENTER;
+			label_p.v_pad = 5;
+			LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);
+			textbox->reshapeToFitText();
+			textbox->reshape(textbox->getRect().getWidth(), form_elements.getRect().getHeight() - 2 * FORM_PADDING_VERTICAL); 
+			form_elements.addChild(textbox);
+			cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL;
+
+			LLLineEditor::Params line_p;
+			line_p.name = form_element["name"];
+			line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString());
+			line_p.is_password = type == "password";
+			line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
+
+			LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p);
+			form_elements.addChild(line_editor);
+			form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL);
+
+			// reset to start of next line
+			cur_x = FORM_PADDING_HORIZONTAL;
+			cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
+		}
+	}
+
+	mFormHeight = form_elements.getRect().getHeight() - (cur_y - FORM_PADDING_VERTICAL) + WIDGET_HEIGHT;
+	form_elements.reshape(form_width, mFormHeight);
+	form_elements.setMinDim(form_width);
+
+	// move all form elements back onto form surface
+	S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y;
+	for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end();
+		it != end_it;
+		++it)
+	{
+		(*it)->translate(0, delta_y);
+	}
+}
+
+void LLWindowShade::show()
+{
+	getChildRef<LLLayoutPanel>("notification_area").setVisible(true);
+	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal);
+
+	setMouseOpaque(mModal);
+}
+
+void LLWindowShade::draw()
+{
+	LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect();
+
+	LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area");
+
+	notification_area->reshape(notification_area->getRect().getWidth(), 
+		llclamp(message_rect.getHeight() + 10, 
+				llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT),
+				MAX_NOTIFICATION_AREA_HEIGHT));
+
+	LLUICtrl::draw();
+	if (mNotification && !mNotification->isActive())
+	{
+		hide();
+	}
+}
+
+void LLWindowShade::hide()
+{
+	getChildRef<LLLayoutPanel>("notification_area").setVisible(false);
+	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
+
+	setMouseOpaque(false);
+}
+
+void LLWindowShade::onCloseNotification()
+{
+	LLNotifications::instance().cancel(mNotification);
+}
+
+void LLWindowShade::onClickIgnore(LLUICtrl* ctrl)
+{
+	bool check = ctrl->getValue().asBoolean();
+	if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
+	{
+		// question was "show again" so invert value to get "ignore"
+		check = !check;
+	}
+	mNotification->setIgnored(check);
+}
+
+void LLWindowShade::onClickNotificationButton(const std::string& name)
+{
+	if (!mNotification) return;
+
+	mNotificationResponse[name] = true;
+
+	mNotification->respond(mNotificationResponse);
+}
+
+void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
+{
+	mNotificationResponse[name] = ctrl->getValue().asString();
+}
diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h
new file mode 100644
index 0000000000000000000000000000000000000000..00471959296dd0429d0f500f5911e6d9b28756ff
--- /dev/null
+++ b/indra/llui/llwindowshade.h
@@ -0,0 +1,69 @@
+/**
+ * @file llwindowshade.h
+ * @brief Notification dialog that slides down and optionally disabled a piece of UI
+ *
+ * $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$
+ */
+
+#ifndef LL_LLWINDOWSHADE_H
+#define LL_LLWINDOWSHADE_H
+
+#include "lluictrl.h"
+#include "llnotifications.h"
+
+class LLWindowShade : public LLUICtrl
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Mandatory<LLNotificationPtr>	notification;
+		Optional<LLUIImage*>			bg_image;
+		Optional<LLUIColor>				text_color;
+		Optional<bool>					modal,
+										can_close;
+
+		Params();
+	};
+
+	void show();
+	/*virtual*/ void draw();
+	void hide();
+
+private:
+	friend class LLUICtrlFactory;
+
+	LLWindowShade(const Params& p);
+	void initFromParams(const Params& params);
+
+	void onCloseNotification();
+	void onClickNotificationButton(const std::string& name);
+	void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name);
+	void onClickIgnore(LLUICtrl* ctrl);
+
+	LLNotificationPtr	mNotification;
+	LLSD				mNotificationResponse;
+	bool				mModal;
+	S32					mFormHeight;
+	LLUIColor			mTextColor;
+};
+
+#endif // LL_LLWINDOWSHADE_H
diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt
index 44f98e5e18c3371a01c65c4ac090467563f6ce98..a4a6b50c6c14fbfc18e733b043a9c5485b143804 100644
--- a/indra/mac_updater/CMakeLists.txt
+++ b/indra/mac_updater/CMakeLists.txt
@@ -3,6 +3,7 @@
 project(mac_updater)
 
 include(00-Common)
+include(OpenSSL)
 include(CURL)
 include(LLCommon)
 include(LLVFS)
@@ -49,6 +50,8 @@ set_target_properties(mac-updater
 
 target_link_libraries(mac-updater
     ${LLVFS_LIBRARIES}
+    ${OPENSSL_LIBRARIES}
+    ${CRYPTO_LIBRARIES}
     ${CURL_LIBRARIES}
     ${LLCOMMON_LIBRARIES}
     )
diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp
index f8a871930ecdd7fd467f80006606ef33ca606014..da7de0179908f03a9041e6f6106dee1783356d5f 100644
--- a/indra/media_plugins/example/media_plugin_example.cpp
+++ b/indra/media_plugins/example/media_plugin_example.cpp
@@ -6,21 +6,21 @@
  * $LicenseInfo:firstyear=2008&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$
  * @endcond
@@ -39,48 +39,48 @@
 ////////////////////////////////////////////////////////////////////////////////
 //
 class MediaPluginExample :
-		public MediaPluginBase
+        public MediaPluginBase
 {
-	public:
-		MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data );
-		~MediaPluginExample();
-
-		/*virtual*/ void receiveMessage( const char* message_string );
-
-	private:
-		bool init();
-		void update( F64 milliseconds );
-		void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b );
-		bool mFirstTime;
-
-		time_t mLastUpdateTime;
-		enum Constants { ENumObjects = 10 };
-		unsigned char* mBackgroundPixels;
-		int mColorR[ ENumObjects ];
-		int mColorG[ ENumObjects ];
-		int mColorB[ ENumObjects ];
-		int mXpos[ ENumObjects ];
-		int mYpos[ ENumObjects ];
-		int mXInc[ ENumObjects ];
-		int mYInc[ ENumObjects ];
-		int mBlockSize[ ENumObjects ];
-		bool mMouseButtonDown;
-		bool mStopAction;
+    public:
+        MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data );
+        ~MediaPluginExample();
+
+        /*virtual*/ void receiveMessage( const char* message_string );
+
+    private:
+        bool init();
+        void update( F64 milliseconds );
+        void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b );
+        bool mFirstTime;
+
+        time_t mLastUpdateTime;
+        enum Constants { ENumObjects = 10 };
+        unsigned char* mBackgroundPixels;
+        int mColorR[ ENumObjects ];
+        int mColorG[ ENumObjects ];
+        int mColorB[ ENumObjects ];
+        int mXpos[ ENumObjects ];
+        int mYpos[ ENumObjects ];
+        int mXInc[ ENumObjects ];
+        int mYInc[ ENumObjects ];
+        int mBlockSize[ ENumObjects ];
+        bool mMouseButtonDown;
+        bool mStopAction;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //
 MediaPluginExample::MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ) :
-	MediaPluginBase( host_send_func, host_user_data )
+    MediaPluginBase( host_send_func, host_user_data )
 {
-	mFirstTime = true;
-	mWidth = 0;
-	mHeight = 0;
-	mDepth = 4;
-	mPixels = 0;
-	mMouseButtonDown = false;
-	mStopAction = false;
-	mLastUpdateTime = 0;
+    mFirstTime = true;
+    mWidth = 0;
+    mHeight = 0;
+    mDepth = 4;
+    mPixels = 0;
+    mMouseButtonDown = false;
+    mStopAction = false;
+    mLastUpdateTime = 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -93,395 +93,320 @@ MediaPluginExample::~MediaPluginExample()
 //
 void MediaPluginExample::receiveMessage( const char* message_string )
 {
-	LLPluginMessage message_in;
-
-	if ( message_in.parse( message_string ) >= 0 )
-	{
-		std::string message_class = message_in.getClass();
-		std::string message_name = message_in.getName();
-
-		if ( message_class == LLPLUGIN_MESSAGE_CLASS_BASE )
-		{
-			if ( message_name == "init" )
-			{
-				LLPluginMessage message( "base", "init_response" );
-				LLSD versions = LLSD::emptyMap();
-				versions[ LLPLUGIN_MESSAGE_CLASS_BASE ] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
-				versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
-				versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
-				message.setValueLLSD( "versions", versions );
-
-				std::string plugin_version = "Example media plugin, Example Version 1.0.0.0";
-				message.setValue( "plugin_version", plugin_version );
-				sendMessage( message );
-			}
-			else
-			if ( message_name == "idle" )
-			{
-				// no response is necessary here.
-				F64 time = message_in.getValueReal( "time" );
-
-				// Convert time to milliseconds for update()
-				update( time );
-			}
-			else
-			if ( message_name == "cleanup" )
-			{
-				// clean up here
-			}
-			else
-			if ( message_name == "shm_added" )
-			{
-				SharedSegmentInfo info;
-				info.mAddress = message_in.getValuePointer( "address" );
-				info.mSize = ( size_t )message_in.getValueS32( "size" );
-				std::string name = message_in.getValue( "name" );
-
-				mSharedSegments.insert( SharedSegmentMap::value_type( name, info ) );
-
-			}
-			else
-			if ( message_name == "shm_remove" )
-			{
-				std::string name = message_in.getValue( "name" );
-
-				SharedSegmentMap::iterator iter = mSharedSegments.find( name );
-				if( iter != mSharedSegments.end() )
-				{
-					if ( mPixels == iter->second.mAddress )
-					{
-						// This is the currently active pixel buffer.
-						// Make sure we stop drawing to it.
-						mPixels = NULL;
-						mTextureSegmentName.clear();
-					};
-					mSharedSegments.erase( iter );
-				}
-				else
-				{
-					//std::cerr << "MediaPluginExample::receiveMessage: unknown shared memory region!" << std::endl;
-				};
-
-				// Send the response so it can be cleaned up.
-				LLPluginMessage message( "base", "shm_remove_response" );
-				message.setValue( "name", name );
-				sendMessage( message );
-			}
-			else
-			{
-				//std::cerr << "MediaPluginExample::receiveMessage: unknown base message: " << message_name << std::endl;
-			};
-		}
-		else
-		if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA )
-		{
-			if ( message_name == "init" )
-			{
-				// Plugin gets to decide the texture parameters to use.
-				LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params" );
-				message.setValueS32( "default_width", mWidth );
-				message.setValueS32( "default_height", mHeight );
-				message.setValueS32( "depth", mDepth );
-				message.setValueU32( "internalformat", GL_RGBA );
-				message.setValueU32( "format", GL_RGBA );
-				message.setValueU32( "type", GL_UNSIGNED_BYTE );
-				message.setValueBoolean( "coords_opengl", false );
-				sendMessage( message );
-			}
-			else if ( message_name == "size_change" )
-			{
-				std::string name = message_in.getValue( "name" );
-				S32 width = message_in.getValueS32( "width" );
-				S32 height = message_in.getValueS32( "height" );
-				S32 texture_width = message_in.getValueS32( "texture_width" );
-				S32 texture_height = message_in.getValueS32( "texture_height" );
-
-				if ( ! name.empty() )
-				{
-					// Find the shared memory region with this name
-					SharedSegmentMap::iterator iter = mSharedSegments.find( name );
-					if ( iter != mSharedSegments.end() )
-					{
-						mPixels = ( unsigned char* )iter->second.mAddress;
-						mWidth = width;
-						mHeight = height;
-
-						mTextureWidth = texture_width;
-						mTextureHeight = texture_height;
-
-						init();
-					};
-				};
-
-				LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response" );
-				message.setValue( "name", name );
-				message.setValueS32( "width", width );
-				message.setValueS32( "height", height );
-				message.setValueS32( "texture_width", texture_width );
-				message.setValueS32( "texture_height", texture_height );
-				sendMessage( message );
-			}
-			else
-			if ( message_name == "load_uri" )
-			{
-				std::string uri = message_in.getValue( "uri" );
-				if ( ! uri.empty() )
-				{
-				};
-			}
-			else
-			if ( message_name == "mouse_event" )
-			{
-				std::string event = message_in.getValue( "event" );
-				S32 button = message_in.getValueS32( "button" );
-
-				// left mouse button
-				if ( button == 0 )
-				{
-					int mouse_x = message_in.getValueS32( "x" );
-					int mouse_y = message_in.getValueS32( "y" );
-					std::string modifiers = message_in.getValue( "modifiers" );
-
-					if ( event == "move" )
-					{
-						if ( mMouseButtonDown )
-							write_pixel( mouse_x, mouse_y, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80 );
-					}
-					else
-					if ( event == "down" )
-					{
-						mMouseButtonDown = true;
-					}
-					else
-					if ( event == "up" )
-					{
-						mMouseButtonDown = false;
-					}
-					else
-					if ( event == "double_click" )
-					{
-					};
-				};
-			}
-			else
-			if ( message_name == "key_event" )
-			{
-				std::string event = message_in.getValue( "event" );
-				S32 key = message_in.getValueS32( "key" );
-				std::string modifiers = message_in.getValue( "modifiers" );
-
-				if ( event == "down" )
-				{
-					if ( key == ' ')
-					{
-						mLastUpdateTime = 0;
-						update( 0.0f );
-					};
-				};
-			}
-			else
-			{
-				//std::cerr << "MediaPluginExample::receiveMessage: unknown media message: " << message_string << std::endl;
-			};
-		}
-		else
-		if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER )
-		{
-			if ( message_name == "browse_reload" )
-			{
-				mLastUpdateTime = 0;
-				mFirstTime = true;
-				mStopAction = false;
-				update( 0.0f );
-			}
-			else
-			if ( message_name == "browse_stop" )
-			{
-				for( int n = 0; n < ENumObjects; ++n )
-					mXInc[ n ] = mYInc[ n ] = 0;
-
-				mStopAction = true;
-				update( 0.0f );
-			}
-			else
-			{
-				//std::cerr << "MediaPluginExample::receiveMessage: unknown media_browser message: " << message_string << std::endl;
-			};
-		}
-		else
-		{
-			//std::cerr << "MediaPluginExample::receiveMessage: unknown message class: " << message_class << std::endl;
-		};
-	};
+//  std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+    LLPluginMessage message_in;
+
+    if(message_in.parse(message_string) >= 0)
+    {
+        std::string message_class = message_in.getClass();
+        std::string message_name = message_in.getName();
+        if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+        {
+            if(message_name == "init")
+            {
+                LLPluginMessage message("base", "init_response");
+                LLSD versions = LLSD::emptyMap();
+                versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
+                message.setValueLLSD("versions", versions);
+
+                std::string plugin_version = "Example plugin 1.0..0";
+                message.setValue("plugin_version", plugin_version);
+                sendMessage(message);
+            }
+            else if(message_name == "idle")
+            {
+                // no response is necessary here.
+                F64 time = message_in.getValueReal("time");
+
+                // Convert time to milliseconds for update()
+                update((int)(time * 1000.0f));
+            }
+            else if(message_name == "cleanup")
+            {
+            }
+            else if(message_name == "shm_added")
+            {
+                SharedSegmentInfo info;
+                info.mAddress = message_in.getValuePointer("address");
+                info.mSize = (size_t)message_in.getValueS32("size");
+                std::string name = message_in.getValue("name");
+
+                mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+            }
+            else if(message_name == "shm_remove")
+            {
+                std::string name = message_in.getValue("name");
+
+                SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+                if(iter != mSharedSegments.end())
+                {
+                    if(mPixels == iter->second.mAddress)
+                    {
+                        // This is the currently active pixel buffer.  Make sure we stop drawing to it.
+                        mPixels = NULL;
+                        mTextureSegmentName.clear();
+                    }
+                    mSharedSegments.erase(iter);
+                }
+                else
+                {
+//                  std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
+                }
+
+                // Send the response so it can be cleaned up.
+                LLPluginMessage message("base", "shm_remove_response");
+                message.setValue("name", name);
+                sendMessage(message);
+            }
+            else
+            {
+//              std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
+            }
+        }
+        else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+        {
+            if(message_name == "init")
+            {
+                // Plugin gets to decide the texture parameters to use.
+                mDepth = 4;
+                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+                message.setValueS32("default_width", 1024);
+                message.setValueS32("default_height", 1024);
+                message.setValueS32("depth", mDepth);
+                message.setValueU32("internalformat", GL_RGBA);
+                message.setValueU32("format", GL_RGBA);
+                message.setValueU32("type", GL_UNSIGNED_BYTE);
+                message.setValueBoolean("coords_opengl", true);
+                sendMessage(message);
+            }
+            else if(message_name == "size_change")
+            {
+                std::string name = message_in.getValue("name");
+                S32 width = message_in.getValueS32("width");
+                S32 height = message_in.getValueS32("height");
+                S32 texture_width = message_in.getValueS32("texture_width");
+                S32 texture_height = message_in.getValueS32("texture_height");
+
+                if(!name.empty())
+                {
+                    // Find the shared memory region with this name
+                    SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+                    if(iter != mSharedSegments.end())
+                    {
+                        mPixels = (unsigned char*)iter->second.mAddress;
+                        mWidth = width;
+                        mHeight = height;
+
+                        mTextureWidth = texture_width;
+                        mTextureHeight = texture_height;
+                    };
+                };
+
+                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+                message.setValue("name", name);
+                message.setValueS32("width", width);
+                message.setValueS32("height", height);
+                message.setValueS32("texture_width", texture_width);
+                message.setValueS32("texture_height", texture_height);
+                sendMessage(message);
+
+            }
+            else if(message_name == "load_uri")
+            {
+            }
+            else if(message_name == "mouse_event")
+            {
+                std::string event = message_in.getValue("event");
+                if(event == "down")
+                {
+
+                }
+                else if(event == "up")
+                {
+                }
+                else if(event == "double_click")
+                {
+                }
+            }
+        }
+        else
+        {
+//          std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
+        };
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //
 void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b )
 {
-	// make sure we don't write outside the buffer
-	if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) )
-		return;
-		
-	if ( mBackgroundPixels != NULL )
-	{
-		unsigned char *pixel = mBackgroundPixels;
-		pixel += y * mWidth * mDepth;
-		pixel += ( x * mDepth );
-		pixel[ 0 ] = b;
-		pixel[ 1 ] = g;
-		pixel[ 2 ] = r;
-
-		setDirty( x, y, x + 1, y + 1 );
-	};
+    // make sure we don't write outside the buffer
+    if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) )
+        return;
+
+    if ( mBackgroundPixels != NULL )
+    {
+        unsigned char *pixel = mBackgroundPixels;
+        pixel += y * mWidth * mDepth;
+        pixel += ( x * mDepth );
+        pixel[ 0 ] = b;
+        pixel[ 1 ] = g;
+        pixel[ 2 ] = r;
+
+        setDirty( x, y, x + 1, y + 1 );
+    };
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //
 void MediaPluginExample::update( F64 milliseconds )
 {
-	if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 )
-		return;
-
-	if ( mPixels == 0 )
-			return;
-
-	if ( mFirstTime )
-	{
-		for( int n = 0; n < ENumObjects; ++n )
-		{
-			mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 );
-			mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 );
-
-			mColorR[ n ] = rand() % 0x60 + 0x60;
-			mColorG[ n ] = rand() % 0x60 + 0x60;
-			mColorB[ n ] = rand() % 0x60 + 0x60;
-
-			mXInc[ n ] = 0;
-			while ( mXInc[ n ] == 0 )
-				mXInc[ n ] = rand() % 7 - 3;
-
-			mYInc[ n ] = 0;
-			while ( mYInc[ n ] == 0 )
-				mYInc[ n ] = rand() % 9 - 4;
-
-			mBlockSize[ n ] = rand() % 0x30 + 0x10;
-		};
-
-		delete [] mBackgroundPixels;
-				
-		mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ];
-
-		mFirstTime = false;
-	};
-
-	if ( mStopAction )
-		return;
-
-	if ( time( NULL ) > mLastUpdateTime + 3 )
-	{
-		const int num_squares = rand() % 20 + 4;
-		int sqr1_r = rand() % 0x80 + 0x20;
-		int sqr1_g = rand() % 0x80 + 0x20;
-		int sqr1_b = rand() % 0x80 + 0x20;
-		int sqr2_r = rand() % 0x80 + 0x20;
-		int sqr2_g = rand() % 0x80 + 0x20;
-		int sqr2_b = rand() % 0x80 + 0x20;
-
-		for ( int y1 = 0; y1 < num_squares; ++y1 )
-		{
-			for ( int x1 = 0; x1 < num_squares; ++x1 )
-			{
-				int px_start = mWidth * x1 / num_squares;
-				int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares;
-				int py_start = mHeight * y1 / num_squares;
-				int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares;
-
-				for( int y2 = py_start; y2 < py_end; ++y2 )
-				{
-					for( int x2 = px_start; x2 < px_end; ++x2 )
-					{
-						int rowspan = mWidth * mDepth;
-
-						if ( ( y1 % 2 ) ^ ( x1 % 2 ) )
-						{
-							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r;
-							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g;
-							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b;
-						}
-						else
-						{
-							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r;
-							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g;
-							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b;
-						};
-					};
-				};
-			};
-		};
-
-		time( &mLastUpdateTime );
-	};
-
-	memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth );
-
-	for( int n = 0; n < ENumObjects; ++n )
-	{
-		if ( rand() % 50 == 0 )
-		{
-				mXInc[ n ] = 0;
-				while ( mXInc[ n ] == 0 )
-					mXInc[ n ] = rand() % 7 - 3;
-
-				mYInc[ n ] = 0;
-				while ( mYInc[ n ] == 0 )
-					mYInc[ n ] = rand() % 9 - 4;
-		};
-
-		if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] )
-			mXInc[ n ] =- mXInc[ n ];
-
-		if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] )
-			mYInc[ n ] =- mYInc[ n ];
-
-		mXpos[ n ] += mXInc[ n ];
-		mYpos[ n ] += mYInc[ n ];
-
-		for( int y = 0; y < mBlockSize[ n ]; ++y )
-		{
-			for( int x = 0; x < mBlockSize[ n ]; ++x )
-			{
-				mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ];
-				mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ];
-				mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ];
-			};
-		};
-	};
-
-	setDirty( 0, 0, mWidth, mHeight );
+    if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 )
+        return;
+
+    if ( mPixels == 0 )
+            return;
+
+    if ( mFirstTime )
+    {
+        for( int n = 0; n < ENumObjects; ++n )
+        {
+            mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 );
+            mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 );
+
+            mColorR[ n ] = rand() % 0x60 + 0x60;
+            mColorG[ n ] = rand() % 0x60 + 0x60;
+            mColorB[ n ] = rand() % 0x60 + 0x60;
+
+            mXInc[ n ] = 0;
+            while ( mXInc[ n ] == 0 )
+                mXInc[ n ] = rand() % 7 - 3;
+
+            mYInc[ n ] = 0;
+            while ( mYInc[ n ] == 0 )
+                mYInc[ n ] = rand() % 9 - 4;
+
+            mBlockSize[ n ] = rand() % 0x30 + 0x10;
+        };
+
+        delete [] mBackgroundPixels;
+
+        mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ];
+
+        mFirstTime = false;
+    };
+
+    if ( mStopAction )
+        return;
+
+    if ( time( NULL ) > mLastUpdateTime + 3 )
+    {
+        const int num_squares = rand() % 20 + 4;
+        int sqr1_r = rand() % 0x80 + 0x20;
+        int sqr1_g = rand() % 0x80 + 0x20;
+        int sqr1_b = rand() % 0x80 + 0x20;
+        int sqr2_r = rand() % 0x80 + 0x20;
+        int sqr2_g = rand() % 0x80 + 0x20;
+        int sqr2_b = rand() % 0x80 + 0x20;
+
+        for ( int y1 = 0; y1 < num_squares; ++y1 )
+        {
+            for ( int x1 = 0; x1 < num_squares; ++x1 )
+            {
+                int px_start = mWidth * x1 / num_squares;
+                int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares;
+                int py_start = mHeight * y1 / num_squares;
+                int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares;
+
+                for( int y2 = py_start; y2 < py_end; ++y2 )
+                {
+                    for( int x2 = px_start; x2 < px_end; ++x2 )
+                    {
+                        int rowspan = mWidth * mDepth;
+
+                        if ( ( y1 % 2 ) ^ ( x1 % 2 ) )
+                        {
+                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r;
+                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g;
+                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b;
+                        }
+                        else
+                        {
+                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r;
+                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g;
+                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b;
+                        };
+                    };
+                };
+            };
+        };
+
+        time( &mLastUpdateTime );
+    };
+
+    memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth );
+
+    for( int n = 0; n < ENumObjects; ++n )
+    {
+        if ( rand() % 50 == 0 )
+        {
+                mXInc[ n ] = 0;
+                while ( mXInc[ n ] == 0 )
+                    mXInc[ n ] = rand() % 7 - 3;
+
+                mYInc[ n ] = 0;
+                while ( mYInc[ n ] == 0 )
+                    mYInc[ n ] = rand() % 9 - 4;
+        };
+
+        if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] )
+            mXInc[ n ] =- mXInc[ n ];
+
+        if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] )
+            mYInc[ n ] =- mYInc[ n ];
+
+        mXpos[ n ] += mXInc[ n ];
+        mYpos[ n ] += mYInc[ n ];
+
+        for( int y = 0; y < mBlockSize[ n ]; ++y )
+        {
+            for( int x = 0; x < mBlockSize[ n ]; ++x )
+            {
+                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ];
+                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ];
+                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ];
+            };
+        };
+    };
+
+    setDirty( 0, 0, mWidth, mHeight );
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //
 bool MediaPluginExample::init()
 {
-	LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" );
-	message.setValue( "name", "Example Plugin" );
-	sendMessage( message );
+    LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" );
+    message.setValue( "name", "Example Plugin" );
+    sendMessage( message );
 
-	return true;
+    return true;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //
 int init_media_plugin( LLPluginInstance::sendMessageFunction host_send_func,
-						void* host_user_data,
-						LLPluginInstance::sendMessageFunction *plugin_send_func,
-						void **plugin_user_data )
+                        void* host_user_data,
+                        LLPluginInstance::sendMessageFunction *plugin_send_func,
+                        void **plugin_user_data )
 {
-	MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data );
-	*plugin_send_func = MediaPluginExample::staticReceiveMessage;
-	*plugin_user_data = ( void* )self;
+    MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data );
+    *plugin_send_func = MediaPluginExample::staticReceiveMessage;
+    *plugin_user_data = ( void* )self;
 
-	return 0;
+    return 0;
 }
+
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index bd1a44a930702c885b62fd99853dd87e4517d979..d6f8ae3e16ae6d3b6a6aa58310cd06c4fe554ec3 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -341,7 +341,7 @@ class MediaPluginWebKit :
 		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
 		url << "%22%3E%3C/body%3E%3C/html%3E";
 		
-		lldebugs << "data url is: " << url.str() << llendl;
+		//lldebugs << "data url is: " << url.str() << llendl;
 					
 		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
 //		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
@@ -407,6 +407,8 @@ class MediaPluginWebKit :
 		{
 			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
 			message.setValue("uri", event.getEventUri());
+			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
+			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
 			sendMessage(message);
 		
 			setStatus(STATUS_LOADING);
@@ -569,6 +571,57 @@ class MediaPluginWebKit :
 		return blockingPickFile();
 	}
 	
+	std::string mAuthUsername;
+	std::string mAuthPassword;
+	bool mAuthOK;
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
+	{
+		mAuthOK = false;
+
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
+		message.setValue("url", in_url);
+		message.setValue("realm", in_realm);
+		message.setValueBoolean("blocking_request", true);
+				
+		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
+		sendMessage(message);
+		
+		if(mAuthOK)
+		{
+			out_username = mAuthUsername;
+			out_password = mAuthPassword;
+		}
+		
+		return mAuthOK;
+	}
+	
+	void authResponse(LLPluginMessage &message)
+	{
+		mAuthOK = message.getValueBoolean("ok");
+		if(mAuthOK)
+		{
+			mAuthUsername = message.getValue("username");
+			mAuthPassword = message.getValue("password");
+		}
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onLinkHovered(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
+			message.setValue("link", event.getEventUri());
+			message.setValue("title", event.getStringValue());
+			message.setValue("text", event.getStringValue2());
+			sendMessage(message);
+		}
+	}
+	
 	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
 	{
 		int result = 0;
@@ -1096,6 +1149,10 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
 			{
 				onPickFileResponse(message_in.getValue("file"));
 			}
+			if(message_name == "auth_response")
+			{
+				authResponse(message_in);
+			}
 			else
 			{
 //				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
@@ -1182,6 +1239,22 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
 				mUserAgent = message_in.getValue("user_agent");
 				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
 			}
+			else if(message_name == "ignore_ssl_cert_errors")
+			{
+#if LLQTWEBKIT_API_VERSION >= 3
+				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
+#else
+				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl;
+#endif
+			}
+			else if(message_name == "add_certificate_file_path")
+			{
+#if LLQTWEBKIT_API_VERSION >= 6
+				LLQtWebKit::getInstance()->addCAFile( message_in.getValue("path") );
+#else
+				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl;
+#endif
+			}
 			else if(message_name == "init_history")
 			{
 				// Initialize browser history
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1176edc130cbec6451b87d4ad4a97bac20d66283..8eb350da344b1ac9f3a24aa2ae6f93ff56ea98f7 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -50,6 +50,7 @@ include_directories(
     ${LLCHARACTER_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
     ${LLIMAGE_INCLUDE_DIRS}
+    ${LLKDU_INCLUDE_DIRS}
     ${LLINVENTORY_INCLUDE_DIRS}
     ${LLMATH_INCLUDE_DIRS}
     ${LLMESSAGE_INCLUDE_DIRS}
@@ -222,6 +223,7 @@ set(viewer_SOURCE_FILES
     llfloaterurlentry.cpp
     llfloatervoiceeffect.cpp
     llfloaterwater.cpp
+    llfloaterwebcontent.cpp
     llfloaterwhitelistentry.cpp
     llfloaterwindlight.cpp
     llfloaterwindowsize.cpp
@@ -758,6 +760,7 @@ set(viewer_HEADER_FILES
     llfloaterurlentry.h
     llfloatervoiceeffect.h
     llfloaterwater.h
+    llfloaterwebcontent.h
     llfloaterwhitelistentry.h
     llfloaterwindlight.h
     llfloaterwindowsize.h
@@ -1455,11 +1458,6 @@ if (WINDOWS)
     # In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py
     # and have the build deps get tracked *please* tell me about it.
 
-    if(LLKDU_LIBRARY)
-      # Configure a var for llkdu which may not exist for all builds.
-      set(LLKDU_DLL_SOURCE ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llkdu.dll)
-    endif(LLKDU_LIBRARY)
-
     if(USE_GOOGLE_PERFTOOLS)
       # Configure a var for tcmalloc location, if used.
       # Note the need to specify multiple names explicitly.
@@ -1476,7 +1474,6 @@ if (WINDOWS)
       #${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libtcmalloc_minimal.dll => None ... Skipping libtcmalloc_minimal.dll
       ${CMAKE_SOURCE_DIR}/../etc/message.xml
       ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
-      ${LLKDU_DLL_SOURCE}
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llcommon.dll
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll
       ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll
@@ -1662,7 +1659,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLAUDIO_LIBRARIES}
     ${LLCHARACTER_LIBRARIES}
     ${LLIMAGE_LIBRARIES}
-    ${LLIMAGEJ2COJ_LIBRARIES}
     ${LLINVENTORY_LIBRARIES}
     ${LLMESSAGE_LIBRARIES}
     ${LLPLUGIN_LIBRARIES}
@@ -1698,6 +1694,17 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     )
 
+if (USE_KDU)
+    target_link_libraries(${VIEWER_BINARY_NAME}
+        ${LLKDU_LIBRARIES}
+        ${KDU_LIBRARY}
+        )
+else (USE_KDU)
+    target_link_libraries(${VIEWER_BINARY_NAME}
+        ${LLIMAGEJ2COJ_LIBRARIES}
+        )
+endif (USE_KDU)
+    
 build_version(viewer)
 
 set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
@@ -1845,29 +1852,31 @@ if (PACKAGE)
     set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
   endif (LINUX)
 
-  if(CMAKE_CFG_INTDIR STREQUAL ".")
+  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 ".")
+    else(CMAKE_CFG_INTDIR STREQUAL ".")
       # set LLBUILD_CONFIG to be a shell variable evaluated at build time
       # reflecting the configuration we are currently building.
       set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR})
-  endif(CMAKE_CFG_INTDIR STREQUAL ".")
-  add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
-    COMMAND "${PYTHON_EXECUTABLE}"
-    ARGS
-      "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
-      "${LLBUILD_CONFIG}"
-      "${VIEWER_DIST_DIR}"
-      "${VIEWER_EXE_GLOBS}"
-      "${VIEWER_LIB_GLOB}"
-      "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms"
-      "${VIEWER_SYMBOL_FILE}"
-    DEPENDS generate_breakpad_symbols.py
-    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(CMAKE_CFG_INTDIR STREQUAL ".")
+    add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
+      COMMAND "${PYTHON_EXECUTABLE}"
+      ARGS
+        "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
+        "${LLBUILD_CONFIG}"
+        "${VIEWER_DIST_DIR}"
+        "${VIEWER_EXE_GLOBS}"
+        "${VIEWER_LIB_GLOB}"
+        "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms"
+        "${VIEWER_SYMBOL_FILE}"
+        DEPENDS generate_breakpad_symbols.py
+        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)
diff --git a/indra/newview/app_settings/lindenlab.pem b/indra/newview/app_settings/lindenlab.pem
new file mode 100644
index 0000000000000000000000000000000000000000..cf88d0e04799bf09835f2c78959e9e8bce3d75f9
--- /dev/null
+++ b/indra/newview/app_settings/lindenlab.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEUDCCA7mgAwIBAgIJAN4ppNGwj6yIMA0GCSqGSIb3DQEBBAUAMIHMMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
+aXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5jLjEpMCcGA1UECxMgTGluZGVu
+IExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIExpbmRlbiBMYWIg
+Q2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZIhvcNAQkBFhBjYUBsaW5kZW5s
+YWIuY29tMB4XDTA1MDQyMTAyNDAzMVoXDTI1MDQxNjAyNDAzMVowgcwxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp
+c2NvMRkwFwYDVQQKExBMaW5kZW4gTGFiLCBJbmMuMSkwJwYDVQQLEyBMaW5kZW4g
+TGFiIENlcnRpZmljYXRlIEF1dGhvcml0eTEpMCcGA1UEAxMgTGluZGVuIExhYiBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgkqhkiG9w0BCQEWEGNhQGxpbmRlbmxh
+Yi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKXh1MThucdTbMg9bYBO
+rAm8yWns32YojB0PRfbq8rUjepEhTm3/13s0u399Uc202v4ejcGhkIDWJZd2NZMF
+oKrhmRfxGHSKPCuFaXC3jh0lRECj7k8FoPkcmaPjSyodrDFDUUuv+C06oYJoI+rk
+8REyal9NwgHvqCzOrZtiTXAdAgMBAAGjggE2MIIBMjAdBgNVHQ4EFgQUO1zK2e1f
+1wO1fHAjq6DTJobKDrcwggEBBgNVHSMEgfkwgfaAFDtcytntX9cDtXxwI6ug0yaG
+yg63oYHSpIHPMIHMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW
+MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5j
+LjEpMCcGA1UECxMgTGluZGVuIExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAn
+BgNVBAMTIExpbmRlbiBMYWIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZI
+hvcNAQkBFhBjYUBsaW5kZW5sYWIuY29tggkA3imk0bCPrIgwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQQFAAOBgQA/ZkgfvwHYqk1UIAKZS3kMCxz0HvYuEQtviwnu
+xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9
+e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu
+glmQ1A==
+-----END CERTIFICATE-----
+
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 06992d2b52b26f5b6a14145ba3d38f63dc4d2381..b3324ea6c628c39b89e61b15f5517d96e30e6d65 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -686,6 +686,39 @@
       <key>Value</key>
       <string>http://www.secondlife.com</string>
     </map>
+    <key>BrowserIgnoreSSLCertErrors</key>
+    <map>
+      <key>Comment</key>
+      <string>FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>BrowserUseDefaultCAFile</key>
+    <map>
+      <key>Comment</key>
+      <string>Tell the built-in web browser to use the CA.pem file shipped with the client.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>BrowserCAFilePath</key>
+    <map>
+      <key>Comment</key>
+      <string>Tell the built-in web browser the path to an alternative CA.pem file (only used if BrowserUseDefaultCAFile is false).</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string></string>
+    </map>  
     <key>BlockAvatarAppearanceMessages</key>
         <map>
         <key>Comment</key>
@@ -6572,7 +6605,18 @@
     <key>MediaBrowserWindowLimit</key>
     <map>
       <key>Comment</key>
-      <string>Maximum number of media brower windows that can be open at once (0 for no limit)</string>
+      <string>Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>5</integer>
+    </map>
+    <key>WebContentWindowLimit</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -9980,6 +10024,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>
@@ -11080,16 +11135,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>
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/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index d6a813d60806ddefbbed85abc3a20d0eddb506a0..6e77d1e3363dd6ecede27859efe9f45b75eb2a44 100644
--- a/indra/newview/llbrowsernotification.cpp
+++ b/indra/newview/llbrowsernotification.cpp
@@ -29,8 +29,9 @@
 
 #include "llnotificationhandler.h"
 #include "llnotifications.h"
-#include "llfloaterreg.h"
 #include "llmediactrl.h"
+#include "llviewermedia.h"
+#include "llviewermediafocus.h"
 
 using namespace LLNotificationsUI;
 
@@ -39,10 +40,19 @@ bool LLBrowserNotification::processNotification(const LLSD& notify)
 	LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
 	if (!notification) return false;
 
-	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(notification->getPayload()["media_id"].asUUID());
+	LLUUID media_id = notification->getPayload()["media_id"].asUUID();
+	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(media_id);
 	if (media_instance)
 	{
 		media_instance->showNotification(notification);
 	}
+	else if (LLViewerMediaFocus::instance().getControlsMediaID() == media_id)
+	{
+		LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(media_id);
+		if (impl)
+		{
+			impl->showNotification(notification);
+		}
+	}
 	return false;
 }
diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp
index d35c9ed8535f658fd761abc0f8942f86a8e7aaad..e5a9be020311da047208e1646899560ae9b92915 100644
--- a/indra/newview/llbuycurrencyhtml.cpp
+++ b/indra/newview/llbuycurrencyhtml.cpp
@@ -33,6 +33,7 @@
 #include "llfloaterreg.h"
 #include "llcommandhandler.h"
 #include "llviewercontrol.h"
+#include "llstatusbar.h"
 
 // support for secondlife:///app/buycurrencyhtml/{ACTION}/{NEXT_ACTION}/{RETURN_CODE} SLapps
 class LLBuyCurrencyHTMLHandler : 
@@ -156,4 +157,7 @@ void LLBuyCurrencyHTML::closeDialog()
 	{
 		buy_currency_floater->closeFloater();
 	};
+	
+	// Update L$ balance in the status bar in case L$ were purchased
+	LLStatusBar::sendMoneyBalanceRequest();
 }
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 6e778de2d86df797872d62016b96136d7ff64768..c98bcbda45325b6abb9b1da5a565e8aaaac191a8 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -586,7 +586,7 @@ void LLChatHistory::initFromParams(const LLChatHistory::Params& p)
 	LLLayoutStack::Params layout_p;
 	layout_p.rect = stack_rect;
 	layout_p.follows.flags = FOLLOWS_ALL;
-	layout_p.orientation = "vertical";
+	layout_p.orientation = LLLayoutStack::VERTICAL;
 	layout_p.mouse_opaque = false;
 	
 	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p, this);
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 8ae3ccbae3146d824c83a63b492c06b46ebf1060..2873bc00599e6fcd5c26e82be55841db738a42e4 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -272,7 +272,7 @@ LLSD LLFloaterAbout::getInfo()
 	}
 	
 	// TODO: Implement media plugin version query
-	info["QT_WEBKIT_VERSION"] = "4.6 (version number hard-coded)";
+	info["QT_WEBKIT_VERSION"] = "4.7.1 (version number hard-coded)";
 
 	if (gPacketsIn > 0)
 	{
diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp
index 58c79fdf151b10350cb293c69815168f17832c97..e21a8594bc0e4f37c3087a65dab274c874807f2b 100644
--- a/indra/newview/llfloaterbuycurrency.cpp
+++ b/indra/newview/llfloaterbuycurrency.cpp
@@ -267,17 +267,23 @@ void LLFloaterBuyCurrencyUI::onClickBuy()
 {
 	mManager.buy(getString("buy_currency"));
 	updateUI();
+	// Update L$ balance
+	LLStatusBar::sendMoneyBalanceRequest();
 }
 
 void LLFloaterBuyCurrencyUI::onClickCancel()
 {
 	closeFloater();
+	// Update L$ balance
+	LLStatusBar::sendMoneyBalanceRequest();
 }
 
 void LLFloaterBuyCurrencyUI::onClickErrorWeb()
 {
 	LLWeb::loadURLExternal(mManager.errorURI());
 	closeFloater();
+	// Update L$ balance
+	LLStatusBar::sendMoneyBalanceRequest();
 }
 
 // static
diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp
index bde620d965bffe6fde637e4994daaac1f44a616a..013cf74c7bab3ee8260090ba21d204943a0134df 100644
--- a/indra/newview/llfloaterbuycurrencyhtml.cpp
+++ b/indra/newview/llfloaterbuycurrencyhtml.cpp
@@ -82,7 +82,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL()
 	LLStringUtil::format( buy_currency_url, replace );
 
 	// write final URL to debug console
-	llinfos << "Buy currency HTML prased URL is " << buy_currency_url << llendl;
+	llinfos << "Buy currency HTML parsed URL is " << buy_currency_url << llendl;
 
 	// kick off the navigation
 	mBrowser->navigateTo( buy_currency_url, "text/html" );
@@ -105,7 +105,7 @@ void LLFloaterBuyCurrencyHTML::handleMediaEvent( LLPluginClassMedia* self, EMedi
 //
 void LLFloaterBuyCurrencyHTML::onClose( bool app_quitting )
 {
-	// update L$ balanace one more time
+	// Update L$ balance one more time
 	LLStatusBar::sendMoneyBalanceRequest();
 
 	destroy();
diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp
index cec98e999235d04c9962a693a3cfc44ea8f504e7..a650886d89f60d08b31bdb2487349f0206ee38ad 100644
--- a/indra/newview/llfloaterhelpbrowser.cpp
+++ b/indra/newview/llfloaterhelpbrowser.cpp
@@ -132,9 +132,10 @@ void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data)
 
 void LLFloaterHelpBrowser::openMedia(const std::string& media_url)
 {
-	mBrowser->setHomePageUrl(media_url);
-	//mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:<br><b>" + media_url + "</b>"); // tofu HACK for debugging =:)
-	mBrowser->navigateTo(media_url);
+	// explicitly make the media mime type for this floater since it will
+	// only ever display one type of content (Web).
+	mBrowser->setHomePageUrl(media_url, "text/html");
+	mBrowser->navigateTo(media_url, "text/html");
 	setCurrentURL(media_url);
 }
 
diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp
index d20092e344f2de809092226080ca4b738a1bd09b..7a670dd90cca7b108027d6911e5ced8d2086b502 100644
--- a/indra/newview/llfloatermediabrowser.cpp
+++ b/indra/newview/llfloatermediabrowser.cpp
@@ -306,17 +306,14 @@ void LLFloaterMediaBrowser::setCurrentURL(const std::string& url)
 {
 	mCurrentURL = url;
 
-	// redirects will navigate momentarily to about:blank, don't add to history
-	if (mCurrentURL != "about:blank")
-	{
-		mAddressCombo->remove(mCurrentURL);
-		mAddressCombo->add(mCurrentURL);
-		mAddressCombo->selectByValue(mCurrentURL);
+	mAddressCombo->remove(mCurrentURL);
+	mAddressCombo->add(mCurrentURL);
+	mAddressCombo->selectByValue(mCurrentURL);
+
+	// Serialize url history
+	LLURLHistory::removeURL("browser", mCurrentURL);
+	LLURLHistory::addURL("browser", mCurrentURL);
 
-		// Serialize url history
-		LLURLHistory::removeURL("browser", mCurrentURL);
-		LLURLHistory::addURL("browser", mCurrentURL);
-	}
 	getChildView("back")->setEnabled(mBrowser->canNavigateBack());
 	getChildView("forward")->setEnabled(mBrowser->canNavigateForward());
 	getChildView("reload")->setEnabled(TRUE);
@@ -334,8 +331,15 @@ void LLFloaterMediaBrowser::onClickRefresh(void* user_data)
 {
 	LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
 
-	self->mAddressCombo->remove(0);
-	self->mBrowser->navigateTo(self->mCurrentURL);
+	if( self->mBrowser->getMediaPlugin() &&  self->mBrowser->getMediaPlugin()->pluginSupportsMediaBrowser())
+	{
+		bool ignore_cache = true;
+		self->mBrowser->getMediaPlugin()->browse_reload( ignore_cache );
+	}
+	else
+	{
+		self->mBrowser->navigateTo(self->mCurrentURL);
+	}
 }
 
 //static 
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index 3ed4aec89ab10cfc5e1d9f1bdf6f1c279e6c31cd..2041fac8d8d165cbfd878e5201c2443cceeb50ab 100644
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -200,5 +200,5 @@ void LLFloaterSearch::search(const LLSD &key)
 	url = LLWeb::expandURLSubstitutions(url, subs);
 
 	// and load the URL in the web view
-	mBrowser->navigateTo(url);
+	mBrowser->navigateTo(url, "text/html");
 }
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51726112a0fccb2c2081a701a8ddf16e9d2016bd
--- /dev/null
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -0,0 +1,402 @@
+/**
+ * @file llfloaterwebcontent.cpp
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $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 "llviewerprecompiledheaders.h"
+
+#include "llcombobox.h"
+#include "lliconctrl.h"
+#include "llfloaterreg.h"
+#include "lllayoutstack.h"
+#include "llpluginclassmedia.h"
+#include "llprogressbar.h"
+#include "lltextbox.h"
+#include "llurlhistory.h"
+#include "llviewercontrol.h"
+#include "llweb.h"
+#include "llwindow.h"
+
+#include "llfloaterwebcontent.h"
+
+LLFloaterWebContent::LLFloaterWebContent( const LLSD& key )
+	: LLFloater( key )
+{
+	mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
+	mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
+	mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
+	mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
+	mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
+	mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
+}
+
+BOOL LLFloaterWebContent::postBuild()
+{
+	// these are used in a bunch of places so cache them
+	mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
+	mAddressCombo = getChild< LLComboBox >( "address" );
+	mStatusBarText = getChild< LLTextBox >( "statusbartext" );
+	mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
+
+	// observe browser events
+	mWebBrowser->addObserver( this );
+
+	// these buttons are always enabled
+	getChildView("reload")->setEnabled( true );
+	getChildView("popexternal")->setEnabled( true );
+
+	// cache image for secure browsing
+	mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
+
+	// initialize the URL history using the system URL History manager
+	initializeURLHistory();
+
+	return TRUE;
+}
+
+void LLFloaterWebContent::initializeURLHistory()
+{
+	// start with an empty list
+	LLCtrlListInterface* url_list = childGetListInterface("address");
+	if (url_list)
+	{
+		url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
+	}
+
+	// Get all of the entries in the "browser" collection
+	LLSD browser_history = LLURLHistory::getURLHistory("browser");
+	LLSD::array_iterator iter_history =
+		browser_history.beginArray();
+	LLSD::array_iterator end_history =
+		browser_history.endArray();
+	for(; iter_history != end_history; ++iter_history)
+	{
+		std::string url = (*iter_history).asString();
+		if(! url.empty())
+			url_list->addSimpleElement(url);
+	}
+}
+
+//static
+void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid )
+{
+	lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
+
+	std::string tag = target;
+
+	if(target.empty() || target == "_blank")
+	{
+		if(!uuid.empty())
+		{
+			tag = uuid;
+		}
+		else
+		{
+			// create a unique tag for this instance
+			LLUUID id;
+			id.generate();
+			tag = id.asString();
+		}
+	}
+
+	S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
+
+	if(LLFloaterReg::findInstance("web_content", tag) != NULL)
+	{
+		// There's already a web browser for this tag, so we won't be opening a new window.
+	}
+	else if(browser_window_limit != 0)
+	{
+		// showInstance will open a new window.  Figure out how many web browsers are already open,
+		// and close the least recently opened one if this will put us over the limit.
+
+		LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
+		lldebugs << "total instance count is " << instances.size() << llendl;
+
+		for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
+		{
+			lldebugs << "    " << (*iter)->getKey() << llendl;
+		}
+
+		if(instances.size() >= (size_t)browser_window_limit)
+		{
+			// Destroy the least recently opened instance
+			(*instances.begin())->closeFloater();
+		}
+	}
+
+	LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
+	llassert(browser);
+	if(browser)
+	{
+		browser->mUUID = uuid;
+
+		// tell the browser instance to load the specified URL
+		browser->open_media(url, target);
+		LLViewerMedia::proxyWindowOpened(target, uuid);
+	}
+}
+
+//static
+void LLFloaterWebContent::closeRequest(const std::string &uuid)
+{
+	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+	{
+		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+		lldebugs << "    " << i->mUUID << llendl;
+		if (i && i->mUUID == uuid)
+		{
+			i->closeFloater(false);
+			return;
+ 		}
+ 	}
+}
+
+//static
+void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
+{
+	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+	{
+		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+		lldebugs << "    " << i->mUUID << llendl;
+		if (i && i->mUUID == uuid)
+		{
+			i->geometryChanged(x, y, width, height);
+			return;
+		}
+	}
+}
+
+void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
+{
+	// Make sure the layout of the browser control is updated, so this calculation is correct.
+	LLLayoutStack::updateClass();
+
+	// TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
+	LLCoordWindow window_size;
+	getWindow()->getSize(&window_size);
+
+	// Adjust width and height for the size of the chrome on the web Browser window.
+	width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
+	height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
+
+	LLRect geom;
+	geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
+
+	lldebugs << "geometry change: " << geom << llendl;
+
+	handleReshape(geom,false);
+}
+
+void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target)
+{
+	// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
+	mWebBrowser->setHomePageUrl(web_url, "text/html");
+	mWebBrowser->setTarget(target);
+	mWebBrowser->navigateTo(web_url, "text/html");
+	set_current_url(web_url);
+}
+
+//virtual
+void LLFloaterWebContent::onClose(bool app_quitting)
+{
+	LLViewerMedia::proxyWindowClosed(mUUID);
+	destroy();
+}
+
+// virtual
+void LLFloaterWebContent::draw()
+{
+	// this is asychronous so we need to keep checking
+	getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() );
+	getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() );
+
+	LLFloater::draw();
+}
+
+// virtual
+void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+	if(event == MEDIA_EVENT_LOCATION_CHANGED)
+	{
+		const std::string url = self->getLocation();
+
+		if ( url.length() )
+			mStatusBarText->setText( url );
+
+		set_current_url( url );
+	}
+	else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
+	{
+		// flags are sent with this event
+		getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+		getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+		// toggle visibility of these buttons based on browser state
+		getChildView("reload")->setVisible( false );
+		getChildView("stop")->setVisible( true );
+
+		// turn "on" progress bar now we're about to start loading
+		mStatusBarProgress->setVisible( true );
+	}
+	else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
+	{
+		// flags are sent with this event
+		getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+		getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+		// toggle visibility of these buttons based on browser state
+		getChildView("reload")->setVisible( true );
+		getChildView("stop")->setVisible( false );
+
+		// turn "off" progress bar now we're loaded
+		mStatusBarProgress->setVisible( false );
+
+		// we populate the status bar with URLs as they change so clear it now we're done
+		const std::string end_str = "";
+		mStatusBarText->setText( end_str );
+
+		// decide if secure browsing icon should be displayed
+		std::string prefix =  std::string("https://");
+		std::string test_prefix = mCurrentURL.substr(0, prefix.length());
+		LLStringUtil::toLower(test_prefix);
+		if(test_prefix == prefix)
+		{
+			mSecureLockIcon->setVisible(true);
+		}
+		else
+		{
+			mSecureLockIcon->setVisible(false);
+		}
+	}
+	else if(event == MEDIA_EVENT_CLOSE_REQUEST)
+	{
+		// The browser instance wants its window closed.
+		closeFloater();
+	}
+	else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
+	{
+		geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
+	}
+	else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
+	{
+		const std::string text = self->getStatusText();
+		if ( text.length() )
+			mStatusBarText->setText( text );
+	}
+	else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
+	{
+		int percent = (int)self->getProgressPercent();
+		mStatusBarProgress->setValue( percent );
+	}
+	else if(event == MEDIA_EVENT_NAME_CHANGED )
+	{
+		std::string page_title = self->getMediaName();
+		// simulate browser behavior - title is empty, use the current URL
+		if ( page_title.length() > 0 )
+			setTitle( page_title );
+		else
+			setTitle( mCurrentURL );
+	}
+	else if(event == MEDIA_EVENT_LINK_HOVERED )
+	{
+		const std::string link = self->getHoverLink();
+		mStatusBarText->setText( link );
+	}
+}
+
+void LLFloaterWebContent::set_current_url(const std::string& url)
+{
+	mCurrentURL = url;
+
+	// serialize url history into the system URL History manager
+	LLURLHistory::removeURL("browser", mCurrentURL);
+	LLURLHistory::addURL("browser", mCurrentURL);
+
+	mAddressCombo->remove( mCurrentURL );
+	mAddressCombo->add( mCurrentURL );
+	mAddressCombo->selectByValue( mCurrentURL );
+}
+
+void LLFloaterWebContent::onClickForward()
+{
+	mWebBrowser->navigateForward();
+}
+
+void LLFloaterWebContent::onClickBack()
+{
+	mWebBrowser->navigateBack();
+}
+
+void LLFloaterWebContent::onClickReload()
+{
+
+	if( mWebBrowser->getMediaPlugin() )
+	{
+		bool ignore_cache = true;
+		mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
+	}
+	else
+	{
+		mWebBrowser->navigateTo(mCurrentURL);
+	}
+}
+
+void LLFloaterWebContent::onClickStop()
+{
+	if( mWebBrowser->getMediaPlugin() )
+		mWebBrowser->getMediaPlugin()->browse_stop();
+
+	// still should happen when we catch the navigate complete event
+	// but sometimes (don't know why) that event isn't sent from Qt
+	// and we getto a point where the stop button stays active.
+	getChildView("reload")->setVisible( true );
+	getChildView("stop")->setVisible( false );
+}
+
+void LLFloaterWebContent::onEnterAddress()
+{
+	// make sure there is at least something there.
+	// (perhaps this test should be for minimum length of a URL)
+	std::string url = mAddressCombo->getValue().asString();
+	if ( url.length() > 0 )
+	{
+		mWebBrowser->navigateTo( url, "text/html");
+	};
+}
+
+void LLFloaterWebContent::onPopExternal()
+{
+	// make sure there is at least something there.
+	// (perhaps this test should be for minimum length of a URL)
+	std::string url = mAddressCombo->getValue().asString();
+	if ( url.length() > 0 )
+	{
+		LLWeb::loadURLExternal( url );
+	};
+}
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h
new file mode 100644
index 0000000000000000000000000000000000000000..001d822ada48b918eb4b5e0b8243377984224c44
--- /dev/null
+++ b/indra/newview/llfloaterwebcontent.h
@@ -0,0 +1,82 @@
+/**
+ * @file llfloaterwebcontent.h
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $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$
+ */
+
+#ifndef LL_LLFLOATERWEBCONTENT_H
+#define LL_LLFLOATERWEBCONTENT_H
+
+#include "llfloater.h"
+#include "llmediactrl.h"
+
+class LLMediaCtrl;
+class LLComboBox;
+class LLTextBox;
+class LLProgressBar;
+class LLIconCtrl;
+
+class LLFloaterWebContent :
+	public LLFloater,
+	public LLViewerMediaObserver
+{
+public:
+    LOG_CLASS(LLFloaterWebContent);
+	LLFloaterWebContent(const LLSD& key);
+
+	void initializeURLHistory();
+
+	static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
+
+	static void closeRequest(const std::string &uuid);
+	static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
+	void geometryChanged(S32 x, S32 y, S32 width, S32 height);
+
+	/* virtual */ BOOL postBuild();
+	/* virtual */ void onClose(bool app_quitting);
+	/* virtual */ void draw();
+
+	// inherited from LLViewerMediaObserver
+	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
+
+	void onClickBack();
+	void onClickForward();
+	void onClickReload();
+	void onClickStop();
+	void onEnterAddress();
+	void onPopExternal();
+
+private:
+	void open_media(const std::string& media_url, const std::string& target);
+	void set_current_url(const std::string& url);
+
+	LLMediaCtrl* mWebBrowser;
+	LLComboBox* mAddressCombo;
+	LLIconCtrl *mSecureLockIcon;
+	LLTextBox* mStatusBarText;
+	LLProgressBar* mStatusBarProgress;
+	std::string mCurrentURL;
+	std::string mUUID;
+};
+
+#endif  // LL_LLFLOATERWEBCONTENT_H
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/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 0f66713ab09673eda55f08aa450debc3756a0eec..9493fddf5044107e0aa502e02ffeea1b967737e8 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -25,7 +25,7 @@
  */
 
 #include "llviewerprecompiledheaders.h"
-
+#include "lltooltip.h"
 
 #include "llmediactrl.h"
 
@@ -54,6 +54,10 @@
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
 #include "llnotifications.h"
+#include "lllineeditor.h"
+#include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
+#include "llwindowshade.h"
 
 extern BOOL gRestoreGL;
 
@@ -98,7 +102,9 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
 	mTextureHeight ( 1024 ),
 	mClearCache(false),
 	mHomePageMimeType(p.initial_mime_type),
-	mTrusted(p.trusted_content)
+	mTrusted(p.trusted_content),
+	mWindowShade(NULL),
+	mHoverTextChanged(false)
 {
 	{
 		LLColor4 color = p.caret_color().get();
@@ -127,7 +133,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
 		setTextureSize(screen_width, screen_height);
 	}
 	
-	mMediaTextureID.generate();
+	mMediaTextureID = getKey();
 	
 	// We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to.
 	if(!mHomePageUrl.empty())
@@ -141,8 +147,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
 //	addChild( mBorder );
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// note: this is now a singleton and destruction happens via initClass() now
 LLMediaCtrl::~LLMediaCtrl()
 {
 
@@ -182,6 +186,13 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )
 		mMediaSource->mouseMove(x, y, mask);
 		gViewerWindow->setCursor(mMediaSource->getLastSetCursor());
 	}
+	
+	// TODO: Is this the right way to handle hover text changes driven by the plugin?
+	if(mHoverTextChanged)
+	{
+		mHoverTextChanged = false;
+		handleToolTip(x, y, mask);
+	}
 
 	return TRUE;
 }
@@ -197,6 +208,35 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks )
 	return TRUE;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+//	virtual 
+BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask)
+{
+	std::string hover_text;
+	
+	if (mMediaSource && mMediaSource->hasMedia())
+		hover_text = mMediaSource->getMediaPlugin()->getHoverText();
+	
+	if(hover_text.empty())
+	{
+		return FALSE;
+	}
+	else
+	{
+		S32 screen_x, screen_y;
+
+		localPointToScreen(x, y, &screen_x, &screen_y);
+		LLRect sticky_rect_screen;
+		sticky_rect_screen.setCenterAndSize(screen_x, screen_y, 20, 20);
+
+		LLToolTipMgr::instance().show(LLToolTip::Params()
+			.message(hover_text)
+			.sticky_rect(sticky_rect_screen));		
+	}
+
+	return TRUE;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )
@@ -338,85 +378,6 @@ void LLMediaCtrl::onFocusLost()
 //
 BOOL LLMediaCtrl::postBuild ()
 {
-	LLLayoutStack::Params layout_p;
-	layout_p.name = "notification_stack";
-	layout_p.rect = LLRect(0,getLocalRect().mTop,getLocalRect().mRight, 30);
-	layout_p.follows.flags = FOLLOWS_ALL;
-	layout_p.mouse_opaque = false;
-	layout_p.orientation = "vertical";
-
-	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
-	addChild(stackp);
-
-	LLLayoutPanel::Params panel_p;
-	panel_p.rect = LLRect(0, 30, 800, 0);
-	panel_p.min_height = 30;
-	panel_p.name = "notification_area";
-	panel_p.visible = false;
-	panel_p.user_resize = false;
-	panel_p.background_visible = true;
-	panel_p.bg_alpha_image.name = "Yellow_Gradient";
-	panel_p.auto_resize = false;
-	LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
-	stackp->addChild(notification_panel);
-
-	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
-	panel_p.auto_resize = true;
-	panel_p.mouse_opaque = false;
-	LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
-	stackp->addChild(dummy_panel);
-
-	layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>();
-	layout_p.rect = LLRect(0, 30, 800, 0);
-	layout_p.follows.flags = FOLLOWS_ALL;
-	layout_p.orientation = "horizontal";
-	stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
-	notification_panel->addChild(stackp);
-
-	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
-	panel_p.rect.height = 30;
-	LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
-	stackp->addChild(panel);
-
-	LLIconCtrl::Params icon_p;
-	icon_p.name = "notification_icon";
-	icon_p.rect = LLRect(5, 23, 21, 8);
-	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
-
-	LLTextBox::Params text_p;
-	text_p.rect = LLRect(31, 20, 430, 0);
-	text_p.text_color = LLColor4::black;
-	text_p.font = LLFontGL::getFontSansSerif();
-	text_p.font.style = "BOLD";
-	text_p.name = "notification_text";
-	text_p.use_ellipses = true;
-	panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
-
-	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
-	panel_p.auto_resize = false;
-	panel_p.user_resize = false;
-	panel_p.name="form_elements";
-	panel_p.rect = LLRect(0, 30, 130, 0);
-	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
-	stackp->addChild(form_elements_panel);
-
-	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
-	panel_p.auto_resize = false;
-	panel_p.user_resize = false;
-	panel_p.rect = LLRect(0, 30, 25, 0);
-	LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
-	stackp->addChild(close_panel);
-
-	LLButton::Params button_p;
-	button_p.name = "close_notification";
-	button_p.rect = LLRect(5, 23, 21, 7);
-	button_p.image_color=LLUIColorTable::instance().getColor("DkGray_66");
-    button_p.image_unselected.name="Icon_Close_Foreground";
-	button_p.image_selected.name="Icon_Close_Press";
-	button_p.click_callback.function = boost::bind(&LLMediaCtrl::onCloseNotification, this);
-
-	close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
-
 	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));
 	return TRUE;
 }
@@ -425,13 +386,15 @@ BOOL LLMediaCtrl::postBuild ()
 //
 BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
 {
-	if (LLPanel::handleKeyHere(key, mask)) return TRUE;
 	BOOL result = FALSE;
 	
 	if (mMediaSource)
 	{
 		result = mMediaSource->handleKeyHere(key, mask);
 	}
+	
+	if ( ! result )
+		result = LLPanel::handleKeyHere(key, mask);
 		
 	return result;
 }
@@ -451,7 +414,6 @@ void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility )
 //
 BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
 {
-	if (LLPanel::handleUnicodeCharHere(uni_char)) return TRUE;
 	BOOL result = FALSE;
 	
 	if (mMediaSource)
@@ -459,6 +421,9 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
 		result = mMediaSource->handleUnicodeCharHere(uni_char);
 	}
 
+	if ( ! result )
+		result = LLPanel::handleUnicodeCharHere(uni_char);
+
 	return result;
 }
 
@@ -914,11 +879,6 @@ void LLMediaCtrl::draw()
 	if ( mBorder && mBorder->getVisible() )
 		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) );
 
-	if (mCurNotification && !mCurNotification->isActive())
-	{
-		hideNotification();
-	}
-	
 	LLPanel::draw();
 
 	// Restore the previous values
@@ -1026,7 +986,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 
 			LLNotification::Params notify_params;
 			notify_params.name = "PopupAttempt";
-			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", getKey());
+			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);
 			notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);
 
 			if (mTrusted)
@@ -1081,6 +1041,31 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;
 		}
 		break;
+
+		case MEDIA_EVENT_AUTH_REQUEST:
+		{
+			LLNotification::Params auth_request_params;
+			auth_request_params.name = "AuthRequest";
+
+			// pass in host name and realm for site (may be zero length but will always exist)
+			LLSD args;
+			LLURL raw_url( self->getAuthURL().c_str() );
+			args["HOST_NAME"] = raw_url.getAuthority();
+			args["REALM"] = self->getAuthRealm();
+			auth_request_params.substitutions = args;
+
+			auth_request_params.payload = LLSD().with("media_id", mMediaTextureID);
+			auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2);
+			LLNotifications::instance().add(auth_request_params);
+		};
+		break;
+
+		case MEDIA_EVENT_LINK_HOVERED:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL;
+			mHoverTextChanged = true;
+		};
+		break;
 	};
 
 	// chain all events to any potential observers of this object.
@@ -1098,109 +1083,85 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response)
 {
 	if (response["open"])
 	{
-		LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]);
+		// name of default floater to open
+		std::string floater_name = "media_browser";
+
+		// look for parent floater name
+		if ( gFloaterView )
+		{
+			if ( gFloaterView->getParentFloater(this) )
+			{
+				floater_name = gFloaterView->getParentFloater(this)->getInstanceName();
+			}
+			else
+			{
+				lldebugs << "No gFloaterView->getParentFloater(this) for onPopuup()" << llendl;
+			};
+		}
+		else
+		{
+			lldebugs << "No gFloaterView for onPopuup()" << llendl;
+		};
+
+		// (for now) open web content floater if that's our parent, otherwise, open the current media floater
+		// (this will change soon)
+		if ( floater_name == "web_content" )
+		{
+			LLWeb::loadWebURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]);
+		}
+		else
+		{
+			LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]);
+		}
 	}
 	else
 	{
 		// Make sure the opening instance knows its window open request was denied, so it can clean things up.
 		LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]);
 	}
-
 }
 
-void LLMediaCtrl::onCloseNotification()
-{
-	LLNotifications::instance().cancel(mCurNotification);
-}
-
-void LLMediaCtrl::onClickIgnore(LLUICtrl* ctrl)
+void LLMediaCtrl::showNotification(LLNotificationPtr notify)
 {
-	bool check = ctrl->getValue().asBoolean();
-	if (mCurNotification && mCurNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
+	delete mWindowShade;
+
+	LLWindowShade::Params params;
+	params.name = "notification_shade";
+	params.rect = getLocalRect();
+	params.follows.flags = FOLLOWS_ALL;
+	params.notification = notify;
+	params.modal = true;
+	//HACK: don't hardcode this
+	if (notify->getIcon() == "Popup_Caution")
 	{
-		// question was "show again" so invert value to get "ignore"
-		check = !check;
+		params.bg_image.name = "Yellow_Gradient";
+		params.text_color = LLColor4::black;
 	}
-	mCurNotification->setIgnored(check);
-}
-
-void LLMediaCtrl::onClickNotificationButton(const std::string& name)
-{
-	if (!mCurNotification) return;
-
-	LLSD response = mCurNotification->getResponseTemplate();
-	response[name] = true;
-
-	mCurNotification->respond(response); 
-}
-
-void LLMediaCtrl::showNotification(LLNotificationPtr notify)
-{
-	mCurNotification = notify;
-
-	// add popup here
-	LLSD payload = notify->getPayload();
-
-	LLNotificationFormPtr formp = notify->getForm();
-	LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area");
-	panel.setVisible(true);
-	panel.getChild<LLUICtrl>("notification_icon")->setValue(notify->getIcon());
-	panel.getChild<LLUICtrl>("notification_text")->setValue(notify->getMessage());
-	panel.getChild<LLUICtrl>("notification_text")->setToolTip(notify->getMessage());
-	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); 
-	LLLayoutPanel& form_elements = panel.getChildRef<LLLayoutPanel>("form_elements");
-	form_elements.deleteAllChildren();
-
-	const S32 FORM_PADDING_HORIZONTAL = 10;
-	const S32 FORM_PADDING_VERTICAL = 3;
-	S32 cur_x = FORM_PADDING_HORIZONTAL;
-
-	if (ignore_type != LLNotificationForm::IGNORE_NO)
+	else
+	//HACK: another one since XUI doesn't support what we need right now
+	if (notify->getName() == "AuthRequest")
 	{
-		LLCheckBoxCtrl::Params checkbox_p;
-		checkbox_p.name = "ignore_check";
-		checkbox_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL);
-		checkbox_p.label = formp->getIgnoreMessage();
-		checkbox_p.label_text.text_color = LLColor4::black;
-		checkbox_p.commit_callback.function = boost::bind(&LLMediaCtrl::onClickIgnore, this, _1);
-		checkbox_p.initial_value = formp->getIgnored();
-
-		LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
-		check->setRect(check->getBoundingRect());
-		form_elements.addChild(check);
-		cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL;
+		params.bg_image.name = "Yellow_Gradient";
+		params.text_color = LLColor4::black;
+		params.can_close = false;
 	}
-
-	for (S32 i = 0; i < formp->getNumElements(); i++)
+	else
 	{
-		LLSD form_element = formp->getElement(i);
-		if (form_element["type"].asString() == "button")
-		{
-			LLButton::Params button_p;
-			button_p.name = form_element["name"];
-			button_p.label = form_element["text"];
-			button_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL);
-			button_p.click_callback.function = boost::bind(&LLMediaCtrl::onClickNotificationButton, this, form_element["name"].asString());
-			button_p.auto_resize = true;
-
-			LLButton* button = LLUICtrlFactory::create<LLButton>(button_p);
-			button->autoResize();
-			form_elements.addChild(button);
-
-			cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
-		}
+		//HACK: make this a property of the notification itself, "cancellable"
+		params.can_close = false;
+		params.text_color.control = "LabelTextColor";
 	}
 
+	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
 
-	form_elements.reshape(cur_x, form_elements.getRect().getHeight());
-
-	//LLWeb::loadURL(payload["url"], payload["target"]);
+	addChild(mWindowShade);
+	mWindowShade->show();
 }
 
 void LLMediaCtrl::hideNotification()
 {
-	LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area");
-	panel.setVisible(FALSE);
-
-	mCurNotification.reset();
+	if (mWindowShade)
+	{
+		mWindowShade->hide();
+	}
 }
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 96bb0c1df5c061aa553f102851ed0d94a0bddaa3..38a74f90d3cf6a2ed5040ced04d1e78bc2ce44d0 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -90,6 +90,7 @@ class LLMediaCtrl :
 		virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
 		virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask );
 		virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
+		virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);
 
 		// navigation
 		void navigateTo( std::string url_in, std::string mime_type = "");
@@ -168,9 +169,6 @@ class LLMediaCtrl :
 	private:
 		void onVisibilityChange ( const LLSD& new_visibility );
 		void onPopup(const LLSD& notification, const LLSD& response);
-		void onCloseNotification();
-		void onClickNotificationButton(const std::string& name);
-		void onClickIgnore(LLUICtrl* ctrl);
 
 		const S32 mTextureDepthBytes;
 		LLUUID mMediaTextureID;
@@ -194,7 +192,8 @@ class LLMediaCtrl :
 		S32 mTextureWidth;
 		S32 mTextureHeight;
 		bool mClearCache;
-		boost::shared_ptr<class LLNotification> mCurNotification;
+		class LLWindowShade* mWindowShade;
+		bool mHoverTextChanged;
 };
 
 #endif // LL_LLMediaCtrl_H
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 2e4be78be18387c2a50d98a45f27420507d70b69..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,16 +200,12 @@ 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
 	//sendChildToBack(getChildView("channel_text"));
 	sendChildToBack(getChildView("forgot_password_text"));
 
-	LLLineEditor* edit = getChild<LLLineEditor>("password_edit");
-	if (edit) edit->setDrawAsterixes(TRUE);
-
 	if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)
 	{
 		LLSLURL slurl(gSavedSettings.getString("LoginLocation"));
@@ -248,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");
@@ -275,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 );
@@ -306,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)
@@ -315,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
 	}
 }
 
@@ -364,7 +337,6 @@ void LLPanelLogin::draw()
 
 		if ( mHtmlAvailable )
 		{
-#if !USE_VIEWER_AUTH
 			if (getChild<LLView>("login_widgets")->getVisible())
 			{
 				// draw a background box in black
@@ -373,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
 		{
@@ -419,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
@@ -453,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);
@@ -833,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/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index 614700fb0a6661bc98d889afd1cf18a6e7a2e533..8ae3553857640f2461a665f6a341c3d340c50cfe 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -59,6 +59,7 @@
 #include "llvovolume.h"
 #include "llweb.h"
 #include "llwindow.h"
+#include "llwindowshade.h"
 #include "llfloatertools.h"  // to enable hide if build tools are up
 
 // Functions pulled from pipeline.cpp
@@ -90,7 +91,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
 	mTargetObjectNormal(LLVector3::zero),
 	mZoomObjectID(LLUUID::null),
 	mZoomObjectFace(0),
-	mVolumeSliderVisible(0)
+	mVolumeSliderVisible(0),
+	mWindowShade(NULL)
 {
 	mCommitCallbackRegistrar.add("MediaCtrl.Close",		boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
 	mCommitCallbackRegistrar.add("MediaCtrl.Back",		boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
@@ -205,6 +207,9 @@ BOOL LLPanelPrimMediaControls::postBuild()
 		
 	mMediaAddress->setFocusReceivedCallback(boost::bind(&LLPanelPrimMediaControls::onInputURL, _1, this ));
 	
+	LLWindowShade::Params window_shade_params;
+	window_shade_params.name = "window_shade";
+
 	mCurrentZoom = ZOOM_NONE;
 	// clicks on buttons do not remove keyboard focus from media
 	setIsChrome(TRUE);
@@ -698,6 +703,24 @@ void LLPanelPrimMediaControls::updateShape()
 /*virtual*/
 void LLPanelPrimMediaControls::draw()
 {
+	LLViewerMediaImpl* impl = getTargetMediaImpl();
+	if (impl)
+	{
+		LLNotificationPtr notification = impl->getCurrentNotification();
+		if (notification != mActiveNotification)
+		{
+			mActiveNotification = notification;
+			if (notification)
+			{
+				showNotification(notification);
+			}
+			else
+			{
+				hideNotification();
+			}
+		}
+	}
+
 	F32 alpha = getDrawContext().mAlpha;
 	if(mFadeTimer.getStarted())
 	{
@@ -1295,3 +1318,38 @@ bool LLPanelPrimMediaControls::shouldVolumeSliderBeVisible()
 {
 	return mVolumeSliderVisible > 0;
 }
+
+void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify)
+{
+	delete mWindowShade;
+	LLWindowShade::Params params;
+	params.rect = mMediaRegion->getLocalRect();
+	params.follows.flags = FOLLOWS_ALL;
+	params.notification = notify;
+
+	//HACK: don't hardcode this
+	if (notify->getIcon() == "Popup_Caution")
+	{
+		params.bg_image.name = "Yellow_Gradient";
+		params.text_color = LLColor4::black;
+	}
+	else
+	{
+		//HACK: make this a property of the notification itself, "cancellable"
+		params.can_close = false;
+		params.text_color.control = "LabelTextColor";
+	}
+
+	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
+
+	mMediaRegion->addChild(mWindowShade);
+	mWindowShade->show();
+}
+
+void LLPanelPrimMediaControls::hideNotification()
+{
+	if (mWindowShade)
+	{
+		mWindowShade->hide();
+	}
+}
diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h
index 3ec24f0e24a8a2d04420f1f75ff812b1693c1d87..0b9664359c6ff7728d2542f1de1901fb1587f1c6 100644
--- a/indra/newview/llpanelprimmediacontrols.h
+++ b/indra/newview/llpanelprimmediacontrols.h
@@ -29,6 +29,7 @@
 
 #include "llpanel.h"
 #include "llviewermedia.h"
+#include "llnotificationptr.h"
 
 class LLButton;
 class LLCoordWindow;
@@ -37,6 +38,7 @@ class LLLayoutStack;
 class LLProgressBar;
 class LLSliderCtrl;
 class LLViewerMediaImpl;
+class LLWindowShade;
 
 class LLPanelPrimMediaControls : public LLPanel
 {
@@ -54,6 +56,9 @@ class LLPanelPrimMediaControls : public LLPanel
 	void updateShape();
 	bool isMouseOver();
 	
+	void showNotification(LLNotificationPtr notify);
+	void hideNotification();
+
 	enum EZoomLevel
 	{
 		ZOOM_NONE = 0,
@@ -162,6 +167,7 @@ class LLPanelPrimMediaControls : public LLPanel
 	LLUICtrl *mRightBookend;
 	LLUIImage* mBackgroundImage;
 	LLUIImage* mVolumeSliderBackgroundImage;
+	LLWindowShade* mWindowShade;
 	F32 mSkipStep;
 	S32 mMinWidth;
 	S32 mMinHeight;
@@ -204,6 +210,8 @@ class LLPanelPrimMediaControls : public LLPanel
 	S32 mZoomObjectFace;
 	
 	S32 mVolumeSliderVisible;
+
+	LLNotificationPtr mActiveNotification;
 };
 
 #endif // LL_PANELPRIMMEDIACONTROLS_H
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/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index e9fc25404a56cce34049a97b6a918d95fbec8442..1b8be7a5b23805be39b9b9e530ecbadf52055fe1 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -115,6 +115,7 @@ LLStatusBar::LLStatusBar(const LLRect& rect)
 	mSGBandwidth(NULL),
 	mSGPacketLoss(NULL),
 	mBtnVolume(NULL),
+	mBoxBalance(NULL),
 	mBalance(0),
 	mHealth(100),
 	mSquareMetersCredit(0),
@@ -168,6 +169,9 @@ BOOL LLStatusBar::postBuild()
 	getChild<LLUICtrl>("buyL")->setCommitCallback(
 		boost::bind(&LLStatusBar::onClickBuyCurrency, this));
 
+	mBoxBalance = getChild<LLTextBox>("balance");
+	mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this );
+
 	mBtnVolume = getChild<LLButton>( "volume_btn" );
 	mBtnVolume->setClickedCallback( onClickVolume, this );
 	mBtnVolume->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterVolume, this));
@@ -304,6 +308,7 @@ void LLStatusBar::setVisibleForMouselook(bool visible)
 {
 	mTextTime->setVisible(visible);
 	getChild<LLUICtrl>("balance_bg")->setVisible(visible);
+	mBoxBalance->setVisible(visible);
 	mBtnVolume->setVisible(visible);
 	mMediaToggle->setVisible(visible);
 	mSGBandwidth->setVisible(visible);
@@ -330,16 +335,15 @@ void LLStatusBar::setBalance(S32 balance)
 
 	std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance );
 
-	LLTextBox* balance_box = getChild<LLTextBox>("balance");
 	LLStringUtil::format_map_t string_args;
 	string_args["[AMT]"] = llformat("%s", money_str.c_str());
 	std::string label_str = getString("buycurrencylabel", string_args);
-	balance_box->setValue(label_str);
+	mBoxBalance->setValue(label_str);
 
 	// Resize the L$ balance background to be wide enough for your balance plus the buy button
 	{
 		const S32 HPAD = 24;
-		LLRect balance_rect = balance_box->getTextBoundingRect();
+		LLRect balance_rect = mBoxBalance->getTextBoundingRect();
 		LLRect buy_rect = getChildView("buyL")->getRect();
 		LLView* balance_bg_view = getChildView("balance_bg");
 		LLRect balance_bg_rect = balance_bg_view->getRect();
@@ -505,6 +509,14 @@ static void onClickVolume(void* data)
 	LLAppViewer::instance()->setMasterSystemAudioMute(!mute_audio);	
 }
 
+//static 
+void LLStatusBar::onClickBalance(void* )
+{
+	// Force a balance request message:
+	LLStatusBar::sendMoneyBalanceRequest();
+	// The refresh of the display (call to setBalance()) will be done by process_money_balance_reply()
+}
+
 //static 
 void LLStatusBar::onClickMediaToggle(void* data)
 {
diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h
index 2388aeb0c85e74c9f0b2fb25947a5a8e195e150c..4ea3183d1820a4c606bbadb45e78ff64923bdd66 100644
--- a/indra/newview/llstatusbar.h
+++ b/indra/newview/llstatusbar.h
@@ -94,6 +94,7 @@ class LLStatusBar
 	void onClickScreen(S32 x, S32 y);
 
 	static void onClickMediaToggle(void* data);
+	static void onClickBalance(void* data);
 
 private:
 	LLTextBox	*mTextTime;
@@ -102,6 +103,7 @@ class LLStatusBar
 	LLStatGraph *mSGPacketLoss;
 
 	LLButton	*mBtnVolume;
+	LLTextBox	*mBoxBalance;
 	LLButton	*mMediaToggle;
 	LLView*		mScriptOut;
 	LLFrameTimer	mClockUpdateTimer;
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/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index f573f25efe79727216cac4a46522f2a831cd3a27..dca1e33e609fac9f0539631c0c74511fee972b71 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -60,6 +60,7 @@
 #include "llfloaterhardwaresettings.h"
 #include "llfloaterhelpbrowser.h"
 #include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
 #include "llfloatermediasettings.h"
 #include "llfloaterhud.h"
 #include "llfloaterimagepreview.h"
@@ -252,6 +253,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);
 	LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>);
 
+	LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWebContent>);	
 	LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);	
 	LLFloaterWindowSizeUtil::registerFloater();
 	LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>);	
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index fae4eb3c056029e2ea5085f299dbb7e8a14a9e1e..d3b6dcd86f2f937121d61890f9c997ae0869fd08 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -52,6 +52,7 @@
 #include "llviewerregion.h"
 #include "llwebsharing.h"	// For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this!
 #include "llfilepicker.h"
+#include "llnotifications.h"
 
 #include "llevent.h"		// LLSimpleListener
 #include "llnotificationsutil.h"
@@ -62,6 +63,7 @@
 #include "llwindow.h"
 
 #include "llfloatermediabrowser.h"	// for handling window close requests and geometry change requests in media browser windows.
+#include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.
 
 #include <boost/bind.hpp>	// for SkinFolder listener
 #include <boost/signals2.hpp>
@@ -293,6 +295,7 @@ LOG_CLASS(LLViewerMediaOpenIDResponder);
 LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;
 LLURL LLViewerMedia::sOpenIDURL;
 std::string LLViewerMedia::sOpenIDCookie;
+LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL;
 static LLViewerMedia::impl_list sViewerMediaImplList;
 static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap;
 static LLTimer sMediaCreateTimer;
@@ -742,6 +745,9 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// Enable/disable the plugin read thread
 	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
 	
+	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
+	createSpareBrowserMediaSource();
+	
 	sAnyMediaShowing = false;
 	sUpdatedCookies = getCookieStore()->getChangedCookies();
 	if(!sUpdatedCookies.empty())
@@ -759,6 +765,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 		pimpl->update();
 		pimpl->calculateInterest();
 	}
+	
+	// Let the spare media source actually launch
+	if(sSpareBrowserMediaSource)
+	{
+		sSpareBrowserMediaSource->idle();
+	}
 		
 	// Sort the static instance list using our interest criteria
 	sViewerMediaImplList.sort(priorityComparitor);
@@ -1034,6 +1046,26 @@ bool LLViewerMedia::isParcelAudioPlaying()
 	return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());
 }
 
+void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response)
+{
+	LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]);
+	if(impl)
+	{
+		LLPluginClassMedia* media = impl->getMediaPlugin();
+		if(media)
+		{
+			if (response["ok"])
+			{
+				media->sendAuthResponse(true, response["username"], response["password"]);
+			}
+			else
+			{
+				media->sendAuthResponse(false, "", "");
+			}
+		}
+	}
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////
 // static
 void LLViewerMedia::clearAllCookies()
@@ -1400,6 +1432,29 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid)
 	}
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::createSpareBrowserMediaSource()
+{
+	if(!sSpareBrowserMediaSource)
+	{
+		// If we don't have a spare browser media source, create one.
+		// The null owner will keep the browser plugin from fully initializing 
+		// (specifically, it keeps LLPluginClassMedia from negotiating a size change, 
+		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
+		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() 
+{
+	LLPluginClassMedia* result = sSpareBrowserMediaSource;
+	sSpareBrowserMediaSource = NULL;
+	return result; 
+};
+
 bool LLViewerMedia::hasInWorldMedia()
 {
 	if (sInWorldMediaDisabled) return false;
@@ -1636,6 +1691,21 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
 LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target)
 {
 	std::string plugin_basename = LLMIMETypes::implType(media_type);
+	LLPluginClassMedia* media_source = NULL;
+	
+	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
+	if(plugin_basename == "media_plugin_webkit")
+	{
+		media_source = LLViewerMedia::getSpareBrowserMediaSource();
+		if(media_source)
+		{
+			media_source->setOwner(owner);
+			media_source->setTarget(target);
+			media_source->setSize(default_width, default_height);
+						
+			return media_source;
+		}
+	}
 	
 	if(plugin_basename.empty())
 	{
@@ -1673,7 +1743,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 		}
 		else
 		{
-			LLPluginClassMedia* media_source = new LLPluginClassMedia(owner);
+			media_source = new LLPluginClassMedia(owner);
 			media_source->setSize(default_width, default_height);
 			media_source->setUserDataPath(user_data_path);
 			media_source->setLanguageCode(LLUI::getLanguage());
@@ -1753,6 +1823,22 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 		media_source->focus(mHasFocus);
 		media_source->setBackgroundColor(mBackgroundColor);
 		
+		if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors"))
+		{
+			media_source->ignore_ssl_cert_errors(true);
+		}
+
+		// start by assuming the default CA file will be used
+		std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" );
+	
+		// default turned off so pick up the user specified path
+		if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile"))
+		{
+			ca_path = gSavedSettings.getString("BrowserCAFilePath");
+		}
+		// set the path to the CA.pem file
+		media_source->addCertificateFilePath( ca_path );
+
 		media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
 		
 		if(mClearCache)
@@ -1848,6 +1934,18 @@ void LLViewerMediaImpl::setSize(int width, int height)
 	}
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::showNotification(LLNotificationPtr notify)
+{
+	mNotification = notify;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::hideNotification()
+{
+	mNotification.reset();
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::play()
 {
@@ -2850,7 +2948,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 			LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; 
 			std::string url = plugin->getClickURL();
 			LLURLDispatcher::dispatch(url, NULL, mTrustedBrowser);
-
 		}
 		break;
 		case MEDIA_EVENT_CLICK_LINK_HREF:
@@ -2913,6 +3010,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN:
 		{
 			LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL;
+			hideNotification();
 
 			if(getNavState() == MEDIANAVSTATE_SERVER_SENT)
 			{
@@ -3003,7 +3101,26 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 			plugin->sendPickFileResponse(response);
 		}
 		break;
-		
+
+
+		case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST:
+		{
+			LLNotification::Params auth_request_params;
+			auth_request_params.name = "AuthRequest";
+
+			// pass in host name and realm for site (may be zero length but will always exist)
+			LLSD args;
+			LLURL raw_url( plugin->getAuthURL().c_str() );
+			args["HOST_NAME"] = raw_url.getAuthority();
+			args["REALM"] = plugin->getAuthRealm();
+			auth_request_params.substitutions = args;
+
+			auth_request_params.payload = LLSD().with("media_id", mTextureId);
+			auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2);
+			LLNotifications::instance().add(auth_request_params);
+		};
+		break;
+
 		case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST:
 		{
 			std::string uuid = plugin->getClickUUID();
@@ -3019,6 +3136,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 				// This close request is directed at another instance
 				pass_through = false;
 				LLFloaterMediaBrowser::closeRequest(uuid);
+				LLFloaterWebContent::closeRequest(uuid);
 			}
 		}
 		break;
@@ -3038,6 +3156,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 				// This request is directed at another instance
 				pass_through = false;
 				LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());
+				LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());
 			}
 		}
 		break;
@@ -3521,6 +3640,11 @@ bool LLViewerMediaImpl::isInAgentParcel() const
 	return result;
 }
 
+LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const
+{
+	return mNotification;
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 //
 // static
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 4025a4484ff0437edb7d708893b8fb1e93c3f772..e2e342cc454e7e73892979012eed48434a33ef76 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -37,6 +37,7 @@
 
 #include "llpluginclassmedia.h"
 #include "v4color.h"
+#include "llnotificationptr.h"
 
 #include "llurl.h"
 
@@ -130,6 +131,8 @@ class LLViewerMedia
 	static bool isParcelMediaPlaying();
 	static bool isParcelAudioPlaying();
 	
+	static void onAuthSubmit(const LLSD& notification, const LLSD& response);
+
 	// Clear all cookies for all plugins
 	static void clearAllCookies();
 	
@@ -155,6 +158,9 @@ class LLViewerMedia
 	static void proxyWindowOpened(const std::string &target, const std::string &uuid);
 	static void proxyWindowClosed(const std::string &uuid);
 	
+	static void createSpareBrowserMediaSource();
+	static LLPluginClassMedia* getSpareBrowserMediaSource();
+	
 private:
 	static void setOpenIDCookie();
 	static void onTeleportFinished();
@@ -162,6 +168,7 @@ class LLViewerMedia
 	static LLPluginCookieStore *sCookieStore;
 	static LLURL sOpenIDURL;
 	static std::string sOpenIDCookie;
+	static LLPluginClassMedia* sSpareBrowserMediaSource;
 };
 
 // Implementation functions not exported into header file
@@ -195,6 +202,9 @@ class LLViewerMediaImpl
 	LLPluginClassMedia* getMediaPlugin() { return mMediaSource; }
 	void setSize(int width, int height);
 
+	void showNotification(LLNotificationPtr notify);
+	void hideNotification();
+
 	void play();
 	void stop();
 	void pause();
@@ -387,6 +397,9 @@ class LLViewerMediaImpl
 	// Is this media in the agent's parcel?
 	bool isInAgentParcel() const;
 
+	// get currently active notification associated with this media instance
+	LLNotificationPtr getCurrentNotification() const;
+
 private:
 	bool isAutoPlayable() const;
 	bool shouldShowBasedOnClass() const;
@@ -444,7 +457,8 @@ class LLViewerMediaImpl
 	bool mNavigateSuspendedDeferred;
 	bool mTrustedBrowser;
 	std::string mTarget;
-	
+	LLNotificationPtr mNotification;
+
 private:
 	BOOL mIsUpdated ;
 	std::list< LLVOVolume* > mObjectList ;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index e18b4ec414aac3557716cb6aa89ff66c1f41c9ea..9e16bf2fbb0fc362ceae59b1e2e7a523f4c3d07f 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7223,6 +7223,12 @@ void handle_web_browser_test(const LLSD& param)
 	LLWeb::loadURLInternal(url);
 }
 
+void handle_web_content_test(const LLSD& param)
+{
+	std::string url = param.asString();
+	LLWeb::loadWebURLInternal(url);
+}
+
 void handle_buy_currency_test(void*)
 {
 	std::string url =
@@ -7973,7 +7979,8 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");
 
 	// Advanced > UI
-	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2));
+	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test,	_2));	// sigh! this one opens the MEDIA browser
+	commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2));	// this one opens the Web Content floater
 	view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
 	view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
 	view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 99e869dafc153ad29347b5dbfbdde184920b1987..40f0b433132389ca31151802c440b2e80fdfd1b8 100644
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -586,6 +586,18 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
 			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;
 		}
 		break;
+
+		case MEDIA_EVENT_AUTH_REQUEST:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL;
+		}
+		break;
+
+		case MEDIA_EVENT_LINK_HOVERED:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL;
+		};
+		break;
 	};
 }
 
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index 6028a8fbeac8f18057360e628806eed94e4a2f8d..b73017a51a2141cb525a1001e35c4bdfaa29152b 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -35,6 +35,7 @@
 #include "llagent.h"
 #include "llappviewer.h"
 #include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
 #include "llfloaterreg.h"
 #include "lllogininstance.h"
 #include "llparcel.h"
@@ -95,6 +96,23 @@ void LLWeb::loadURL(const std::string& url, const std::string& target, const std
 	}
 }
 
+// static
+void LLWeb::loadWebURL(const std::string& url, const std::string& target, const std::string& uuid)
+{
+	if(target == "_internal")
+	{
+		// Force load in the internal browser, as if with a blank target.
+		loadWebURLInternal(url, "", uuid);
+	}
+	else if (gSavedSettings.getBOOL("UseExternalBrowser") || (target == "_external"))
+	{
+		loadURLExternal(url);
+	}
+	else
+	{
+		loadWebURLInternal(url, target, uuid);
+	}
+}
 
 // static
 void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid)
@@ -102,6 +120,13 @@ void LLWeb::loadURLInternal(const std::string &url, const std::string& target, c
 	LLFloaterMediaBrowser::create(url, target, uuid);
 }
 
+// static
+// Explicitly open a Web URL using the Web content floater
+void LLWeb::loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid)
+{
+	LLFloaterWebContent::create(url, target, uuid);
+}
+
 
 // static
 void LLWeb::loadURLExternal(const std::string& url, const std::string& uuid)
diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h
index 291537658329e4c7f4f80fe2a012010764bba407..dc5958e57fb26cfdedc7e7fc38ec5489471ec0e7 100644
--- a/indra/newview/llweb.h
+++ b/indra/newview/llweb.h
@@ -57,6 +57,11 @@ class LLWeb
 	static void loadURLExternal(const std::string& url, const std::string& uuid);
 	static void loadURLExternal(const std::string& url, bool async, const std::string& uuid = LLStringUtil::null);
 
+	// Explicitly open a Web URL using the Web content floater vs. the more general media browser
+	static void loadWebURL(const std::string& url, const std::string& target, const std::string& uuid);
+	static void loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid);
+	static void loadWebURLInternal(const std::string &url) { loadWebURLInternal(url, LLStringUtil::null, LLStringUtil::null); }
+
 	/// Returns escaped url (eg, " " to "%20") - used by all loadURL methods
 	static std::string escapeURL(const std::string& url);
 	/// Expands various strings like [LANG], [VERSION], etc. in a URL
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index a51a096482da2b0aa6259dc1f9848323294ef49d..89611d8899d35a535d1aed8c3009cad078b9b3d8 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -392,7 +392,7 @@ with the same filename but different name
   <texture name="RadioButton_On_Disabled" file_name="widgets/RadioButton_On_Disabled.png" preload="true" />
 
 
-  <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="false" />
+  <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="true" />
 
   <texture name="Resize_Corner" file_name="windows/Resize_Corner.png" preload="true" />
 
@@ -468,7 +468,7 @@ with the same filename but different name
   <texture name="Stepper_Up_Off" file_name="widgets/Stepper_Up_Off.png" preload="false" />
   <texture name="Stepper_Up_Press" file_name="widgets/Stepper_Up_Press.png" preload="false" />
 
-  <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="false" />
+  <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="true" />
   <texture name="StopReload_Off" file_name="icons/StopReload_Off.png" preload="false" />
   <texture name="StopReload_Over" file_name="icons/StopReload_Over.png" preload="false" />
 
diff --git a/indra/newview/skins/default/xui/en/floater_help_browser.xml b/indra/newview/skins/default/xui/en/floater_help_browser.xml
index 837923bcf606c48dce7a36eb858eda8d2e36e324..02e50ee5844931593ad4894d0777b9f2ceff68c8 100644
--- a/indra/newview/skins/default/xui/en/floater_help_browser.xml
+++ b/indra/newview/skins/default/xui/en/floater_help_browser.xml
@@ -36,7 +36,8 @@
          user_resize="false"
          width="620">
             <web_browser
-              trusted_content="true" 
+             trusted_content="true" 
+             initial_mime_type="text/html" 
              bottom="-25"
              follows="left|right|top|bottom"
              layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_media_browser.xml b/indra/newview/skins/default/xui/en/floater_media_browser.xml
index 49e835cce4d8cb1b79b7dcc3331ee8f19d8fddad..43729d7c9fd0da284a6a19b7e50fb6932f270cc9 100644
--- a/indra/newview/skins/default/xui/en/floater_media_browser.xml
+++ b/indra/newview/skins/default/xui/en/floater_media_browser.xml
@@ -101,7 +101,7 @@
              left_pad="5"
              name="go"
              top_delta="0"
-             width="55">
+             width="50">
 				<button.commit_callback
 				function="MediaBrowser.Go" />
 			</button>
diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2ad46824c25def60bfef10ca725e16947a4184c4
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_web_content.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+  legacy_header_height="18"
+  can_resize="true"
+  height="440"
+  layout="topleft"
+  min_height="140"
+  min_width="467"
+  name="floater_web_content"
+  help_topic="floater_web_content"
+  save_rect="true"
+  auto_tile="true"
+  title=""
+  initial_mime_type="text/html"
+  width="820">
+  <layout_stack
+    bottom="440"
+    follows="left|right|top|bottom"
+    layout="topleft"
+    left="5"
+    name="stack1"
+    orientation="vertical"
+    top="20"
+    width="810">
+    <layout_panel
+      auto_resize="false"
+      default_tab_group="1"
+      height="22"
+      layout="topleft"
+      left="0"
+      min_height="20"
+      name="nav_controls"
+      top="400"
+      user_resize="false"
+      width="800">
+      <button
+        image_overlay="Arrow_Left_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+		    hover_glow_amount="0.15"
+        tool_tip="Navigate back"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="1"
+        name="back"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Back" />
+      </button>
+      <button
+        image_overlay="Arrow_Right_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Navigate forward"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="27"
+        name="forward"
+        top_delta="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Forward" />
+      </button>
+      <button
+        image_overlay="Stop_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Stop navigation"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="51"
+        name="stop"
+        top_delta="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Stop" />
+      </button>
+      <button
+        image_overlay="Refresh_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Reload page"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="51"
+        name="reload"
+        top_delta="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Reload" />
+      </button>
+      <combo_box
+        allow_text_entry="true"
+        follows="left|top|right"
+        tab_group="1"
+        height="22"
+        layout="topleft"
+        left_pad="4"
+        max_chars="1024"
+        name="address"
+        combo_editor.select_on_focus="true"
+        tool_tip="Enter URL here"
+        top_delta="0"
+        width="702">
+        <combo_box.commit_callback
+          function="WebContent.EnterAddress" />
+      </combo_box>
+      <icon
+        name="media_secure_lock_flag"
+        height="16"
+        follows="top|right"
+        image_name="Lock2"
+        layout="topleft"
+        left_delta="656"
+        top_delta="2"
+        visible="false" 
+        tool_tip="Secured Browsing"
+        width="16" />
+      <button
+        image_overlay="ExternalBrowser_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Open current URL in your desktop browser"
+        follows="right|top"
+        enabled="true" 
+        height="22"
+        layout="topleft"
+        name="popexternal"
+        right="800"
+        top_delta="-2"
+        width="22">
+        <button.commit_callback
+          function="WebContent.PopExternal" />
+      </button>
+    </layout_panel>
+    <layout_panel
+      height="40"
+      layout="topleft"
+      left_delta="0"
+      name="external_controls"
+      top_delta="0"
+      user_resize="false"
+      width="540">
+      <web_browser
+        bottom="-22"
+        follows="all"
+        layout="topleft"
+        left="0"
+        name="webbrowser"
+        top="0"/>
+      <text
+        type="string"
+        length="100"
+        follows="bottom|left"
+        height="20"
+        layout="topleft"
+        left_delta="0"
+        name="statusbartext"
+        parse_urls="false"
+        text_color="0.4 0.4 0.4 1" 
+        top_pad="5"
+        width="452"/>
+      <progress_bar
+        color_bar="0.3 1.0 0.3 1"
+        follows="bottom|right"
+        height="16"
+        top_delta="-1"
+        left_pad="24"
+        layout="topleft"
+        name="statusbarprogress"
+        width="64"/>
+    </layout_panel>
+  </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index 4f982cc8e9a6c69993754e6fc333b5a3d61d105f..0d4a095e14d4cb0c1ebf4241d7ac8ed1b33ffb00 100644
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -176,13 +176,19 @@
              parameter="message_critical" />
         </menu_item_call>
         <menu_item_call
-         label="Web Browser Test"
+         label="Media Browser Test"
          name="Web Browser Test">
           <menu_item_call.on_click
            function="Advanced.WebBrowserTest"
            parameter="http://join.secondlife.com/"/>
         </menu_item_call>
-      <menu_item_separator/>
+      <menu_item_call
+       label="Web Content Floater Test"
+       name="Web Content Floater Test">
+        <menu_item_call.on_click
+         function="Advanced.WebContentTest"
+         parameter="http://www.google.com"/>
+      </menu_item_call>
       <menu_item_check
         label="Show Grid Picker"
         name="Show Grid Picker"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 3b1ebc64ab33a67d09a0df62efbcc360ea04fdaa..d997a262a820dae84ff8332bbf921cf10661a09a 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2646,13 +2646,21 @@
                  parameter="BottomPanelNew" />
             </menu_item_check>-->
             <menu_item_call
-             label="Web Browser Test"
+             label="Media Browser Test"
              name="Web Browser Test">
                 <menu_item_call.on_click
                  function="Advanced.WebBrowserTest"
                  parameter="http://secondlife.com/app/search/slurls.html"/>
             </menu_item_call>
-            <menu_item_call
+          <menu_item_call
+           label="Web Content Browser"
+           name="Web Content Browser"
+           shortcut="control|alt|W">
+            <menu_item_call.on_click
+             function="Advanced.WebContentTest"
+             parameter="http://google.com"/>
+          </menu_item_call>
+          <menu_item_call
              label="Dump SelectMgr"
              name="Dump SelectMgr">
                 <menu_item_call.on_click
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index b1fd579c6fda57b86748c665230b33aa56211d93..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
@@ -5014,7 +5082,7 @@ If you want to view streaming media on parcels that support it you should go to
    type="notify">
 No Media Plugin was found to handle the "[MIME_TYPE]" mime type.  Media of this type will be unavailable.
     <unique>
-      <context key="[MIME_TYPE]"/>
+      <context>MIME_TYPE</context>
     </unique>
 
   </notification>
@@ -5943,7 +6011,7 @@ You may only select up to [MAX_SELECT] items from this list.
 [NAME] is inviting you to a Voice Chat call.
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -5992,8 +6060,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] has joined a Voice Chat call with the group [GROUP].
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
-      <context key="GROUP"/>
+      <context>NAME</context>
+      <context>GROUP</context>
     </unique>
     <form name="form">
       <button
@@ -6018,7 +6086,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] has joined a voice chat call with a conference chat.
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -6043,7 +6111,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] is inviting you to a conference chat.
 Click Accept to join the chat or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -6067,7 +6135,7 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block
    type="notifytip">
 The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum capacity. Please try again later.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6085,7 +6153,7 @@ We&apos;re sorry.  This area has reached maximum capacity for voice conversation
    type="notifytip">
 You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6095,7 +6163,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] has ended the call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6105,7 +6173,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] has declined your call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6115,7 +6183,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] is not available to take your call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6125,7 +6193,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 Failed to connect to [VOICE_CHANNEL_NAME], please try again later.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6211,7 +6279,7 @@ Cannot enter parcel, you are not on the access list.
    type="notifytip">
 You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6221,7 +6289,7 @@ You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
    type="notifytip">
 An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_NAME].  Please try again later.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6628,6 +6696,23 @@ Mute everyone?
     </form>
   </notification>
 
+  <notification
+  name="AuthRequest"
+  type="browser">
+The site at &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; in realm &apos;[REALM]&apos; requires a user name and password.
+    <form name="form">
+      <input name="username" type="text" text="User Name"/>
+      <input name="password" type="password" text="Password    "/>
+      <button default="true"
+              index="0"
+              name="ok"
+              text="Submit"/>
+      <button index="1"
+              name="cancel"
+              text="Cancel"/>
+    </form>
+  </notification>
+
   
   <global name="UnsupportedCPU">
 - Your CPU speed does not meet the minimum requirements.
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index e3cd61c5aa02258ce6d7eddbf403d170df38d006..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
@@ -92,6 +88,7 @@ follows="left|bottom"
   height="22"
   max_length_bytes="16"
 name="password_edit"
+is_password="true" 
 select_on_focus="true"
   top_pad="0"
   width="135" />
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_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 2f52ca660b833608d09f63c95d5c62e59d66484e..d756dfb7de6d53b13bdaabb3f059651fa0973fa0 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -51,7 +51,7 @@
      height="18"
      left="0" 
      name="balance"
-     tool_tip="My Balance"
+     tool_tip="Click to refresh your L$ balance"
      v_pad="4"
      top="0"
      wrap="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/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 6c77f8ec38b485ada06fcb15caff09b1816bd6d5..338c62b9fb3a7193971a511872c108a16fd69be4 100644
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -255,12 +255,6 @@ def construct(self):
 
             self.enable_crt_manifest_check()
 
-            # Get kdu dll, continue if missing.
-            try:
-                self.path('llkdu.dll', dst='llkdu.dll')
-            except RuntimeError:
-                print "Skipping llkdu.dll"
-
             # Get llcommon and deps. If missing assume static linkage and continue.
             try:
                 self.path('llcommon.dll')
@@ -625,21 +619,21 @@ def construct(self):
                 libdir = "../../libraries/universal-darwin/lib_release"
                 dylibs = {}
 
-                # need to get the kdu dll from any of the build directories as well
-                for lib in "llkdu", "llcommon":
-                    libfile = "lib%s.dylib" % lib
-                    try:
-                        self.path(self.find_existing_file(os.path.join(os.pardir,
-                                                                       lib,
-                                                                       self.args['configuration'],
-                                                                       libfile),
-                                                          os.path.join(libdir, libfile)),
-                                  dst=libfile)
-                    except RuntimeError:
-                        print "Skipping %s" % libfile
-                        dylibs[lib] = False
-                    else:
-                        dylibs[lib] = True
+                # Need to get the llcommon dll from any of the build directories as well
+                lib = "llcommon"
+                libfile = "lib%s.dylib" % lib
+                try:
+                    self.path(self.find_existing_file(os.path.join(os.pardir,
+                                                                    lib,
+                                                                    self.args['configuration'],
+                                                                    libfile),
+                                                      os.path.join(libdir, libfile)),
+                                                      dst=libfile)
+                except RuntimeError:
+                    print "Skipping %s" % libfile
+                    dylibs[lib] = False
+                else:
+                    dylibs[lib] = True
 
                 if dylibs["llcommon"]:
                     for libfile in ("libapr-1.0.3.7.dylib",
@@ -931,15 +925,6 @@ class Linux_i686Manifest(LinuxManifest):
     def construct(self):
         super(Linux_i686Manifest, self).construct()
 
-        # install either the libllkdu we just built, or a prebuilt one, in
-        # decreasing order of preference.  for linux package, this goes to bin/
-        try:
-            self.path(self.find_existing_file('../llkdu/libllkdu.so',
-                '../../libraries/i686-linux/lib_release_client/libllkdu.so'),
-                  dst='bin/libllkdu.so')
-        except:
-            print "Skipping libllkdu.so - not found"
-
         if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
             self.path("libapr-1.so.0")
             self.path("libaprutil-1.so.0")
@@ -955,12 +940,6 @@ def construct(self):
             self.path("libalut.so")
             self.path("libopenal.so", "libopenal.so.1")
             self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname
-            try:
-                    self.path("libkdu.so")
-                    pass
-            except:
-                    print "Skipping libkdu.so - not found"
-                    pass
             try:
                     self.path("libfmod-3.75.so")
                     pass
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index 873fa23db8675b55c8e5cfca4c3311a9411fafee..4a2272032b0a7fd2d1c85136da9822e8e5f805a7 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -2220,6 +2220,21 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e
 				<< ", height = " << self->getGeometryHeight() 
 				<< std::endl;
 		break;
+
+		case MEDIA_EVENT_AUTH_REQUEST:
+		{
+			//std::cerr <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() ", realm " << self->getAuthRealm() << std::endl;
+
+			// TODO: display an auth dialog
+			self->sendAuthResponse(false, "", "");
+		}
+		break;
+
+		case MEDIA_EVENT_LINK_HOVERED:
+		{
+			std::cerr <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << std::endl;
+		};
+		break;
 	}
 }
 
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/install.xml b/install.xml
index 98e983299e413afa5c879da1852f30389cf162fa..13abaac1c1ce5a6ae5c9eecb3e2c00b2c7e42ad4 100644
--- a/install.xml
+++ b/install.xml
@@ -233,16 +233,16 @@
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>752e295ccb17f0dcb7c0167db3ad1e69</string>
+            <string>ca8f0134fa5ab6f34a6eeb8d0896c9b0</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.20.1-darwin-20100606.tar.bz2</uri>
+            <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Darwin/installer/curl-7.21.1-darwin-20101214.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>
             <key>md5sum</key>
-            <string>a20e73f2e7d6a032ff25a5161b1b7394</string>
+            <string>9c9b629b62bf874d550c430ad678dc04</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.20.1-linux-20100527.tar.bz2</uri>
+            <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Linux/installer/curl-7.21.1-linux-20101215.tar.bz2</uri>
           </map>
           <key>linux64</key>
           <map>
@@ -254,9 +254,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>b28856d3d02ee680353ae440561a6579</string>
+            <string>48691883065a82d53691d73aae81d4c1</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.20.1-windows-20100611.tar.bz2</uri>
+            <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/CYGWIN/installer/curl-7.21.1-windows-20101214.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -830,23 +830,23 @@
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>ae18dd120807a46ac961b881a631ad94</string>
+            <string>8261994de5af6581e08c26fefe1b2810</string>
             <key>url</key>
-            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/indra_private-2.1.1-darwin-20100820.tar.bz2</uri>
+            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-darwin-20101123.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>
             <key>md5sum</key>
-            <string>b1f15bbabb68445e55ce23a2aeaca598</string>
+            <string>ed3e58899a424684dad49c94ba3813e7</string>
             <key>url</key>
-            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/indra_private-2.1.1-linux-20100826.tar.bz2</uri>
+            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-linux-20101124.tar.bz2</uri>
           </map>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>0e2fe621ce99085eba00d86d9a3bc130</string>
+            <string>066e089a5d9faeaf131e1f4e4860a163</string>
             <key>url</key>
-            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/indra_private-2.1.1-windows-20100820.tar.bz2</uri>
+            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-windows-20101123.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -981,9 +981,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>34d9e4c93678a422cf80521bf0cd7628</string>
+            <string>66c46841825ab4969ec875b5c8f9b24c</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-4.6-darwin-20100914.tar.bz2</uri>
+            <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-darwin-qt4.7.1-20101221.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>
@@ -995,9 +995,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>4b8412833c00f8cdaba26808f0ddb404</string>
+            <string>b678c4d18ea8e4fab42b20f8d0b2629a</string>
             <key>url</key>
-            <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.6-20100916.tar.bz2</uri>
+            <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.7.1-20101221.tar.bz2</uri>
           </map>
         </map>
       </map>