diff --git a/.hgtags b/.hgtags
index 0aa708c977912b8ad26cd0d11dbfbe239f7d5f7e..44ca1e0d7d5965485d6d12c1d2503b7459af416a 100755
--- a/.hgtags
+++ b/.hgtags
@@ -519,3 +519,4 @@ e9d350764dfbf5a46229e627547ef5c1b1eeef00 4.0.2-release
 4070611edd95eb3a683d1cd97c4c07fe67793812 4.0.6-release
 33981d8130f031597b4c7f4c981b18359afb61a0 4.0.7-release
 45eaee56883df7a439ed3300c44d3126f7e3a41e 4.0.8-release
+b280a1c797a3891e68dbc237e73de9cf19f426e9 4.1.1-release
diff --git a/autobuild.xml b/autobuild.xml
index 5a91ba15f5651898bb3c97cd1f24c1097999ea25..5ff6d3330539bd2fc1673f06d6a11ca85875bf27 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1454,9 +1454,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>faa1e5b7cf70c143caabe190fa5588ce</string>
+              <string>fddd634dec5ec03924d62cc774f7f8ea</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearance_viewer-update-llappearance-utility/rev/304432/arch/Linux/installer/llappearance_utility-0.0.1-linux-304432.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/p64_viewer-llappearance-utility/rev/317266/arch/Linux/installer/llappearance_utility-0.0.1-linux-317266.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -1484,11 +1484,11 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>29a1f64df46094eda0d681821a98d17e</string>
+              <string>db992d58c46c80df7d4d31f8a4784b98</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/311349/arch/Darwin/installer/llceflib-1.5.3.311349-darwin-311349.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/317959/arch/Darwin/installer/llceflib-1.5.3.317959-darwin-317959.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -1498,18 +1498,18 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>827b7c339a2cd401d9d23f9ee02cb83f</string>
+              <string>bb3818628131a99cd789febfad9dc2c2</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/311349/arch/CYGWIN/installer/llceflib-1.5.3.311349-windows-311349.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/317959/arch/CYGWIN/installer/llceflib-1.5.3.317959-windows-317959.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.5.3.311349</string>
+        <string>1.5.3.317959</string>
       </map>
       <key>llphysicsextensions_source</key>
       <map>
@@ -2135,6 +2135,46 @@
         <key>version</key>
         <string>0.8.0.1</string>
       </map>
+      <key>vlc-bin</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright (C) 1998-2016 VLC authors and VideoLAN</string>
+        <key>license</key>
+        <string>GPL2</string>
+        <key>license_file</key>
+        <string>LICENSES/vlc.txt</string>
+        <key>name</key>
+        <string>vlc-bin</string>
+        <key>platforms</key>
+        <map>
+          <key>linux</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>2f410640df3f9812d1abff02a414cfa8</string>
+              <key>url</key>
+              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-vlc-bin/rev/315283/arch/Linux/vlc_bin-2.2.3-linux-201606011750-r10.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>linux</string>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>04cff37070a5f65f3652b4ddcec7183f</string>
+              <key>url</key>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-vlc-bin/rev/317935/arch/CYGWIN/installer/vlc_bin-2.2.4.317935-windows-317935.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>windows</string>
+          </map>
+        </map>
+        <key>version</key>
+        <string>2.2.4.317935</string>
+      </map>
       <key>xmlrpc-epi</key>
       <map>
         <key>copyright</key>
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 6dc8e3dfbf7572d7bdca353a6588c5ac544d25ca..13a31cbce7d02c488e6a782e1f6a04ce58db798d 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -24,7 +24,6 @@ set(cmake_SOURCE_FILES
     DirectX.cmake
     DragDrop.cmake
     EXPAT.cmake
-##  ExamplePlugin.cmake
     FindAPR.cmake
     FindAutobuild.cmake
     FindBerkeleyDB.cmake
@@ -100,6 +99,7 @@ set(cmake_SOURCE_FILES
     Variables.cmake
     ViewerMiscLibs.cmake
     VisualLeakDetector.cmake
+    LibVLCPlugin.cmake
     XmlRpcEpi.cmake
     ZLIB.cmake
     )
diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake
index ba07a80f051af43e9165f8f74c01f6b99be28198..80af7ff2ab2a6d1676404910ab75b55079a6f91f 100644
--- a/indra/cmake/LLWindow.cmake
+++ b/indra/cmake/LLWindow.cmake
@@ -18,7 +18,7 @@ else (USESYSTEMLIBS)
     use_prebuilt_binary(SDL)
     set (SDL_FOUND TRUE)
     set (SDL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/i686-linux)
-    set (SDL_LIBRARY SDL directfb fusion direct)
+    set (SDL_LIBRARY SDL directfb fusion direct X11)
   endif (LINUX)
 endif (USESYSTEMLIBS)
 
diff --git a/indra/cmake/LibVLCPlugin.cmake b/indra/cmake/LibVLCPlugin.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..4472676fb489b0d94d24936e4846de7597ff30f5
--- /dev/null
+++ b/indra/cmake/LibVLCPlugin.cmake
@@ -0,0 +1,27 @@
+# -*- cmake -*-
+include(Linking)
+include(Prebuilt)
+
+if (USESYSTEMLIBS)
+    set(LIBVLCPLUGIN OFF CACHE BOOL
+        "LIBVLCPLUGIN support for the llplugin/llmedia test apps.")
+else (USESYSTEMLIBS)
+    use_prebuilt_binary(vlc-bin)
+    set(LIBVLCPLUGIN ON CACHE BOOL
+        "LIBVLCPLUGIN support for the llplugin/llmedia test apps.")
+        set(VLC_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/vlc)
+endif (USESYSTEMLIBS)
+
+if (WINDOWS)
+    set(VLC_PLUGIN_LIBRARIES
+        libvlc.lib
+        libvlccore.lib
+    )
+elseif (DARWIN)
+elseif (LINUX)
+    # Specify a full path to make sure we get a static link
+    set(VLC_PLUGIN_LIBRARIES
+        ${LIBS_PREBUILT_DIR}/lib/libvlc.a
+        ${LIBS_PREBUILT_DIR}/lib/libvlccore.a
+    )
+endif (WINDOWS)
diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt
index 32aa08a2b71e3eae62d6f24c97ff585f67bac9d4..9f9ca6c39c990d535e37755422678182cca8a7c3 100644
--- a/indra/edit-me-to-trigger-new-build.txt
+++ b/indra/edit-me-to-trigger-new-build.txt
@@ -1,3 +1,4 @@
 2014-02-25 10:34
 
 
+
diff --git a/indra/linux_crash_logger/linux_crash_logger.cpp b/indra/linux_crash_logger/linux_crash_logger.cpp
index 9d5ec33fed74add89e7f34e6ee401a2e542638d5..63e540987607b2c3cdcd4d5ecd994c53546f479d 100644
--- a/indra/linux_crash_logger/linux_crash_logger.cpp
+++ b/indra/linux_crash_logger/linux_crash_logger.cpp
@@ -51,7 +51,7 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
-	app.mainLoop();
+	app.frame();
 	app.cleanup();
 	LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;
 	return 0;
diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp
index e2d2e7ff26949fdfbfdc9c81db9520badbf255f2..4092d43fc5fc029818bb8cac9d76c13f003b77cc 100644
--- a/indra/linux_crash_logger/llcrashloggerlinux.cpp
+++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp
@@ -114,7 +114,7 @@ void LLCrashLoggerLinux::gatherPlatformSpecificFiles()
 {
 }
 
-bool LLCrashLoggerLinux::mainLoop()
+bool LLCrashLoggerLinux::frame()
 {
 	bool send_logs = true;
 	if(CRASH_BEHAVIOR_ASK == getCrashBehavior())
diff --git a/indra/linux_crash_logger/llcrashloggerlinux.h b/indra/linux_crash_logger/llcrashloggerlinux.h
index dae6c46651ba642e401aa09874d4c2d2567eb92f..789f6f03f578b48dd2953b992f502e3fc085c957 100644
--- a/indra/linux_crash_logger/llcrashloggerlinux.h
+++ b/indra/linux_crash_logger/llcrashloggerlinux.h
@@ -36,7 +36,7 @@ class LLCrashLoggerLinux : public LLCrashLogger
 public:
 	LLCrashLoggerLinux(void);
 	~LLCrashLoggerLinux(void);
-	virtual bool mainLoop();
+	virtual bool frame();
 	virtual void updateApplication(const std::string& = LLStringUtil::null);
 	virtual void gatherPlatformSpecificFiles();
 	virtual bool cleanup();
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index c3242389c272c728f53799d642e77963b71735df..5bce2b88099fa1242c08776733f2c88d84c76ff7 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -59,6 +59,7 @@ set(llcommon_SOURCE_FILES
     lleventfilter.cpp
     llevents.cpp
     lleventtimer.cpp
+    llexception.cpp
     llfasttimer.cpp
     llfile.cpp
     llfindlocale.cpp
@@ -160,6 +161,7 @@ set(llcommon_HEADER_FILES
     lleventfilter.h
     llevents.h
     lleventemitter.h
+    llexception.h
     llfasttimer.h
     llfile.h
     llfindlocale.h
@@ -319,7 +321,7 @@ if (LL_TESTS)
   LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
-  LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")                          
+  LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lltrace "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")
@@ -332,6 +334,11 @@ if (LL_TESTS)
   LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llstreamqueue "" "${test_libs}")
 
+## llexception_test.cpp isn't a regression test, and doesn't need to be run
+## every build. It's to help a developer make implementation choices about
+## throwing and catching exceptions.
+##LL_ADD_INTEGRATION_TEST(llexception "" "${test_libs}")
+
   # *TODO - reenable these once tcmalloc libs no longer break the build.
   #ADD_BUILD_TEST(llallocator llcommon)
   #ADD_BUILD_TEST(llallocator_heap_profile llcommon)
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index d9933b3d369d21590bedc35c07c1a258b54f1e02..ff9a92b45f703418c1d2c03018af7fee8486566b 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -172,12 +172,12 @@ class LL_COMMON_API LLApp
 	virtual bool cleanup() = 0;			// Override to do application cleanup
 
 	//
-	// mainLoop()
+	// frame()
 	//
-	// Runs the application main loop.  It's assumed that when you exit
-	// this method, the application is in one of the cleanup states, either QUITTING or ERROR
+	// Pass control to the application for a single frame. Returns 'done'
+	// flag: if frame() returns false, it expects to be called again.
 	//
-	virtual bool mainLoop() = 0; // Override for the application main loop.  Needs to at least gracefully notice the QUITTING state and exit.
+	virtual bool frame() = 0; // Override for application body logic
 
 	//
 	// Crash logging
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 5bbce4325b9274657abc679e510e4be6fc189bf7..8e516d8beb9395429bafb58d6eeb27c7c2a82fa0 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -38,6 +38,7 @@
 #include "llevents.h"
 #include "llerror.h"
 #include "stringize.h"
+#include "llexception.h"
 
 // do nothing, when we need nothing done
 void LLCoros::no_cleanup(CoroData*) {}
@@ -235,7 +236,23 @@ void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& calla
     // capture the 'self' param in CoroData
     data->mSelf = &self;
     // run the code the caller actually wants in the coroutine
-    callable();
+    try
+    {
+        callable();
+    }
+    catch (const LLContinueError&)
+    {
+        // Any uncaught exception derived from LLContinueError will be caught
+        // here and logged. This coroutine will terminate but the rest of the
+        // viewer will carry on.
+        LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName));
+    }
+    catch (...)
+    {
+        // Any OTHER kind of uncaught exception will cause the viewer to
+        // crash, hopefully informatively.
+        CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName));
+    }
     // This cleanup isn't perfectly symmetrical with the way we initially set
     // data->mPrev, but this is our last chance to reset mCurrentCoro.
     sCurrentCoro.reset(data->mPrev);
diff --git a/indra/llcommon/lldependencies.cpp b/indra/llcommon/lldependencies.cpp
index 0e72c175cb7dfff13d3f481891173e14ad58ac51..0d5757effddf550c331c91a0b78b9e6267aac27c 100644
--- a/indra/llcommon/lldependencies.cpp
+++ b/indra/llcommon/lldependencies.cpp
@@ -40,6 +40,7 @@
 #include <boost/graph/topological_sort.hpp>
 #include <boost/graph/exception.hpp>
 // other Linden headers
+#include "llexception.h"
 
 LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const EdgeList& edges) const
 {
@@ -76,7 +77,7 @@ LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const
         // Omit independent nodes: display only those that might contribute to
         // the cycle.
         describe(out, false);
-        throw Cycle(out.str());
+        LLTHROW(Cycle(out.str()));
     }
     // A peculiarity of boost::topological_sort() is that it emits results in
     // REVERSE topological order: to get the result you want, you must
diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h
index e0294e271ba472c050d82c87a0212cb684549eaf..125bd6a835ce501ef35d5ffe3c3e420dcdc2633b 100644
--- a/indra/llcommon/lldependencies.h
+++ b/indra/llcommon/lldependencies.h
@@ -34,13 +34,13 @@
 #include <vector>
 #include <set>
 #include <map>
-#include <stdexcept>
 #include <iosfwd>
 #include <boost/iterator/transform_iterator.hpp>
 #include <boost/iterator/indirect_iterator.hpp>
 #include <boost/range/iterator_range.hpp>
 #include <boost/function.hpp>
 #include <boost/bind.hpp>
+#include "llexception.h"
 
 /*****************************************************************************
 *   Utilities
@@ -106,9 +106,9 @@ class LL_COMMON_API LLDependenciesBase
     /**
      * Exception thrown by sort() if there's a cycle
      */
-    struct Cycle: public std::runtime_error
+    struct Cycle: public LLException
     {
-        Cycle(const std::string& what): std::runtime_error(what) {}
+        Cycle(const std::string& what): LLException(what) {}
     };
 
     /**
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 555a189b00a15859c0b4aeec1ee6e400e9dcda9a..3573b3f44e7851a00732b5b312b765de8e83f684 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -174,7 +174,8 @@ namespace LLError
 			// not really a level
 			// used to indicate that no messages should be logged
 	};
-	
+	// If you change ELevel, please update llvlog() macro below.
+
 	/*	Macro support
 		The classes CallSite and Log are used by the logging macros below.
 		They are not intended for general use.
@@ -305,24 +306,38 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
 
 /////////////////////////////////
 // Error Logging Macros
-// See top of file for common usage.	
+// See top of file for common usage.
 /////////////////////////////////
 
-// this macro uses a one-shot do statement to avoid parsing errors when writing control flow statements
-// without braces:
-// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL
-
-#define lllog(level, once, ...)																	          \
-	do {                                                                                                  \
-		const char* tags[] = {"", ##__VA_ARGS__};													      \
-		::size_t tag_count = LL_ARRAY_SIZE(tags) - 1;													  \
-		static LLError::CallSite _site(                                                                   \
-		    level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, once, &tags[1], tag_count);\
-		if (LL_UNLIKELY(_site.shouldLog()))			                                                      \
-		{                                                                                                 \
-			std::ostringstream* _out = LLError::Log::out();                                               \
+// Instead of using LL_DEBUGS(), LL_INFOS() et al., it may be tempting to
+// directly code the lllog() macro so you can pass in the LLError::ELevel as a
+// variable. DON'T DO IT! The reason is that the first time control passes
+// through lllog(), it initializes a local static LLError::CallSite with that
+// *first* ELevel value. All subsequent visits will decide whether or not to
+// emit output based on the *first* ELevel value bound into that static
+// CallSite instance. Use LL_VLOGS() instead. lllog() assumes its ELevel
+// argument never varies.
+
+// this macro uses a one-shot do statement to avoid parsing errors when
+// writing control flow statements without braces:
+// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL;
+
+#define lllog(level, once, ...)                                         \
+	do {                                                                \
+		const char* tags[] = {"", ##__VA_ARGS__};                       \
+		static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
+		lllog_test_()
+
+#define lllog_test_()                                       \
+		if (LL_UNLIKELY(_site.shouldLog()))                 \
+		{                                                   \
+			std::ostringstream* _out = LLError::Log::out(); \
 			(*_out)
 
+#define lllog_site_args_(level, once, tags)                 \
+	level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG),    \
+	__FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1
+
 //Use this construct if you need to do computation in the middle of a
 //message:
 //	
@@ -363,6 +378,48 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
 #define LL_INFOS_ONCE(...)	lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__)
 #define LL_WARNS_ONCE(...)	lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__)
 
+// Use this if you need to pass LLError::ELevel as a variable.
+#define LL_VLOGS(level, ...)      llvlog(level, false, ##__VA_ARGS__)
+#define LL_VLOGS_ONCE(level, ...) llvlog(level, true,  ##__VA_ARGS__)
+
+// The problem with using lllog() with a variable level is that the first time
+// through, it initializes a static CallSite instance with whatever level you
+// pass. That first level is bound into the CallSite; the level parameter is
+// never again examined. One approach to variable level would be to
+// dynamically construct a CallSite instance every call -- which could get
+// expensive, depending on context. So instead, initialize a static CallSite
+// for each level value we support, then dynamically select the CallSite
+// instance for the passed level value.
+// Compare implementation to lllog() above.
+#define llvlog(level, once, ...)                                        \
+	do {                                                                \
+		const char* tags[] = {"", ##__VA_ARGS__};                       \
+		/* Need a static CallSite instance per expected ELevel value. */ \
+		/* Since we intend to index this array with the ELevel, */      \
+		/* _sites[0] should be ELevel(0), and so on -- avoid using */   \
+		/* ELevel symbolic names when initializing -- except for */     \
+		/* the last entry, which handles anything beyond the end. */    \
+		/* (Commented ELevel value names are from 2016-09-01.) */       \
+		/* Passing an ELevel past the end of this array is itself */    \
+		/* a fatal error, so ensure the last is LEVEL_ERROR. */         \
+		static LLError::CallSite _sites[] =                             \
+		{                                                               \
+			/* LEVEL_DEBUG */                                           \
+			LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \
+			/* LEVEL_INFO */                                            \
+			LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \
+			/* LEVEL_WARN */                                            \
+			LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \
+			/* LEVEL_ERROR */                                           \
+			LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \
+		};                                                              \
+		/* Clamp the passed 'level' to at most last entry */            \
+		std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \
+						  (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \
+		/* selected CallSite *must* be named _site for LL_ENDL */       \
+		LLError::CallSite& _site(_sites[which]);                        \
+		lllog_test_()
+
 // Check at run-time whether logging is enabled, without generating output
 bool debugLoggingEnabled(const std::string& tag);
 
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
index 2d5f964deb2fa62efe9ee671ae85175e1e0ae568..56367b8f54448ba864e5b1d1fed873150c22d159 100644
--- a/indra/llcommon/lleventcoro.cpp
+++ b/indra/llcommon/lleventcoro.cpp
@@ -39,6 +39,7 @@
 #include "llerror.h"
 #include "llcoros.h"
 #include "llmake.h"
+#include "llexception.h"
 
 #include "lleventfilter.h"
 
@@ -351,7 +352,7 @@ LLSD errorException(const LLEventWithID& result, const std::string& desc)
     // returning it, deliver it via exception.
     if (result.second)
     {
-        throw LLErrorEvent(desc, result.first);
+        LLTHROW(LLErrorEvent(desc, result.first));
     }
     // That way, our caller knows a simple return must be from the reply
     // pump (pump 0).
diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h
index 87926c692deae5586a83be90ae7fd42642649703..84827aab4af6140be5834140df1bad2cfb8c32c5 100644
--- a/indra/llcommon/lleventcoro.h
+++ b/indra/llcommon/lleventcoro.h
@@ -31,10 +31,10 @@
 
 #include <boost/optional.hpp>
 #include <string>
-#include <stdexcept>
 #include <utility>                  // std::pair
 #include "llevents.h"
 #include "llerror.h"
+#include "llexception.h"
 
 /**
  * Like LLListenerOrPumpName, this is a class intended for parameter lists:
@@ -234,11 +234,11 @@ LLSD errorException(const LLEventWithID& result, const std::string& desc);
  * because it's not an error in event processing: rather, this exception
  * announces an event that bears error information (for some other API).
  */
-class LL_COMMON_API LLErrorEvent: public std::runtime_error
+class LL_COMMON_API LLErrorEvent: public LLException
 {
 public:
     LLErrorEvent(const std::string& what, const LLSD& data):
-        std::runtime_error(what),
+        LLException(what),
         mData(data)
     {}
     virtual ~LLErrorEvent() throw() {}
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index 645c29d770c70678f16388dda67438eb64670b9b..19d700a3b06073d7793cf0a5a0f066bed8ece11f 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -57,6 +57,7 @@
 #include "stringize.h"
 #include "llerror.h"
 #include "llsdutil.h"
+#include "llexception.h"
 #if LL_MSVC
 #pragma warning (disable : 4702)
 #endif
@@ -174,7 +175,7 @@ std::string LLEventPumps::registerNew(const LLEventPump& pump, const std::string
     // Unless we're permitted to tweak it, that's Bad.
     if (! tweak)
     {
-        throw LLEventPump::DupPumpName(std::string("Duplicate LLEventPump name '") + name + "'");
+        LLTHROW(LLEventPump::DupPumpName("Duplicate LLEventPump name '" + name + "'"));
     }
     // The passed name isn't unique, but we're permitted to tweak it. Find the
     // first decimal-integer suffix not already taken. The insert() attempt
@@ -326,8 +327,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
     // is only when the existing connection object is still connected.
     if (found != mConnections.end() && found->second.connected())
     {
-        throw DupListenerName(std::string("Attempt to register duplicate listener name '") + name +
-                              "' on " + typeid(*this).name() + " '" + getName() + "'");
+        LLTHROW(DupListenerName("Attempt to register duplicate listener name '" + name +
+                                "' on " + typeid(*this).name() + " '" + getName() + "'"));
     }
     // Okay, name is unique, try to reconcile its dependencies. Specify a new
     // "node" value that we never use for an mSignal placement; we'll fix it
@@ -353,8 +354,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
         // unsortable. If we leave the new node in mDeps, it will continue
         // to screw up all future attempts to sort()! Pull it out.
         mDeps.remove(name);
-        throw Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() +
-                    " '" + getName() + "' would cause cycle: " + e.what());
+        LLTHROW(Cycle("New listener '" + name + "' on " + typeid(*this).name() +
+                      " '" + getName() + "' would cause cycle: " + e.what()));
     }
     // Walk the list to verify that we haven't changed the order.
     float previous = 0.0, myprev = 0.0;
@@ -418,7 +419,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
             // NOW remove the offending listener node.
             mDeps.remove(name);
             // Having constructed a description of the order change, inform caller.
-            throw OrderChange(out.str());
+            LLTHROW(OrderChange(out.str()));
         }
         // This node becomes the previous one.
         previous = dmi->second;
@@ -608,7 +609,7 @@ bool LLListenerOrPumpName::operator()(const LLSD& event) const
 {
     if (! mListener)
     {
-        throw Empty("attempting to call uninitialized");
+        LLTHROW(Empty("attempting to call uninitialized"));
     }
     return (*mListener)(event);
 }
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index ba4fcd766ee594ff2b9c04b2582dc30fa75fb3a5..15261287252c7deb5d9dc52450cc1dced5975622 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -37,7 +37,6 @@
 #include <set>
 #include <vector>
 #include <deque>
-#include <stdexcept>
 #if LL_WINDOWS
 	#pragma warning (push)
 	#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
@@ -62,6 +61,7 @@
 #include "llsingleton.h"
 #include "lldependencies.h"
 #include "llstl.h"
+#include "llexception.h"
 
 /*==========================================================================*|
 // override this to allow binding free functions with more parameters
@@ -95,12 +95,32 @@ struct LLStopWhenHandled
     result_type operator()(InputIterator first, InputIterator last) const
     {
         for (InputIterator si = first; si != last; ++si)
-		{
-            if (*si)
-			{
-                return true;
-			}
-		}
+        {
+            try
+            {
+                if (*si)
+                {
+                    return true;
+                }
+            }
+            catch (const LLContinueError&)
+            {
+                // We catch LLContinueError here because an LLContinueError-
+                // based exception means the viewer as a whole should carry on
+                // to the best of our ability. Therefore subsequent listeners
+                // on the same LLEventPump should still receive this event.
+
+                // The iterator passed to a boost::signals2 Combiner is very
+                // clever, but provides no contextual information. We would
+                // very much like to be able to log the name of the LLEventPump
+                // plus the name of this particular listener, but alas.
+                LOG_UNHANDLED_EXCEPTION("LLEventPump");
+            }
+            // We do NOT catch (...) here because we might as well let it
+            // propagate out to the generic handler. If we were able to log
+            // context information here, that would be great, but we can't, so
+            // there's no point.
+        }
         return false;
     }
 };
@@ -188,10 +208,10 @@ class LL_COMMON_API LLListenerOrPumpName
     bool operator()(const LLSD& event) const;
 
     /// exception if you try to call when empty
-    struct Empty: public std::runtime_error
+    struct Empty: public LLException
     {
         Empty(const std::string& what):
-            std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
+            LLException(std::string("LLListenerOrPumpName::Empty: ") + what) {}
     };
 
 private:
@@ -371,10 +391,10 @@ class LL_COMMON_API LLEventPump: public LLEventTrackable
      * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
      * variant.
      */
-    struct DupPumpName: public std::runtime_error
+    struct DupPumpName: public LLException
     {
         DupPumpName(const std::string& what):
-            std::runtime_error(std::string("DupPumpName: ") + what) {}
+            LLException(std::string("DupPumpName: ") + what) {}
     };
 
     /**
@@ -399,9 +419,9 @@ class LL_COMMON_API LLEventPump: public LLEventTrackable
     /// group exceptions thrown by listen(). We use exceptions because these
     /// particular errors are likely to be coding errors, found and fixed by
     /// the developer even before preliminary checkin.
-    struct ListenError: public std::runtime_error
+    struct ListenError: public LLException
     {
-        ListenError(const std::string& what): std::runtime_error(what) {}
+        ListenError(const std::string& what): LLException(what) {}
     };
     /**
      * exception thrown by listen(). You are attempting to register a
diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b32ec2c9c9f067f30a57cb636cf0e98653135429
--- /dev/null
+++ b/indra/llcommon/llexception.cpp
@@ -0,0 +1,55 @@
+/**
+ * @file   llexception.cpp
+ * @author Nat Goodspeed
+ * @date   2016-08-12
+ * @brief  Implementation for llexception.
+ * 
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llexception.h"
+// STL headers
+// std headers
+#include <typeinfo>
+// external library headers
+#include <boost/exception/diagnostic_information.hpp>
+// other Linden headers
+#include "llerror.h"
+#include "llerrorcontrol.h"
+
+namespace {
+// used by crash_on_unhandled_exception_() and log_unhandled_exception_()
+void log_unhandled_exception_(LLError::ELevel level,
+                              const char* file, int line, const char* pretty_function,
+                              const std::string& context)
+{
+    // log same message but allow caller-specified severity level
+    LL_VLOGS(level, "LLException") << LLError::abbreviateFile(file)
+        << "(" << line << "): Unhandled exception caught in " << pretty_function;
+    if (! context.empty())
+    {
+        LL_CONT << ": " << context;
+    }
+    LL_CONT << ":\n" << boost::current_exception_diagnostic_information() << LL_ENDL;
+}
+}
+
+void crash_on_unhandled_exception_(const char* file, int line, const char* pretty_function,
+                                   const std::string& context)
+{
+    // LL_ERRS() terminates and propagates message into crash dump.
+    log_unhandled_exception_(LLError::LEVEL_ERROR, file, line, pretty_function, context);
+}
+
+void log_unhandled_exception_(const char* file, int line, const char* pretty_function,
+                              const std::string& context)
+{
+    // Use LL_WARNS() because we seriously do not expect this to happen
+    // routinely, but we DO expect to return from this function.
+    log_unhandled_exception_(LLError::LEVEL_WARN, file, line, pretty_function, context);
+}
diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h
new file mode 100644
index 0000000000000000000000000000000000000000..dfcb7c192fee966fed022ae2e365c4a81529763b
--- /dev/null
+++ b/indra/llcommon/llexception.h
@@ -0,0 +1,85 @@
+/**
+ * @file   llexception.h
+ * @author Nat Goodspeed
+ * @date   2016-06-29
+ * @brief  Types needed for generic exception handling
+ * 
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLEXCEPTION_H)
+#define LL_LLEXCEPTION_H
+
+#include <stdexcept>
+#include <boost/exception/exception.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/current_function.hpp>
+
+// "Found someone who can comfort me
+//  But there are always exceptions..."
+//  - Empty Pages, Traffic, from John Barleycorn (1970)
+//    https://www.youtube.com/watch?v=dRH0CGVK7ic
+
+/**
+ * LLException is intended as the common base class from which all
+ * viewer-specific exceptions are derived. Rationale for why it's derived from
+ * both std::exception and boost::exception is explained in
+ * tests/llexception_test.cpp.
+ *
+ * boost::current_exception_diagnostic_information() is quite wonderful: if
+ * all we need to do with an exception is log it, in most places we should
+ * catch (...) and log boost::current_exception_diagnostic_information().
+ * See CRASH_ON_UNHANDLED_EXCEPTION() and LOG_UNHANDLED_EXCEPTION() below.
+ *
+ * There may be circumstances in which it would be valuable to distinguish an
+ * exception explicitly thrown by viewer code from an exception thrown by
+ * (say) a third-party library. Catching (const LLException&) supports such
+ * usage. However, most of the value of this base class is in the
+ * diagnostic_information() available via Boost.Exception.
+ */
+struct LLException:
+    public std::runtime_error,
+    public boost::exception
+{
+    LLException(const std::string& what):
+        std::runtime_error(what)
+    {}
+};
+
+/**
+ * The point of LLContinueError is to distinguish exceptions that need not
+ * terminate the whole viewer session. In general, an uncaught exception will
+ * be logged and will crash the viewer. However, though an uncaught exception
+ * derived from LLContinueError will still be logged, the viewer will attempt
+ * to continue processing.
+ */
+struct LLContinueError: public LLException
+{
+    LLContinueError(const std::string& what):
+        LLException(what)
+    {}
+};
+
+/**
+ * Please use LLTHROW() to throw viewer exceptions whenever possible. This
+ * enriches the exception's diagnostic_information() with the source file,
+ * line and containing function of the LLTHROW() macro.
+ */
+// Currently we implement that using BOOST_THROW_EXCEPTION(). Wrap it in
+// LLTHROW() in case we ever want to revisit that implementation decision.
+#define LLTHROW(x) BOOST_THROW_EXCEPTION(x)
+
+/// Call this macro from a catch (...) clause
+#define CRASH_ON_UNHANDLED_EXCEPTION(CONTEXT) \
+     crash_on_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT)
+void crash_on_unhandled_exception_(const char*, int, const char*, const std::string&);
+
+/// Call this from a catch (const LLContinueError&) clause, or from a catch
+/// (...) clause in which you do NOT want the viewer to crash.
+#define LOG_UNHANDLED_EXCEPTION(CONTEXT) \
+     log_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT)
+void log_unhandled_exception_(const char*, int, const char*, const std::string&);
+
+#endif /* ! defined(LL_LLEXCEPTION_H) */
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 237025307843de532441cb8416c41f13dd190414..f56e5596f5496fd862ff3b39bf9ad21123ca5494 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -296,7 +296,16 @@ LL_FORCE_INLINE BlockTimer::BlockTimer(BlockTimerStatHandle& timer)
 {
 #if LL_FAST_TIMER_ON
 	BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();
-	if (!cur_timer_data) return;
+	if (!cur_timer_data)
+	{
+		// How likely is it that
+		// LLThreadLocalSingletonPointer<T>::getInstance() will return NULL?
+		// Even without researching, what we can say is that if we exit
+		// without setting mStartTime at all, gcc 4.7 produces (fatal)
+		// warnings about a possibly-uninitialized data member.
+		mStartTime = 0;
+		return;
+	}
 	TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
 	accumulator.mActiveCount++;
 	// keep current parent as long as it is active when we are
diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h
index 401e4d759ae048a43b07e618248bd9e83434f145..feb5f418489e5b401eff95591ba4dd0fc31dbd66 100644
--- a/indra/llcommon/llhandle.h
+++ b/indra/llcommon/llhandle.h
@@ -28,8 +28,11 @@
 #define LLHANDLE_H
 
 #include "llpointer.h"
+#include "llexception.h"
+#include <stdexcept>
 #include <boost/type_traits/is_convertible.hpp>
 #include <boost/utility/enable_if.hpp>
+#include <boost/throw_exception.hpp>
 
 /**
  * Helper object for LLHandle. Don't instantiate these directly, used
@@ -213,4 +216,82 @@ class LLHandleProvider
 	mutable LLRootHandle<T> mHandle;
 };
 
+
+
+class LLCheckedHandleBase
+{
+public:
+    class Stale : public LLException
+    {
+    public:
+        Stale() :
+            LLException("Attempt to access stale handle.")
+        {}
+    };
+
+protected:
+    LLCheckedHandleBase() { }
+
+};
+
+/**
+ * This is a simple wrapper for Handles, allowing direct calls to the underlying 
+ * pointer. The checked handle will throw a Stale if an attempt 
+ * is made to access the object referenced by the handle and that object has 
+ * been destroyed.
+ **/
+template <typename T> 
+class LLCheckedHandle: public LLCheckedHandleBase
+{
+public:
+
+    LLCheckedHandle(LLHandle<T> handle):
+        mHandle(handle)
+    { }
+
+    /**
+     * Test the underlying handle.  If it is no longer valid, throw a Stale exception.
+     */
+    void check() const
+    {
+        T* ptr = mHandle.get();
+        if (!ptr)
+            BOOST_THROW_EXCEPTION(Stale());
+    }
+
+    /**
+     * Cast back to an appropriate handle
+     */
+    operator LLHandle<T>() const
+    {
+        return mHandle;
+    }
+
+    /**
+     * Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {} 
+     * Does not throw.
+     */
+    /*explicit*/ operator bool() const // explicit conversion operator not available with Linux compiler
+    {
+        return (mHandle.get() != NULL);
+    }
+
+    /**
+     * Attempt to call a method or access a member in the structure referenced 
+     * by the handle.  If the handle no longer points to a valid structure 
+     * throw a Stale.
+     */
+    T* operator ->() const
+    {
+        T* ptr = mHandle.get();
+        if (!ptr)
+            BOOST_THROW_EXCEPTION(Stale());
+        return ptr;
+    }
+
+private:
+
+    LLHandle<T> mHandle;
+};
+
 #endif
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index 84d2a12f657364de4c170673bdeda1bb2b88a209..c87d2a3e588c87a6ee6a2e8a3dd808b1d540d116 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -33,6 +33,7 @@
 #include "lltimer.h"
 #include "lluuid.h"
 #include "llleaplistener.h"
+#include "llexception.h"
 
 #if LL_MSVC
 #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
@@ -69,7 +70,7 @@ class LLLeapImpl: public LLLeap
         // Rule out empty vector
         if (plugin.empty())
         {
-            throw Error("no plugin command");
+            LLTHROW(Error("no plugin command"));
         }
 
         // Don't leave desc empty either, but in this case, if we weren't
@@ -112,7 +113,7 @@ class LLLeapImpl: public LLLeap
         // If that didn't work, no point in keeping this LLLeap object.
         if (! mChild)
         {
-            throw Error(STRINGIZE("failed to run " << mDesc));
+            LLTHROW(Error(STRINGIZE("failed to run " << mDesc)));
         }
 
         // Okay, launch apparently worked. Change our mDonePump listener.
diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h
index e33f25e530957fb52943c91ed429b8912b043520..8aac8a64c578e243f2ec74bbfaa434e7d301812c 100644
--- a/indra/llcommon/llleap.h
+++ b/indra/llcommon/llleap.h
@@ -13,9 +13,9 @@
 #define LL_LLLEAP_H
 
 #include "llinstancetracker.h"
+#include "llexception.h"
 #include <string>
 #include <vector>
-#include <stdexcept>
 
 /**
  * LLSD Event API Plugin class. Because instances are managed by
@@ -67,9 +67,9 @@ class LL_COMMON_API LLLeap: public LLInstanceTracker<LLLeap>
      * string(s) passed to create() might come from an external source. This
      * way the caller can catch LLLeap::Error and try to recover.
      */
-    struct Error: public std::runtime_error
+    struct Error: public LLException
     {
-        Error(const std::string& what): std::runtime_error(what) {}
+        Error(const std::string& what): LLException(what) {}
     };
 
     virtual ~LLLeap();
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 0fb257aab1dbe6d89340c5831045928f6779e782..575edddc43c9500bd4142458d8faea6ad38b01ac 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -110,11 +110,15 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
 	#if defined(LL_WINDOWS)
 		return _aligned_malloc(size, align);
 	#else
+        char* aligned = NULL;
 		void* mem = malloc( size + (align - 1) + sizeof(void*) );
-		char* aligned = ((char*)mem) + sizeof(void*);
-		aligned += align - ((uintptr_t)aligned & (align - 1));
+        if (mem)
+        {
+            aligned = ((char*)mem) + sizeof(void*);
+            aligned += align - ((uintptr_t)aligned & (align - 1));
 
-		((void**)aligned)[-1] = mem;
+            ((void**)aligned)[-1] = mem;
+        }
 		return aligned;
 	#endif
 	}
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 44f56daf2dec5f6b96774dca026fcd90bd0d051a..8c321d06b9eaecad730a9e080da4bfd3e80a4eea 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -34,6 +34,7 @@
 #include "llapr.h"
 #include "apr_signal.h"
 #include "llevents.h"
+#include "llexception.h"
 
 #include <boost/foreach.hpp>
 #include <boost/bind.hpp>
@@ -472,9 +473,9 @@ class ReadPipeImpl: public LLProcess::ReadPipe
 *****************************************************************************/
 /// Need an exception to avoid constructing an invalid LLProcess object, but
 /// internal use only
-struct LLProcessError: public std::runtime_error
+struct LLProcessError: public LLException
 {
-	LLProcessError(const std::string& msg): std::runtime_error(msg) {}
+	LLProcessError(const std::string& msg): LLException(msg) {}
 };
 
 LLProcessPtr LLProcess::create(const LLSDOrParams& params)
@@ -530,8 +531,8 @@ LLProcess::LLProcess(const LLSDOrParams& params):
 
 	if (! params.validateBlock(true))
 	{
-		throw LLProcessError(STRINGIZE("not launched: failed parameter validation\n"
-									   << LLSDNotationStreamer(params)));
+		LLTHROW(LLProcessError(STRINGIZE("not launched: failed parameter validation\n"
+										 << LLSDNotationStreamer(params))));
 	}
 
 	mPostend = params.postend;
@@ -596,10 +597,10 @@ LLProcess::LLProcess(const LLSDOrParams& params):
 		}
 		else
 		{
-			throw LLProcessError(STRINGIZE("For " << params.executable()
-										   << ": unsupported FileParam for " << which
-										   << ": type='" << fparam.type()
-										   << "', name='" << fparam.name() << "'"));
+			LLTHROW(LLProcessError(STRINGIZE("For " << params.executable()
+											 << ": unsupported FileParam for " << which
+											 << ": type='" << fparam.type()
+											 << "', name='" << fparam.name() << "'")));
 		}
 	}
 	// By default, pass APR_NO_PIPE for unspecified slots.
@@ -678,7 +679,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
 	if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr,
 										   gAPRPoolp)))
 	{
-		throw LLProcessError(STRINGIZE(params << " failed"));
+		LLTHROW(LLProcessError(STRINGIZE(params << " failed")));
 	}
 
 	// arrange to call status_callback()
@@ -1063,7 +1064,7 @@ PIPETYPE& LLProcess::getPipe(FILESLOT slot)
 	PIPETYPE* wp = getPipePtr<PIPETYPE>(error, slot);
 	if (! wp)
 	{
-		throw NoPipe(error);
+		LLTHROW(NoPipe(error));
 	}
 	return *wp;
 }
diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h
index 43ccadc41278be52dcecb8acdd5a2b646fbee530..bfac4567a50587f5816a0cfcf94ba6127b9d2501 100644
--- a/indra/llcommon/llprocess.h
+++ b/indra/llcommon/llprocess.h
@@ -30,13 +30,13 @@
 #include "llinitparam.h"
 #include "llsdparam.h"
 #include "llwin32headerslean.h"
+#include "llexception.h"
 #include "apr_thread_proc.h"
 #include <boost/shared_ptr.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
 #include <boost/optional.hpp>
 #include <boost/noncopyable.hpp>
 #include <iosfwd>                   // std::ostream
-#include <stdexcept>
 
 #if LL_WINDOWS
 #include "llwin32headerslean.h"	// for HANDLE
@@ -479,9 +479,9 @@ class LL_COMMON_API LLProcess: public boost::noncopyable
 
 	/// Exception thrown by getWritePipe(), getReadPipe() if you didn't ask to
 	/// create a pipe at the corresponding FILESLOT.
-	struct NoPipe: public std::runtime_error
+	struct NoPipe: public LLException
 	{
-		NoPipe(const std::string& what): std::runtime_error(what) {}
+		NoPipe(const std::string& what): LLException(what) {}
 	};
 
 	/**
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
index 185f0d63fb4d536d9ac11ce064c2666ff15e7bc7..491f920c0f943c6be98b3078e45ee4583cf9f9e4 100644
--- a/indra/llcommon/llthreadsafequeue.cpp
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -27,6 +27,7 @@
 #include <apr_pools.h>
 #include <apr_queue.h>
 #include "llthreadsafequeue.h"
+#include "llexception.h"
 
 
 
@@ -41,13 +42,13 @@ LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * po
 {
 	if(mOwnsPool) {
 		apr_status_t status = apr_pool_create(&mPool, 0);
-		if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool");
+		if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate pool"));
 	} else {
 		; // No op.
 	}
 	
 	apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
-	if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
+	if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate queue"));
 }
 
 
@@ -68,9 +69,9 @@ void LLThreadSafeQueueImplementation::pushFront(void * element)
 	apr_status_t status = apr_queue_push(mQueue, element);
 	
 	if(status == APR_EINTR) {
-		throw LLThreadSafeQueueInterrupt();
+		LLTHROW(LLThreadSafeQueueInterrupt());
 	} else if(status != APR_SUCCESS) {
-		throw LLThreadSafeQueueError("push failed");
+		LLTHROW(LLThreadSafeQueueError("push failed"));
 	} else {
 		; // Success.
 	}
@@ -88,9 +89,9 @@ void * LLThreadSafeQueueImplementation::popBack(void)
 	apr_status_t status = apr_queue_pop(mQueue, &element);
 
 	if(status == APR_EINTR) {
-		throw LLThreadSafeQueueInterrupt();
+		LLTHROW(LLThreadSafeQueueInterrupt());
 	} else if(status != APR_SUCCESS) {
-		throw LLThreadSafeQueueError("pop failed");
+		LLTHROW(LLThreadSafeQueueError("pop failed"));
 	} else {
 		return element;
 	}
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 58cac38769cd2d3801fc9f01b1d1cc2a010ae0c6..45289ef0b400fa6a0f0b3f6d4b96ae1721cf12d7 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -27,9 +27,8 @@
 #ifndef LL_LLTHREADSAFEQUEUE_H
 #define LL_LLTHREADSAFEQUEUE_H
 
-
+#include "llexception.h"
 #include <string>
-#include <stdexcept>
 
 
 struct apr_pool_t; // From apr_pools.h
@@ -40,11 +39,11 @@ class LLThreadSafeQueueImplementation; // See below.
 // A general queue exception.
 //
 class LL_COMMON_API LLThreadSafeQueueError:
-public std::runtime_error
+	public LLException
 {
 public:
 	LLThreadSafeQueueError(std::string const & message):
-	std::runtime_error(message)
+		LLException(message)
 	{
 		; // No op.
 	}
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index e3671047b4a3375921aa6bbec95726931f227f47..d4af2c6b011f2cf261247a5a798ef051060c988c 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -83,7 +83,7 @@ unsigned int decode( char const * fiveChars ) throw( bad_input_data )
 unsigned int ret = 0;
 for( int ix = 0; ix < 5; ++ix ) {
 char * s = strchr( encodeTable, fiveChars[ ix ] );
-if( s == 0 ) throw bad_input_data();
+if( s == 0 ) LLTHROW(bad_input_data());
 ret = ret * 85 + (s-encodeTable);
 }
 return ret;
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index f51279e8172009f0b0475189313a0b25e3070b19..8bace8ac41f031f1643afb37b91c276b75bab5d1 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -237,8 +237,21 @@ namespace tut
 	void ErrorTestObject::test<4>()
 		// file abbreviation
 	{
-		std::string thisFile = __FILE__;
-		std::string abbreviateFile = LLError::abbreviateFile(thisFile);
+		std::string prev, abbreviateFile = __FILE__;
+        do
+        {
+            prev = abbreviateFile;
+            abbreviateFile = LLError::abbreviateFile(abbreviateFile);
+            // __FILE__ is assumed to end with
+            // indra/llcommon/tests/llerror_test.cpp. This test used to call
+            // abbreviateFile() exactly once, then check below whether it
+            // still contained the string 'indra'. That fails if the FIRST
+            // part of the pathname also contains indra! Certain developer
+            // machine images put local directory trees under
+            // /ngi-persist/indra, which is where we observe the problem. So
+            // now, keep calling abbreviateFile() until it returns its
+            // argument unchanged, THEN check.
+        } while (abbreviateFile != prev);
 
 		ensure_ends_with("file name abbreviation",
 			abbreviateFile,
diff --git a/indra/llcommon/tests/llexception_test.cpp b/indra/llcommon/tests/llexception_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6bee1943c26a870517408eafdc7fdbdd8d804123
--- /dev/null
+++ b/indra/llcommon/tests/llexception_test.cpp
@@ -0,0 +1,308 @@
+/**
+ * @file   llexception_test.cpp
+ * @author Nat Goodspeed
+ * @date   2016-08-12
+ * @brief  Tests for throwing exceptions.
+ *
+ * This isn't a regression test: it doesn't need to be run every build, which
+ * is why the corresponding line in llcommon/CMakeLists.txt is commented out.
+ * Rather it's a head-to-head test of what kind of exception information we
+ * can collect from various combinations of exception base classes, type of
+ * throw verb and sequences of catch clauses.
+ *
+ * This "test" makes no ensure() calls: its output goes to stdout for human
+ * examination.
+ *
+ * As of 2016-08-12 with Boost 1.57, we come to the following conclusions.
+ * These should probably be re-examined from time to time as we update Boost.
+ *
+ * - It is indisputably beneficial to use BOOST_THROW_EXCEPTION() rather than
+ *   plain throw. The macro annotates the exception object with the filename,
+ *   line number and function name from which the exception was thrown.
+ *
+ * - That being the case, deriving only from boost::exception isn't an option.
+ *   Every exception object passed to BOOST_THROW_EXCEPTION() must be derived
+ *   directly or indirectly from std::exception. The only question is whether
+ *   to also derive from boost::exception. We decided to derive LLException
+ *   from both, as it makes message output slightly cleaner, but this is a
+ *   trivial reason: if a strong reason emerges to prefer single inheritance,
+ *   dropping the boost::exception base class shouldn't be a problem.
+ *
+ * - (As you will have guessed, ridiculous things like a char* or int or a
+ *   class derived from neither boost::exception nor std::exception can only
+ *   be caught by that specific type or (...), and
+ *   boost::current_exception_diagnostic_information() simply throws up its
+ *   hands and confesses utter ignorance. Stay away from such nonsense.)
+ *
+ * - But if you derive from std::exception, to nat's surprise,
+ *   boost::current_exception_diagnostic_information() gives as much
+ *   information about exceptions in a catch (...) clause as you can get from
+ *   a specific catch (const std::exception&) clause, notably the concrete
+ *   exception class and the what() string. So instead of a sequence like
+ *
+ *   try { ... }
+ *   catch (const boost::exception& e) { ... boost-flavored logging ... }
+ *   catch (const std::exception& e)   { ... std::exception logging ... }
+ *   catch (...)                       { ... generic logging ... }
+ *
+ *   we should be able to get away with only a catch (...) clause that logs
+ *   boost::current_exception_diagnostic_information().
+ *
+ * - Going further: boost::current_exception_diagnostic_information() provides
+ *   just as much information even within a std::set_terminate() handler. So
+ *   it might not even be strictly necessary to include a catch (...) clause
+ *   since the viewer does use std::set_terminate().
+ *
+ * - (We might consider adding a catch (int) clause because Kakadu internally
+ *   throws ints, and who knows if one of those might leak out. If it does,
+ *   boost::current_exception_diagnostic_information() can do nothing with it.
+ *   A catch (int) clause could at least log the value and rethrow.)
+ *
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llexception.h"
+// STL headers
+// std headers
+#include <typeinfo>
+// external library headers
+#include <boost/throw_exception.hpp>
+// other Linden headers
+#include "../test/lltut.h"
+
+// helper for display output
+// usage: std::cout << center(some string value, fill char, width) << std::endl;
+// (assumes it's the only thing on that particular line)
+struct center
+{
+    center(const std::string& label, char fill, std::size_t width):
+        mLabel(label),
+        mFill(fill),
+        mWidth(width)
+    {}
+
+    // Use friend declaration not because we need to grant access, but because
+    // it lets us declare a free operator like a member function.
+    friend std::ostream& operator<<(std::ostream& out, const center& ctr)
+    {
+        std::size_t padded = ctr.mLabel.length() + 2;
+        std::size_t left  = (ctr.mWidth - padded) / 2;
+        std::size_t right = ctr.mWidth - left - padded;
+        return out << std::string(left, ctr.mFill) << ' ' << ctr.mLabel << ' '
+                   << std::string(right, ctr.mFill);
+    }
+
+    std::string mLabel;
+    char mFill;
+    std::size_t mWidth;
+};
+
+/*****************************************************************************
+*   Four kinds of exceptions: derived from boost::exception, from
+*   std::exception, from both, from neither
+*****************************************************************************/
+// Interestingly, we can't use this variant with BOOST_THROW_EXCEPTION()
+// (which we want) -- we reach a failure topped by this comment:
+//  //All boost exceptions are required to derive from std::exception,
+//  //to ensure compatibility with BOOST_NO_EXCEPTIONS.
+struct FromBoost: public boost::exception
+{
+    FromBoost(const std::string& what): mWhat(what) {}
+    ~FromBoost() throw() {}
+    std::string what() const { return mWhat; }
+    std::string mWhat;
+};
+
+struct FromStd: public std::runtime_error
+{
+    FromStd(const std::string& what): std::runtime_error(what) {}
+};
+
+struct FromBoth: public boost::exception, public std::runtime_error
+{
+    FromBoth(const std::string& what): std::runtime_error(what) {}
+};
+
+// Same deal with FromNeither: can't use with BOOST_THROW_EXCEPTION().
+struct FromNeither
+{
+    FromNeither(const std::string& what): mWhat(what) {}
+    std::string what() const { return mWhat; }
+    std::string mWhat;
+};
+
+/*****************************************************************************
+*   Two kinds of throws: plain throw and BOOST_THROW_EXCEPTION()
+*****************************************************************************/
+template <typename EXC>
+void plain_throw(const std::string& what)
+{
+    throw EXC(what);
+}
+
+template <typename EXC>
+void boost_throw(const std::string& what)
+{
+    BOOST_THROW_EXCEPTION(EXC(what));
+}
+
+// Okay, for completeness, functions that throw non-class values. We wouldn't
+// even deign to consider these if we hadn't found examples in our own source
+// code! (Note that Kakadu's internal exception support is still based on
+// throwing ints.)
+void throw_char_ptr(const std::string& what)
+{
+    throw what.c_str(); // umm...
+}
+
+void throw_int(const std::string& what)
+{
+    throw int(what.length());
+}
+
+/*****************************************************************************
+*   Three sequences of catch clauses:
+*   boost::exception then ...,
+*   std::exception then ...,
+*   or just ...
+*****************************************************************************/
+void catch_boost_dotdotdot(void (*thrower)(const std::string&), const std::string& what)
+{
+    try
+    {
+        thrower(what);
+    }
+    catch (const boost::exception& e)
+    {
+        std::cout << "catch (const boost::exception& e)" << std::endl;
+        std::cout << "e is " << typeid(e).name() << std::endl;
+        std::cout << "boost::diagnostic_information(e):\n'"
+                  << boost::diagnostic_information(e) << "'" << std::endl;
+        // no way to report e.what()
+    }
+    catch (...)
+    {
+        std::cout << "catch (...)" << std::endl;
+        std::cout << "boost::current_exception_diagnostic_information():\n'"
+                  << boost::current_exception_diagnostic_information() << "'"
+                  << std::endl;
+    }
+}
+
+void catch_std_dotdotdot(void (*thrower)(const std::string&), const std::string& what)
+{
+    try
+    {
+        thrower(what);
+    }
+    catch (const std::exception& e)
+    {
+        std::cout << "catch (const std::exception& e)" << std::endl;
+        std::cout << "e is " << typeid(e).name() << std::endl;
+        std::cout << "boost::diagnostic_information(e):\n'"
+                  << boost::diagnostic_information(e) << "'" << std::endl;
+        std::cout << "e.what: '"
+                  << e.what() << "'" << std::endl;
+    }
+    catch (...)
+    {
+        std::cout << "catch (...)" << std::endl;
+        std::cout << "boost::current_exception_diagnostic_information():\n'"
+                  << boost::current_exception_diagnostic_information() << "'"
+                  << std::endl;
+    }
+}
+
+void catch_dotdotdot(void (*thrower)(const std::string&), const std::string& what)
+{
+    try
+    {
+        thrower(what);
+    }
+    catch (...)
+    {
+        std::cout << "catch (...)" << std::endl;
+        std::cout << "boost::current_exception_diagnostic_information():\n'"
+                  << boost::current_exception_diagnostic_information() << "'"
+                  << std::endl;
+    }
+}
+
+/*****************************************************************************
+*   Try a particular kind of throw against each of three catch sequences
+*****************************************************************************/
+void catch_several(void (*thrower)(const std::string&), const std::string& what)
+{
+    std::cout << std::string(20, '-') << "catch_boost_dotdotdot(" << what << ")" << std::endl;
+    catch_boost_dotdotdot(thrower, "catch_boost_dotdotdot(" + what + ")");
+
+    std::cout << std::string(20, '-') << "catch_std_dotdotdot(" << what << ")" << std::endl;
+    catch_std_dotdotdot(thrower, "catch_std_dotdotdot(" + what + ")");
+
+    std::cout << std::string(20, '-') << "catch_dotdotdot(" << what << ")" << std::endl;
+    catch_dotdotdot(thrower, "catch_dotdotdot(" + what + ")");
+}
+
+/*****************************************************************************
+*   For a particular kind of exception, try both kinds of throw against all
+*   three catch sequences
+*****************************************************************************/
+template <typename EXC>
+void catch_both_several(const std::string& what)
+{
+    std::cout << std::string(20, '*') << "plain_throw<" << what << ">" << std::endl;
+    catch_several(plain_throw<EXC>, "plain_throw<" + what + ">");
+
+    std::cout << std::string(20, '*') << "boost_throw<" << what << ">" << std::endl;
+    catch_several(boost_throw<EXC>, "boost_throw<" + what + ">");
+}
+
+/*****************************************************************************
+*   TUT
+*****************************************************************************/
+namespace tut
+{
+    struct llexception_data
+    {
+    };
+    typedef test_group<llexception_data> llexception_group;
+    typedef llexception_group::object object;
+    llexception_group llexceptiongrp("llexception");
+
+    template<> template<>
+    void object::test<1>()
+    {
+        set_test_name("throwing exceptions");
+
+        // For each kind of exception, try both kinds of throw against all
+        // three catch sequences
+        std::size_t margin = 72;
+        std::cout << center("FromStd", '=', margin) << std::endl;
+        catch_both_several<FromStd>("FromStd");
+
+        std::cout << center("FromBoth", '=', margin) << std::endl;
+        catch_both_several<FromBoth>("FromBoth");
+
+        std::cout << center("FromBoost", '=', margin) << std::endl;
+        // can't throw with BOOST_THROW_EXCEPTION(), just use catch_several()
+        catch_several(plain_throw<FromBoost>, "plain_throw<FromBoost>");
+
+        std::cout << center("FromNeither", '=', margin) << std::endl;
+        // can't throw this with BOOST_THROW_EXCEPTION() either
+        catch_several(plain_throw<FromNeither>, "plain_throw<FromNeither>");
+
+        std::cout << center("const char*", '=', margin) << std::endl;
+        // We don't expect BOOST_THROW_EXCEPTION() to throw anything so daft
+        // as a const char* or an int, so don't bother with
+        // catch_both_several() -- just catch_several().
+        catch_several(throw_char_ptr, "throw_char_ptr");
+
+        std::cout << center("int", '=', margin) << std::endl;
+        catch_several(throw_int, "throw_int");
+    }
+} // namespace tut
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index 785197ba111fda1139b6cfbda6494faee726ffd6..9a4bbbd630d002a6effa410c39e737f0dfc23d89 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -35,13 +35,13 @@
 
 #include <tut/tut.hpp>
 #include "llerrorcontrol.h"
+#include "llexception.h"
 #include "stringize.h"
 #include <boost/bind.hpp>
 #include <boost/noncopyable.hpp>
 #include <boost/shared_ptr.hpp>
 #include <list>
 #include <string>
-#include <stdexcept>
 
 // statically reference the function in test.cpp... it's short, we could
 // replicate, but better to reuse
@@ -67,9 +67,9 @@ struct WrapLLErrs
         LLError::restoreSettings(mPriorErrorSettings);
     }
 
-    struct FatalException: public std::runtime_error
+    struct FatalException: public LLException
     {
-        FatalException(const std::string& what): std::runtime_error(what) {}
+        FatalException(const std::string& what): LLException(what) {}
     };
 
     void operator()(const std::string& message)
@@ -78,7 +78,7 @@ struct WrapLLErrs
         error = message;
         // Also throw an appropriate exception since calling code is likely to
         // assume that control won't continue beyond LL_ERRS.
-        throw FatalException(message);
+        LLTHROW(FatalException(message));
     }
 
     std::string error;
diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h
index 8b4afae24ab4309744897afffdd4816f3762cb45..56e26c23ba3f49ae4264d1c1dbb9f075913bd813 100644
--- a/indra/llcrashlogger/llcrashlogger.h
+++ b/indra/llcrashlogger/llcrashlogger.h
@@ -57,7 +57,7 @@ class LLCrashLogger : public LLApp
 	LLSD constructPostData();
 	virtual void updateApplication(const std::string& message = LLStringUtil::null);
 	virtual bool init();
-	virtual bool mainLoop() = 0;
+	virtual bool frame() = 0;
 	virtual bool cleanup() = 0;
 	void commonCleanup();
 	void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index feb97ec2ab2c5649e09bfbe4f9c4e8c7733e8a44..f71607096c8e7c51d6f6a6622c8b72c42644edec 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -1426,7 +1426,12 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
 
 bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
 {
-	llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) );
+    S32 components = getComponents();
+	if (! ((1 == components) || (3 == components) || (4 == components) ))
+    {
+        LL_WARNS() << "Invalid getComponents value (" << components << ")" << LL_ENDL;
+        return false;
+    }
 
 	if (isBufferInvalid())
 	{
@@ -1446,67 +1451,53 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
 
 	if (scale_image_data)
 	{
-		/*
-		S32 temp_data_size = old_width * new_height * getComponents();
-		llassert_always(temp_data_size > 0);
-		std::vector<U8> temp_buffer(temp_data_size);
-
-		// Vertical
-		for( S32 col = 0; col < old_width; col++ )
-		{
-			copyLineScaled( getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), old_height, new_height, old_width, old_width );
-		}
-
-		deleteData();
+		S32 new_data_size = new_width * new_height * components;
 
-		U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
+		if (new_data_size > 0)
+        {
+            U8 *new_data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), new_data_size); 
+            if(NULL == new_data) 
+            {
+                return false; 
+            }
 
-		// Horizontal
-		for( S32 row = 0; row < new_height; row++ )
-		{
-			copyLineScaled( &temp_buffer[0] + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
-		}
-		*/
-
-		S32 new_data_size = new_width * new_height * getComponents();
-		llassert_always(new_data_size > 0);
-
-		U8 *new_data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), new_data_size); 
-		if(NULL == new_data) 
-		{
-			return false; 
+            bilinear_scale(getData(), old_width, old_height, components, old_width*components, new_data, new_width, new_height, components, new_width*components);
+            setDataAndSize(new_data, new_width, new_height, components); 
 		}
-
-		bilinear_scale(getData(), old_width, old_height, getComponents(), old_width*getComponents(), new_data, new_width, new_height, getComponents(), new_width*getComponents());
-		setDataAndSize(new_data, new_width, new_height, getComponents()); 
 	}
 	else
 	{
 		// copy	out	existing image data
-		S32	temp_data_size = old_width * old_height	* getComponents();
+		S32	temp_data_size = old_width * old_height	* components;
 		std::vector<U8> temp_buffer(temp_data_size);
 		memcpy(&temp_buffer[0],	getData(), temp_data_size);
 
 		// allocate	new	image data,	will delete	old	data
-		U8*	new_buffer = allocateDataSize(new_width, new_height, getComponents());
-
-		for( S32 row = 0; row <	new_height;	row++ )
-		{
-			if (row	< old_height)
-			{
-				memcpy(new_buffer +	(new_width * row * getComponents()), &temp_buffer[0] + (old_width *	row	* getComponents()),	getComponents()	* llmin(old_width, new_width));
-				if (old_width <	new_width)
-				{
-					// pad out rest	of row with	black
-					memset(new_buffer +	(getComponents() * ((new_width * row) +	old_width)), 0,	getComponents()	* (new_width - old_width));
-				}
-			}
-			else
-			{
-				// pad remaining rows with black
-				memset(new_buffer +	(new_width * row * getComponents()), 0,	new_width *	getComponents());
-			}
-		}
+		U8*	new_buffer = allocateDataSize(new_width, new_height, components);
+
+        if (!new_buffer)
+        {
+            LL_WARNS() << "Failed to allocate new image data buffer" << LL_ENDL;
+            return false;
+        }
+        
+        for( S32 row = 0; row <	new_height;	row++ )
+        {
+            if (row	< old_height)
+            {
+                memcpy(new_buffer +	(new_width * row * components), &temp_buffer[0] + (old_width *	row	* components),	components * llmin(old_width, new_width));
+                if (old_width <	new_width)
+                {
+                    // pad out rest	of row with	black
+                    memset(new_buffer +	(components * ((new_width * row) +	old_width)), 0,	components * (new_width - old_width));
+                }
+            }
+            else
+            {
+                // pad remaining rows with black
+                memset(new_buffer +	(new_width * row * components), 0,	new_width *	components);
+            }
+        }
 	}
 
 	return true ;
diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp
index aad139f57087c2dc818a67f57ee08d1bf6840522..da289ea889f796f15a3ba5dcd082b1f0dd33acdb 100644
--- a/indra/llimage/llpngwrapper.cpp
+++ b/indra/llimage/llpngwrapper.cpp
@@ -31,6 +31,16 @@
 #include "llimage.h"
 #include "llpngwrapper.h"
 
+#include "llexception.h"
+
+namespace {
+// Failure to load an image shouldn't crash the whole viewer.
+struct PngError: public LLContinueError
+{
+    PngError(png_const_charp msg): LLContinueError(msg) {}
+};
+} // anonymous namespace
+
 // ---------------------------------------------------------------------------
 // LLPngWrapper
 // ---------------------------------------------------------------------------
@@ -75,11 +85,10 @@ BOOL LLPngWrapper::isValidPng(U8* src)
 }
 
 // Called by the libpng library when a fatal encoding or decoding error
-// occurs.  We simply throw the error message and let our try/catch
-// block clean up.
+// occurs. We throw PngError and let our try/catch block clean up.
 void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg)
 {
-	throw msg;
+	LLTHROW(PngError(msg));
 }
 
 // Called by the libpng library when reading (decoding) the PNG file. We
@@ -129,7 +138,7 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
 			this, &errorHandler, NULL);
 		if (mReadPngPtr == NULL)
 		{
-			throw "Problem creating png read structure";
+			LLTHROW(PngError("Problem creating png read structure"));
 		}
 
 		// Allocate/initialize the memory for image information.
@@ -187,9 +196,9 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
 
 		mFinalSize = dataPtr.mOffset;
 	}
-	catch (png_const_charp msg)
+	catch (const PngError& msg)
 	{
-		mErrorMessage = msg;
+		mErrorMessage = msg.what();
 		releaseResources();
 		return (FALSE);
 	}
@@ -288,14 +297,14 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest)
 
 		if (mColorType == -1)
 		{
-			throw "Unsupported image: unexpected number of channels";
+			LLTHROW(PngError("Unsupported image: unexpected number of channels"));
 		}
 
 		mWritePngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
 			NULL, &errorHandler, NULL);
 		if (!mWritePngPtr)
 		{
-			throw "Problem creating png write structure";
+			LLTHROW(PngError("Problem creating png write structure"));
 		}
 
 		mWriteInfoPtr = png_create_info_struct(mWritePngPtr);
@@ -339,9 +348,9 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest)
 		png_write_end(mWritePngPtr, mWriteInfoPtr);
 		mFinalSize = dataPtr.mOffset;
 	}
-	catch (png_const_charp msg)
+	catch (const PngError& msg)
 	{
-		mErrorMessage = msg;
+		mErrorMessage = msg.what();
 		releaseResources();
 		return (FALSE);
 	}
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 025c77b85e8fc269107e2a8070975d99b15deaf8..aa405362e8c0fc22c8cf04bded5aa12d89d86983 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -1,4 +1,4 @@
- /** 
+/** 
  * @file llimagej2ckdu.cpp
  * @brief This is an implementation of JPEG2000 encode/decode using Kakadu
  *
@@ -35,16 +35,51 @@
 
 #include "kdu_block_coding.h"
 
-#include <stdexcept>
-#include <iostream>
+#include "llexception.h"
+#include <boost/exception/diagnostic_information.hpp>
+#include <sstream>
+#include <iomanip>
 
 namespace {
-// exception used to keep KDU from terminating entire program -- see comments
-// in LLKDUMessageError::flush()
-struct KDUError: public std::runtime_error
+// Failure to load an image shouldn't crash the whole viewer.
+struct KDUError: public LLContinueError
 {
-	KDUError(const std::string& msg): std::runtime_error(msg) {}
+    KDUError(const std::string& msg): LLContinueError(msg) {}
 };
+
+// KDU defines int error codes as hex values, so we should log them in hex
+// so we can grep KDU headers for the hex. However those hex values
+// generally "happen" to encode big-endian multibyte character sequences,
+// e.g. KDU_ERROR_EXCEPTION is 0x6b647545: 'kduE'
+// But beware because KDU_NULL_EXCEPTION is simply 0 -- which doesn't
+// preclude somebody from throwing it.
+std::string report_kdu_exception(kdu_exception mb)
+{
+    std::ostringstream out;
+    // always report mb in hex
+    out << "kdu_exception " << std::hex << mb;
+
+    // Also display as many chars as are encoded in the kdu_exception
+    // value. Make a char array; reserve 1 extra byte for nul terminator.
+    char bytes[sizeof(kdu_exception) + 1];
+    // Back up through 'bytes'
+    char *bptr = bytes + sizeof(bytes);
+    *(--bptr) = '\0';
+    while (mb)
+    {
+        // store low-order byte of mb in next-left char
+        *(--bptr) = char(mb & 0xFF);
+        // then shift mb right by one byte
+        mb >>= 8;
+    }
+    // did that produce any characters?
+    if (*bptr)
+    {
+        out << " (" << bptr << ')';
+    }
+
+    return out.str();
+}
 } // anonymous namespace
 
 // stream kdu_dims to std::ostream
@@ -195,7 +230,7 @@ struct LLKDUMessageError : public LLKDUMessage
 		// shutdown will NOT engage the behavior described above.
 		if (end_of_message) 
 		{
-	 		throw KDUError("LLKDUMessageError::flush()");
+			LLTHROW(KDUError("LLKDUMessageError::flush()"));
 		}
 	}
 };
@@ -309,10 +344,10 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
 		{
 			// This method is only called from methods that catch KDUError.
 			// We want to fail the image load, not crash the viewer.
-			throw KDUError(STRINGIZE("Component " << idx << " dimensions "
+			LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
 									 << other_dims
 									 << " do not match component 0 dimensions "
-									 << dims << "!"));
+									 << dims << "!")));
 		}
 	}
 
@@ -439,9 +474,19 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
 		base.setLastError(msg.what());
 		return false;
 	}
+	catch (kdu_exception kdu_value)
+	{
+		// KDU internally throws kdu_exception. It's possible that such an
+		// exception might leak out into our code. Catch kdu_exception
+		// specially because boost::current_exception_diagnostic_information()
+		// could do nothing with it.
+		base.setLastError(report_kdu_exception(kdu_value));
+		return false;
+	}
 	catch (...)
 	{
-		base.setLastError("Unknown J2C error");
+		base.setLastError("Unknown J2C error: " +
+						  boost::current_exception_diagnostic_information());
 		return false;
 	}
 
@@ -537,9 +582,21 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
 				cleanupCodeStream();
 				return true; // done
 			}
+			catch (kdu_exception kdu_value)
+			{
+				// KDU internally throws kdu_exception. It's possible that such an
+				// exception might leak out into our code. Catch kdu_exception
+				// specially because boost::current_exception_diagnostic_information()
+				// could do nothing with it.
+				base.setLastError(report_kdu_exception(kdu_value));
+				base.decodeFailed();
+				cleanupCodeStream();
+				return true; // done
+			}
 			catch (...)
 			{
-				base.setLastError( "Unknown J2C error" );
+				base.setLastError("Unknown J2C error: " +
+								  boost::current_exception_diagnostic_information());
 				base.decodeFailed();
 				cleanupCodeStream();
 				return true; // done
@@ -728,9 +785,19 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
 		base.setLastError(msg.what());
 		return false;
 	}
+	catch (kdu_exception kdu_value)
+	{
+		// KDU internally throws kdu_exception. It's possible that such an
+		// exception might leak out into our code. Catch kdu_exception
+		// specially because boost::current_exception_diagnostic_information()
+		// could do nothing with it.
+		base.setLastError(report_kdu_exception(kdu_value));
+		return false;
+	}
 	catch( ... )
 	{
-		base.setLastError( "Unknown J2C error" );
+		base.setLastError("Unknown J2C error: " +
+						  boost::current_exception_diagnostic_information());
 		return false;
 	}
 
@@ -752,9 +819,19 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
 		base.setLastError(msg.what());
 		return false;
 	}
+	catch (kdu_exception kdu_value)
+	{
+		// KDU internally throws kdu_exception. It's possible that such an
+		// exception might leak out into our code. Catch kdu_exception
+		// specially because boost::current_exception_diagnostic_information()
+		// could do nothing with it.
+		base.setLastError(report_kdu_exception(kdu_value));
+		return false;
+	}
 	catch (...)
 	{
-		base.setLastError( "Unknown J2C error" );
+		base.setLastError("Unknown J2C error: " +
+						  boost::current_exception_diagnostic_information());
 		return false;
 	}
 }
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 1ca5f58ae2742f568163091757ecd046d49fba0f..004db546b701191145d178c48e46c4b462786737 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -43,6 +43,8 @@
 #include "llcoros.h"
 #include "lleventcoro.h"
 #include "llcorehttputil.h"
+#include "llexception.h"
+#include "stringize.h"
 
 #include <map>
 #include <set>
@@ -231,13 +233,12 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU
         LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults);
 
     }
-    catch (std::exception e)
-    {
-        LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
-    }
     catch (...)
     {
-        LL_WARNS() << "Caught unknown exception." << LL_ENDL;
+        LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName()
+                                          << "('" << url << "', " << agentIds.size()
+                                          << " Agent Ids)"));
+        throw;
     }
 }
 
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
index d4c0788b7d5ef272abb0e6c1e4c51e9988d6c7dd..74cdff2b0087d6480d6ead893d3328adae176286 100644
--- a/indra/llmessage/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -27,6 +27,8 @@
 
 #include "linden_common.h" 
 #include "llcoproceduremanager.h"
+#include "llexception.h"
+#include "stringize.h"
 #include <boost/assign.hpp>
 
 //=========================================================================
@@ -388,14 +390,14 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap
             {
                 coproc->mProc(httpAdapter, coproc->mId);
             }
-            catch (std::exception &e)
-            {
-                LL_WARNS() << "Coprocedure(" << coproc->mName << ") id=" << coproc->mId.asString() <<
-                    " threw an exception! Message=\"" << e.what() << "\"" << LL_ENDL;
-            }
             catch (...)
             {
-                LL_WARNS() << "A non std::exception was thrown from " << coproc->mName << " with id=" << coproc->mId << "." << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+                LOG_UNHANDLED_EXCEPTION(STRINGIZE("Coprocedure('" << coproc->mName
+                                                  << "', id=" << coproc->mId.asString()
+                                                  << ") in pool '" << mPoolName << "'"));
+                // must NOT omit this or we deplete the pool
+                mActiveCoprocs.erase(itActive);
+                throw;
             }
 
             LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL;
diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp
index f235965879cf60118130839b7ef68885e95ca6bb..04b34a296c13c4961498a4f58f6dccdf014689f2 100644
--- a/indra/llmessage/llhttpnode.cpp
+++ b/indra/llmessage/llhttpnode.cpp
@@ -31,6 +31,7 @@
 
 #include "llstl.h"
 #include "llhttpconstants.h"
+#include "llexception.h"
 
 const std::string CONTEXT_HEADERS("headers");
 const std::string CONTEXT_PATH("path");
@@ -92,27 +93,28 @@ LLHTTPNode::~LLHTTPNode()
 
 
 namespace {
-	class NotImplemented
+	struct NotImplemented: public LLException
 	{
+		NotImplemented(): LLException("LLHTTPNode::NotImplemented") {}
 	};
 }
 
 // virtual
 LLSD LLHTTPNode::simpleGet() const
 {
-	throw NotImplemented();
+	LLTHROW(NotImplemented());
 }
 
 // virtual
 LLSD LLHTTPNode::simplePut(const LLSD& input) const
 {
-	throw NotImplemented();
+	LLTHROW(NotImplemented());
 }
 
 // virtual
 LLSD LLHTTPNode::simplePost(const LLSD& input) const
 {
-	throw NotImplemented();
+	LLTHROW(NotImplemented());
 }
 
 
@@ -172,7 +174,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons
 // virtual
 LLSD LLHTTPNode::simpleDel(const LLSD&) const
 {
-	throw NotImplemented();
+	LLTHROW(NotImplemented());
 }
 
 // virtual
diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h
index 0d149b5258deae37fe033a325f6b161f3112319f..7c8f27bbd2f1ae266190a413fec9af3e7657c5d2 100644
--- a/indra/llmessage/tests/commtest.h
+++ b/indra/llmessage/tests/commtest.h
@@ -33,15 +33,15 @@
 #include "llevents.h"
 #include "llsd.h"
 #include "llhost.h"
+#include "llexception.h"
 #include "stringize.h"
 #include <map>
 #include <string>
-#include <stdexcept>
 #include <boost/lexical_cast.hpp>
 
-struct CommtestError: public std::runtime_error
+struct CommtestError: public LLException
 {
-    CommtestError(const std::string& what): std::runtime_error(what) {}
+    CommtestError(const std::string& what): LLException(what) {}
 };
 
 static bool query_verbose()
@@ -68,7 +68,7 @@ static int query_port(const std::string& var)
     const char* cport = getenv(var.c_str());
     if (! cport)
     {
-        throw CommtestError(STRINGIZE("missing environment variable" << var));
+        LLTHROW(CommtestError(STRINGIZE("missing environment variable" << var)));
     }
     // This will throw, too, if the value of PORT isn't numeric.
     int port(boost::lexical_cast<int>(cport));
diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h
index 2aff90ca1ef8657f0c56cced2cc9a33c02f98041..5eb739393febf14f076be528964880636872fe5c 100644
--- a/indra/llmessage/tests/networkio.h
+++ b/indra/llmessage/tests/networkio.h
@@ -34,6 +34,7 @@
 #include "llares.h"
 #include "llpumpio.h"
 #include "llhttpclient.h"
+#include "llexception.h"
 
 /*****************************************************************************
 *   NetworkIO
@@ -51,7 +52,7 @@ class NetworkIO: public LLSingleton<NetworkIO>
         ll_init_apr();
         if (! gAPRPoolp)
         {
-            throw std::runtime_error("Can't initialize APR");
+            LLTHROW(LLException("Can't initialize APR"));
         }
 
         // Create IO Pump to use for HTTP Requests.
@@ -59,7 +60,7 @@ class NetworkIO: public LLSingleton<NetworkIO>
         LLHTTPClient::setPump(*mServicePump);
         if (ll_init_ares() == NULL || !gAres->isInitialized())
         {
-            throw std::runtime_error("Can't start DNS resolver");
+            LLTHROW(LLException("Can't start DNS resolver"));
         }
 
         // You can interrupt pump() without waiting the full timeout duration
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 3d173d04595366dae7bf1db1479be02a23eb7a4a..d672650658599c1ebe175f06b00d65757a3b2f3b 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -116,7 +116,7 @@ void LLPluginClassMedia::reset()
 	mMediaHeight = 0;
 	mDirtyRect = LLRect::null;
 	mAutoScaleMedia = false;
-	mRequestedVolume = 1.0f;
+	mRequestedVolume = 0.0f;
 	mPriority = PRIORITY_NORMAL;
 	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
 	mAllowDownsample = false;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index b30bc1aed65c0ac9d0e84096342d246bf93ebd91..58c1186a3e7c9e11a28549b11208af177a06e64c 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -349,8 +349,8 @@ void LLGLSLShader::unloadInternal()
         for (GLsizei i = 0; i < count; i++)
         {
             glDetachObjectARB(mProgramObject, obj[i]);
-            glDeleteObjectARB(obj[i]);
-        }
+                glDeleteObjectARB(obj[i]);
+            }
 
         glDeleteObjectARB(mProgramObject);
 
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index b297223c2e92280f598814acaf5ae0a278c066b8..55f079117477f538bcc834e6d76f7ffb5306139e 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -520,7 +520,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string&
 		if (!filename.empty())
 		{
             LL_CONT << "From " << filename << ":\n";
-        }
+		}
         LL_CONT << log << LL_ENDL;
 	}
  }
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 62c3f401bf9c9ce29cb1655a923e7120c306b640..fd7406b653808fa04fcf282322d1a849dfa8f4df 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -812,7 +812,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
 LLView*	LLView::childFromPoint(S32 x, S32 y, bool recur)
 {
 	if (!getVisible())
-		return false;
+		return NULL;
 
 	BOOST_FOREACH(LLView* viewp, mChildList)
 	{
diff --git a/indra/llwindow/llappdelegate-objc.h b/indra/llwindow/llappdelegate-objc.h
index faa5d3abb71e2049e33d03d76fde6145fa130673..6daf1ac55b98c6f080c49deb483d34d7ff8e934d 100644
--- a/indra/llwindow/llappdelegate-objc.h
+++ b/indra/llwindow/llappdelegate-objc.h
@@ -41,7 +41,7 @@
 
 @property (retain) NSString *currentInputLanguage;
 
-- (void) mainLoop;
+- (void) oneFrame;
 - (void) showInputWindow:(bool)show withEvent:(NSEvent*)textEvent;
 - (void) languageUpdated;
 - (bool) romanScript;
diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h
index c22f3382fb3fca5dc08a3c55f527ecc4752adf31..b06cd2c184ec61488d54e024c931cac20ace1fca 100644
--- a/indra/llwindow/llwindowmacosx-objc.h
+++ b/indra/llwindow/llwindowmacosx-objc.h
@@ -69,7 +69,7 @@ typedef const NativeKeyEventData * NSKeyEventRef;
 // These are defined in llappviewermacosx.cpp.
 bool initViewer();
 void handleQuit();
-bool runMainLoop();
+bool pumpMainLoop();
 void initMainLoop();
 void cleanupViewer();
 void handleUrl(const char* url);
diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp
index 3149fad6e8732a59312f868b21ec189607960262..ec3616e26a93a173c052407a62c0e46cae31b3ea 100644
--- a/indra/mac_crash_logger/llcrashloggermac.cpp
+++ b/indra/mac_crash_logger/llcrashloggermac.cpp
@@ -64,7 +64,7 @@ void LLCrashLoggerMac::gatherPlatformSpecificFiles()
 {
 }
 
-bool LLCrashLoggerMac::mainLoop()
+bool LLCrashLoggerMac::frame()
 {
 
     if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)
diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h
index 6d8f63ecac0570c8e8000a111568c384c191bfc3..05ef8c9f53976161c8ac392a9ea8f095a64ac75d 100644
--- a/indra/mac_crash_logger/llcrashloggermac.h
+++ b/indra/mac_crash_logger/llcrashloggermac.h
@@ -37,7 +37,7 @@ class LLCrashLoggerMac : public LLCrashLogger
 	LLCrashLoggerMac(void);
 	~LLCrashLoggerMac(void);
 	virtual bool init();
-	virtual bool mainLoop();
+	virtual bool frame();
 	virtual bool cleanup();
 	virtual void gatherPlatformSpecificFiles();
 };
diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp
index 95d4e65207d8930d114cf75eecb1ac70426b18f6..54e41a1954d927894dc394d2112841e2550903d0 100644
--- a/indra/mac_crash_logger/mac_crash_logger.cpp
+++ b/indra/mac_crash_logger/mac_crash_logger.cpp
@@ -49,7 +49,7 @@ int main(int argc, char **argv)
     {
 //        return NSApplicationMain(argc, (const char **)argv);
     }
-	app.mainLoop();
+	app.frame();
 	app.cleanup();
 
 	LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;
diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt
index 24eb3947b489f074ada8bcbf5feb938527d3de4a..9055e0111a37f5b06f902fd733af87178007af57 100644
--- a/indra/media_plugins/CMakeLists.txt
+++ b/indra/media_plugins/CMakeLists.txt
@@ -4,15 +4,18 @@ add_subdirectory(base)
 
 if (LINUX)
     add_subdirectory(gstreamer010)
+    add_subdirectory(libvlc)
 endif (LINUX)
 
-if (WINDOWS OR DARWIN)
+if (DARWIN)
     add_subdirectory(quicktime)
     add_subdirectory(cef)
-endif (WINDOWS OR DARWIN)
+endif (DARWIN)
 
 if (WINDOWS)
+    add_subdirectory(cef)
     add_subdirectory(winmmshim)
+    add_subdirectory(libvlc)
 endif (WINDOWS)
 
 ### add_subdirectory(example)
diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp
index 8d9d1dd975e12b8fe7e1ee8a66d32a8863343872..28a8a5886a4ac340331edfbc48054cdaa6c95136 100644
--- a/indra/media_plugins/cef/media_plugin_cef.cpp
+++ b/indra/media_plugins/cef/media_plugin_cef.cpp
@@ -100,6 +100,12 @@ class MediaPluginCEF :
 	LLCEFLib* mLLCEFLib;
 
     VolumeCatcher mVolumeCatcher;
+
+	U8 *mPopupBuffer;
+	U32 mPopupW;
+	U32 mPopupH;
+	U32 mPopupX;
+	U32 mPopupY;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -127,12 +133,19 @@ MediaPluginBase(host_send_func, host_user_data)
 	mCookiePath = "";
 	mPickedFile = "";
 	mLLCEFLib = new LLCEFLib();
+
+	mPopupBuffer = NULL;
+	mPopupW = 0;
+	mPopupH = 0;
+	mPopupX = 0;
+	mPopupY = 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //
 MediaPluginCEF::~MediaPluginCEF()
 {
+	delete[] mPopupBuffer;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -155,20 +168,28 @@ void MediaPluginCEF::postDebugMessage(const std::string& msg)
 //
 void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup)
 {
-	if (mPixels && pixels)
+	if( is_popup )
+	{
+		delete mPopupBuffer;
+		mPopupBuffer = NULL;
+		mPopupH = 0;
+		mPopupW = 0;
+		mPopupX = 0;
+		mPopupY = 0;
+	}
+
+	if( mPixels && pixels )
 	{
 		if (is_popup)
 		{
-			for (int line = 0; line < height; ++line)
+			if( width > 0 && height> 0 )
 			{
-				int inverted_y = mHeight - y - height;
-				int src = line * width * mDepth;
-				int dst = (inverted_y + line) * mWidth * mDepth + x * mDepth;
-
-				if (dst + width * mDepth < mWidth * mHeight * mDepth)
-				{
-					memcpy(mPixels + dst, pixels + src, width * mDepth);
-				}
+				mPopupBuffer = new U8[ width * height * mDepth ];
+				memcpy( mPopupBuffer, pixels, width * height * mDepth );
+				mPopupH = height;
+				mPopupW = width;
+				mPopupX = x;
+				mPopupY = mHeight - y - height;
 			}
 		}
 		else
@@ -177,6 +198,23 @@ void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y,
 			{
 				memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
 			}
+			if( mPopupBuffer && mPopupH && mPopupW )
+			{
+				U32 bufferSize = mWidth * mHeight * mDepth;
+				U32 popupStride = mPopupW * mDepth;
+				U32 bufferStride = mWidth * mDepth;
+				int dstY = mPopupY;
+
+				int src = 0;
+				int dst = dstY  * mWidth * mDepth + mPopupX * mDepth;
+
+				for( int line = 0; dst + popupStride < bufferSize && line < mPopupH; ++line )
+				{
+					memcpy( mPixels + dst, mPopupBuffer + src, popupStride );
+					src += popupStride;
+					dst += bufferStride;
+				}
+			}
 
 		}
 		setDirty(0, 0, mWidth, mHeight);
@@ -559,6 +597,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
 				S32 x = message_in.getValueS32("x");
 				S32 y = message_in.getValueS32("y");
 
+				y = mHeight - y;
+
 				// only even send left mouse button events to LLCEFLib
 				// (partially prompted by crash in OS X CEF when sending right button events)
 				// we catch the right click in viewer and display our own context menu anyway
diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..535d29125b763a2d51c0c9c38f92b82dc8989e93
--- /dev/null
+++ b/indra/media_plugins/libvlc/CMakeLists.txt
@@ -0,0 +1,86 @@
+# -*- cmake -*-
+
+project(media_plugin_libvlc)
+
+include(00-Common)
+include(LLCommon)
+include(LLImage)
+include(LLPlugin)
+include(LLMath)
+include(LLRender)
+include(LLWindow)
+include(Linking)
+include(PluginAPI)
+include(MediaPluginBase)
+include(OpenGL)
+
+include(LibVLCPlugin)
+
+include_directories(
+    ${LLPLUGIN_INCLUDE_DIRS}
+    ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS}
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLMATH_INCLUDE_DIRS}
+    ${LLIMAGE_INCLUDE_DIRS}
+    ${LLRENDER_INCLUDE_DIRS}
+    ${LLWINDOW_INCLUDE_DIRS}
+    ${VLC_INCLUDE_DIR}
+)
+include_directories(SYSTEM
+    ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
+    )
+
+
+### media_plugin_libvlc
+
+if(NOT WORD_SIZE EQUAL 32)
+  if(WINDOWS)
+    add_definitions(/FIXED:NO)
+  else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
+    add_definitions(-fPIC)
+  endif(WINDOWS)
+endif(NOT WORD_SIZE EQUAL 32)
+
+set(media_plugin_libvlc_SOURCE_FILES
+    media_plugin_libvlc.cpp
+    )
+
+add_library(media_plugin_libvlc
+    SHARED
+    ${media_plugin_libvlc_SOURCE_FILES}
+)
+
+target_link_libraries(media_plugin_libvlc
+  ${LLPLUGIN_LIBRARIES}
+  ${MEDIA_PLUGIN_BASE_LIBRARIES}
+  ${LLCOMMON_LIBRARIES}
+  ${VLC_PLUGIN_LIBRARIES}
+  ${PLUGIN_API_WINDOWS_LIBRARIES}
+)
+
+add_dependencies(media_plugin_libvlc
+  ${LLPLUGIN_LIBRARIES}
+  ${MEDIA_PLUGIN_BASE_LIBRARIES}
+  ${LLCOMMON_LIBRARIES}
+)
+
+if (WINDOWS)
+  set_target_properties(
+    media_plugin_libvlc
+    PROPERTIES
+    LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /LTCG /NODEFAULTLIB:LIBCMT"
+    )
+endif (WINDOWS)
+
+if (DARWIN)
+  # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name
+  set_target_properties(
+    media_plugin_libvlc
+    PROPERTIES
+    PREFIX ""
+    BUILD_WITH_INSTALL_RPATH 1
+    INSTALL_NAME_DIR "@executable_path"
+    LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp"
+  )
+
+endif (DARWIN)
diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0bd323eb58d8f0754ca0aa28565ba8d2d8d0ee12
--- /dev/null
+++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
@@ -0,0 +1,618 @@
+/**
+* @file media_plugin_libvlc.cpp
+* @brief LibVLC plugin for LLMedia API plugin system
+*
+* @cond
+* $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
+*/
+
+#include "linden_common.h"
+
+#include "llgl.h"
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.h"
+
+#include "vlc/vlc.h"
+#include "vlc/libvlc_version.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginLibVLC :
+	public MediaPluginBase
+{
+public:
+	MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+	~MediaPluginLibVLC();
+
+	/*virtual*/ void receiveMessage(const char* message_string);
+
+private:
+	bool init();
+
+	void initVLC();
+	void playMedia();
+	void resetVLC();
+	void setVolume(const F64 volume);
+	void updateTitle(const char* title);
+
+	static void* lock(void* data, void** p_pixels);
+	static void unlock(void* data, void* id, void* const* raw_pixels);
+	static void display(void* data, void* id);
+
+	/*virtual*/ void setDirty(int left, int top, int right, int bottom) /* override, but that is not supported in gcc 4.6 */;
+
+	static void eventCallbacks(const libvlc_event_t* event, void* ptr);
+
+	libvlc_instance_t* mLibVLC;
+	libvlc_media_t* mLibVLCMedia;
+	libvlc_media_player_t* mLibVLCMediaPlayer;
+
+	struct mLibVLCContext
+	{
+		unsigned char* texture_pixels;
+		libvlc_media_player_t* mp;
+		MediaPluginLibVLC* parent;
+	};
+	struct mLibVLCContext mLibVLCCallbackContext;
+
+	std::string mURL;
+	F64 mCurVolume;
+
+	bool mIsLooping;
+
+	float mCurTime;
+	float mDuration;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+MediaPluginLibVLC::MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
+MediaPluginBase(host_send_func, host_user_data)
+{
+	mTextureWidth = 0;
+	mTextureHeight = 0;
+	mWidth = 0;
+	mHeight = 0;
+	mDepth = 4;
+	mPixels = 0;
+
+	mLibVLC = 0;
+	mLibVLCMedia = 0;
+	mLibVLCMediaPlayer = 0;
+
+	mCurVolume = 0.0;
+
+	mIsLooping = false;
+
+	mCurTime = 0.0;
+	mDuration = 0.0;
+
+	mURL = std::string();
+
+	setStatus(STATUS_NONE);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+MediaPluginLibVLC::~MediaPluginLibVLC()
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+void* MediaPluginLibVLC::lock(void* data, void** p_pixels)
+{
+	struct mLibVLCContext* context = (mLibVLCContext*)data;
+
+	*p_pixels = context->texture_pixels;
+
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::unlock(void* data, void* id, void* const* raw_pixels)
+{
+	// nothing to do here for the moment
+	// we *could* modify pixels here to, for example, Y flip, but this is done with
+	// a VLC video filter transform. 
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::display(void* data, void* id)
+{
+	struct mLibVLCContext* context = (mLibVLCContext*)data;
+
+	context->parent->setDirty(0, 0, context->parent->mWidth, context->parent->mHeight);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::initVLC()
+{
+	char const* vlc_argv[] =
+	{
+		"--no-xlib",
+		"--video-filter=transform{type=vflip}",  // MAINT-6578 Y flip textures in plugin vs client
+	};
+
+	int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
+	mLibVLC = libvlc_new(vlc_argc, vlc_argv);
+
+	if (!mLibVLC)
+	{
+		// for the moment, if this fails, the plugin will fail and 
+		// the media sub-system will tell the viewer something went wrong.
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::resetVLC()
+{
+	libvlc_media_player_stop(mLibVLCMediaPlayer);
+	libvlc_media_player_release(mLibVLCMediaPlayer);
+	libvlc_release(mLibVLC);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// *virtual*
+void MediaPluginLibVLC::setDirty(int left, int top, int right, int bottom)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
+
+	message.setValueS32("left", left);
+	message.setValueS32("top", top);
+	message.setValueS32("right", right);
+	message.setValueS32("bottom", bottom);
+
+	message.setValueReal("current_time", mCurTime);
+	message.setValueReal("duration", mDuration);
+	message.setValueReal("current_rate", 1.0f);
+
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
+{
+	MediaPluginLibVLC* parent = (MediaPluginLibVLC*)ptr;
+	if (parent == 0)
+	{
+		return;
+	}
+
+	switch (event->type)
+	{
+	case libvlc_MediaPlayerOpening:
+		parent->setStatus(STATUS_LOADING);
+		break;
+
+	case libvlc_MediaPlayerPlaying:
+		parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f;
+		parent->setStatus(STATUS_PLAYING);
+		break;
+
+	case libvlc_MediaPlayerPaused:
+		parent->setStatus(STATUS_PAUSED);
+		break;
+
+	case libvlc_MediaPlayerStopped:
+		parent->setStatus(STATUS_DONE);
+		break;
+
+	case libvlc_MediaPlayerEndReached:
+		parent->setStatus(STATUS_DONE);
+		break;
+
+	case libvlc_MediaPlayerEncounteredError:
+		parent->setStatus(STATUS_ERROR);
+		break;
+
+	case libvlc_MediaPlayerTimeChanged:
+		parent->mCurTime = (float)libvlc_media_player_get_time(parent->mLibVLCMediaPlayer) / 1000.0f;
+		break;
+
+	case libvlc_MediaPlayerPositionChanged:
+		break;
+
+	case libvlc_MediaPlayerLengthChanged:
+		parent->mDuration = (float)libvlc_media_get_duration(parent->mLibVLCMedia) / 1000.0f;
+		break;
+
+	case libvlc_MediaPlayerTitleChanged:
+	{
+		char* title = libvlc_media_get_meta(parent->mLibVLCMedia, libvlc_meta_Title);
+		if (title)
+		{
+			parent->updateTitle(title);
+		}
+	}
+	break;
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::playMedia()
+{
+	if (mURL.length() == 0)
+	{
+		return;
+	}
+
+	if (mLibVLCMediaPlayer)
+	{
+		// stop listening to events while we reset things
+		libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer);
+		if (em)
+		{
+			libvlc_event_detach(em, libvlc_MediaPlayerOpening, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerPlaying, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerPaused, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerStopped, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerEndReached, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, NULL);
+			libvlc_event_detach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, NULL);
+		};
+
+		libvlc_media_player_stop(mLibVLCMediaPlayer);
+		libvlc_media_player_release(mLibVLCMediaPlayer);
+
+		mLibVLCMediaPlayer = 0;
+	}
+
+	if (mLibVLCMedia)
+	{
+		libvlc_media_release(mLibVLCMedia);
+
+		mLibVLCMedia = 0;
+	}
+
+	mLibVLCMedia = libvlc_media_new_location(mLibVLC, mURL.c_str());
+	if (!mLibVLCMedia)
+	{
+		mLibVLCMediaPlayer = 0;
+		setStatus(STATUS_ERROR);
+		return;
+	}
+
+	mLibVLCMediaPlayer = libvlc_media_player_new_from_media(mLibVLCMedia);
+	if (!mLibVLCMediaPlayer)
+	{
+		setStatus(STATUS_ERROR);
+		return;
+	}
+
+	// listen to events
+	libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer);
+	if (em)
+	{
+		libvlc_event_attach(em, libvlc_MediaPlayerOpening, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerPlaying, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerPaused, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerStopped, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerEndReached, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, this);
+		libvlc_event_attach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, this);
+	}
+
+	mLibVLCCallbackContext.parent = this;
+	mLibVLCCallbackContext.texture_pixels = mPixels;
+	mLibVLCCallbackContext.mp = mLibVLCMediaPlayer;
+
+	// Send a "navigate begin" event.
+	// This is really a browser message but the QuickTime plugin did it and 
+	// the media system relies on this message to update internal state so we must send it too
+	// Note: see "navigate_complete" message below too
+	// https://jira.secondlife.com/browse/MAINT-6528
+	LLPluginMessage message_begin(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
+	message_begin.setValue("uri", mURL);
+	message_begin.setValueBoolean("history_back_available", false);
+	message_begin.setValueBoolean("history_forward_available", false);
+	sendMessage(message_begin);
+
+	// volume level gets set before VLC is initialized (thanks media system) so we have to record
+	// it in mCurVolume and set it again here so that volume levels are correctly initialized
+	setVolume(mCurVolume);
+
+	setStatus(STATUS_LOADED);
+
+	libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext);
+	libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth);
+
+	// note this relies on the "set_loop" message arriving before the "start" (play) one
+	// but that appears to always be the case
+	if (mIsLooping)
+	{
+		libvlc_media_add_option(mLibVLCMedia, "input-repeat=-1");
+	}
+
+	libvlc_media_player_play(mLibVLCMediaPlayer);
+
+	// send a "location_changed" message - this informs the media system
+	// that a new URL is the 'current' one and is used extensively.
+	// Again, this is really a browser message but we will use it here.
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
+	message.setValue("uri", mURL);
+	sendMessage(message);
+
+	// Send a "navigate complete" event.
+	// This is really a browser message but the QuickTime plugin did it and 
+	// the media system relies on this message to update internal state so we must send it too
+	// Note: see "navigate_begin" message above too
+	// https://jira.secondlife.com/browse/MAINT-6528
+	LLPluginMessage message_complete(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
+	message_complete.setValue("uri", mURL);
+	message_complete.setValueS32("result_code", 200);
+	message_complete.setValue("result_string", "OK");
+	sendMessage(message_complete);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::updateTitle(const char* title)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+	message.setValue("name", title);
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::setVolume(const F64 volume)
+{
+	mCurVolume = volume;
+
+	if (mLibVLCMediaPlayer)
+	{
+		int result = libvlc_audio_set_volume(mLibVLCMediaPlayer, (int)(volume * 100));
+		if (result != 0)
+		{
+			// volume wasn't set but not much to be done here
+		}
+	}
+	else
+	{
+		// volume change was requested but VLC wasn't ready.
+		// that's okay thought because we saved the value in mCurVolume and 
+		// the next volume change after the VLC system is initilzied  will set it
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginLibVLC::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")
+			{
+				initVLC();
+
+				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_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
+				message.setValueLLSD("versions", versions);
+
+				std::ostringstream s;
+				s << "LibVLC plugin ";
+				s << LIBVLC_VERSION_MAJOR;
+				s << ".";
+				s << LIBVLC_VERSION_MINOR;
+				s << ".";
+				s << LIBVLC_VERSION_REVISION;
+
+				message.setValue("plugin_version", s.str());
+				sendMessage(message);
+			}
+			else if (message_name == "idle")
+			{
+			}
+			else if (message_name == "cleanup")
+			{
+				resetVLC();
+			}
+			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)
+					{
+						libvlc_media_player_stop(mLibVLCMediaPlayer);
+						libvlc_media_player_release(mLibVLCMediaPlayer);
+						mLibVLCMediaPlayer = 0;
+
+						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")
+			{
+				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_RGB);
+				message.setValueU32("format", GL_BGRA_EXT);
+				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;
+
+						playMedia();
+					};
+				};
+
+				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")
+			{
+				mURL = message_in.getValue("uri");
+				playMedia();
+			}
+		}
+		else
+			if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+			{
+				if (message_name == "stop")
+				{
+					if (mLibVLCMediaPlayer)
+					{
+						libvlc_media_player_stop(mLibVLCMediaPlayer);
+					}
+				}
+				else if (message_name == "start")
+				{
+					if (mLibVLCMediaPlayer)
+					{
+						libvlc_media_player_play(mLibVLCMediaPlayer);
+					}
+				}
+				else if (message_name == "pause")
+				{
+					if (mLibVLCMediaPlayer)
+					{
+						libvlc_media_player_pause(mLibVLCMediaPlayer);
+					}
+				}
+				else if (message_name == "seek")
+				{
+					if (mDuration > 0)
+					{
+						F64 normalized_offset = message_in.getValueReal("time") / mDuration;
+						libvlc_media_player_set_position(mLibVLCMediaPlayer, normalized_offset);
+					}
+				}
+				else if (message_name == "set_loop")
+				{
+					mIsLooping = true;
+				}
+				else if (message_name == "set_volume")
+				{
+					// volume comes in 0 -> 1.0
+					F64 volume = message_in.getValueReal("volume");
+					setVolume(volume);
+				}
+			}
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool MediaPluginLibVLC::init()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+	message.setValue("name", "LibVLC Plugin");
+	sendMessage(message);
+
+	return true;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func,
+	void* host_user_data,
+	LLPluginInstance::sendMessageFunction *plugin_send_func,
+	void **plugin_user_data)
+{
+	MediaPluginLibVLC* self = new MediaPluginLibVLC(host_send_func, host_user_data);
+	*plugin_send_func = MediaPluginLibVLC::staticReceiveMessage;
+	*plugin_user_data = (void*)self;
+
+	return 0;
+}
diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/media_plugins/quicktime/CMakeLists.txt
old mode 100644
new mode 100755
index c5615145be1e05d3b1650d83b758c59b8213848a..58391007fff486a814a3ffe9fee3da1cd98e8489
--- a/indra/media_plugins/quicktime/CMakeLists.txt
+++ b/indra/media_plugins/quicktime/CMakeLists.txt
@@ -14,7 +14,6 @@ include(PluginAPI)
 include(MediaPluginBase)
 include(OpenGL)
 include(QuickTimePlugin)
-include(Boost)
 
 include_directories(
     ${LLPLUGIN_INCLUDE_DIRS}
@@ -54,12 +53,17 @@ target_link_libraries(media_plugin_quicktime
   ${PLUGIN_API_WINDOWS_LIBRARIES}
 )
 
+add_dependencies(media_plugin_quicktime
+  ${LLPLUGIN_LIBRARIES}
+  ${MEDIA_PLUGIN_BASE_LIBRARIES}
+  ${LLCOMMON_LIBRARIES}
+)
+
 if (WINDOWS)
   set_target_properties(
     media_plugin_quicktime
     PROPERTIES
-    LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT"
-    LINK_FLAGS_DEBUG "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMTD"
+    LINK_FLAGS "/MANIFEST:NO"
     )
 endif (WINDOWS)
 
diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
old mode 100644
new mode 100755
index 7ef5a0fe44ed4b14321c70ba1ff3a198b3dd51c0..b43598e4a55fa3663bacddcde57bbbbb5f6e42b8
--- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
+++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
@@ -837,9 +837,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
 			else if(message_name == "cleanup")
 			{
 				// TODO: clean up here
-                LLPluginMessage message("base", "goodbye");
-                sendMessage(message);
-            }
+			}
 			else if(message_name == "shm_added")
 			{
 				SharedSegmentInfo info;
@@ -921,6 +919,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
 				#endif
 				message.setValueS32("depth", mDepth);
 				message.setValueU32("internalformat", GL_RGB);
+
+                // note this apparently only has an effect when media is opened in 2D browser. 
+                // see https://jira.secondlife.com/browse/BUG-18252 - media flipped in 2D so flipping it back.
 				message.setValueBoolean("coords_opengl", true);	// true == use OpenGL-style coordinates, false == (0,0) is upper left.
 				message.setValueBoolean("allow_downsample", true);
 				sendMessage(message);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 9a9f6de1eb976793d7174797652ac0388a3e9479..d6d7d2c563d77d515454db1a7e61135319466635 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1757,6 +1757,7 @@ if (WINDOWS)
       SLPlugin
       media_plugin_quicktime
       media_plugin_cef
+      media_plugin_libvlc
       winmm_shim
       windows-crash-logger
       )
@@ -1972,6 +1973,7 @@ if (LINUX)
     linux-crash-logger
     SLPlugin
     media_plugin_gstreamer010
+    media_plugin_libvlc
     llcommon
     )
 
@@ -2079,7 +2081,7 @@ if (DARWIN)
       ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
     )
 
-  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_cef mac-crash-logger)
+  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_libvlc media_plugin_cef mac-crash-logger)
   add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
 
   if (ENABLE_SIGNING)
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp
index 92a5413adb519991dbe223b73d4e9b6db1174e3e..1dddf5296171cd8a73d9f64b01377f02df7f90df 100644
--- a/indra/newview/llaccountingcostmanager.cpp
+++ b/indra/newview/llaccountingcostmanager.cpp
@@ -31,6 +31,8 @@
 #include "llcoros.h"
 #include "lleventcoro.h"
 #include "llcorehttputil.h"
+#include "llexception.h"
+#include "stringize.h"
 #include <algorithm>
 #include <iterator>
 
@@ -154,13 +156,11 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
         } while (false);
 
     }
-    catch (std::exception e)
-    {
-        LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
-    }
     catch (...)
     {
-        LL_WARNS() << "Caught unknown exception." << LL_ENDL;
+        LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName()
+                                          << "('" << url << "')"));
+        throw;
     }
 
     mPendingObjectQuota.clear();
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index 49291ea5642e33d88c1a31661a11a199868d657d..c1f898284a8ab582d6f434f38c8998a637bff4e0 100644
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -30,6 +30,8 @@
 
 #include "llappviewer.h"
 #include "llviewercontrol.h"
+#include "llexception.h"
+#include "stringize.h"
 
 #include <openssl/x509_vfy.h>
 #include <openssl/ssl.h>
@@ -534,7 +536,7 @@ LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url,
 		// somewhat clumsy, as we may run into errors that do not map directly to curl
 		// error codes.  Should be refactored with login refactoring, perhaps.
 		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CACERT);
-		result.setMessage(cert_exception.getMessage());
+		result.setMessage(cert_exception.what());
 		LLPointer<LLCertificate> cert = cert_exception.getCert();
 		cert->ref(); // adding an extra ref here
 		result.setErrorData(cert.get());
@@ -544,13 +546,14 @@ LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url,
 	catch (LLCertException &cert_exception)
 	{
 		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_PEER_CERTIFICATE);
-		result.setMessage(cert_exception.getMessage());
+		result.setMessage(cert_exception.what());
 		LLPointer<LLCertificate> cert = cert_exception.getCert();
 		cert->ref(); // adding an extra ref here
 		result.setErrorData(cert.get());
 	}
 	catch (...)
 	{
+		LOG_UNHANDLED_EXCEPTION(STRINGIZE("('" << url << "')"));
 		// any other odd error, we just handle as a connect error.
 		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CONNECT_ERROR);
 	}
diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm
index 549df80fa1a501a268d77f1f948d58d26022ab50..be8877328d767e974fd5f797f25934d2366b60ca 100644
--- a/indra/newview/llappdelegate-objc.mm
+++ b/indra/newview/llappdelegate-objc.mm
@@ -48,16 +48,19 @@
 - (void) applicationDidFinishLaunching:(NSNotification *)notification
 {
 	frameTimer = nil;
-	
+
 	[self languageUpdated];
-	
+
 	if (initViewer())
 	{
-		frameTimer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(mainLoop) userInfo:nil repeats:YES];
+		// Set up recurring calls to oneFrame (repeating timer with timeout 0)
+		// until applicationShouldTerminate.
+		frameTimer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:self
+							  selector:@selector(oneFrame) userInfo:nil repeats:YES];
 	} else {
 		handleQuit();
 	}
-	
+
 	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageUpdated) name:@"NSTextInputContextKeyboardSelectionDidChangeNotification" object:nil];
 
  //   [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
@@ -96,22 +99,29 @@
 
 - (NSApplicationDelegateReply) applicationShouldTerminate:(NSApplication *)sender
 {
-	if (!runMainLoop())
+	// run one frame to assess state
+	if (!pumpMainLoop())
 	{
+		// pumpMainLoop() returns true when done, false if it wants to be
+		// called again. Since it returned false, do not yet cancel
+		// frameTimer.
 		handleQuit();
 		return NSTerminateCancel;
 	} else {
+		// pumpMainLoop() returned true: it's done. Okay, done with frameTimer.
 		[frameTimer release];
 		cleanupViewer();
 		return NSTerminateNow;
 	}
 }
 
-- (void) mainLoop
+- (void) oneFrame
 {
-	bool appExiting = runMainLoop();
+	bool appExiting = pumpMainLoop();
 	if (appExiting)
 	{
+		// Once pumpMainLoop() reports that we're done, cancel frameTimer:
+		// stop the repetitive calls.
 		[frameTimer release];
 		[[NSApplication sharedApplication] terminate:self];
 	}
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 0f96e16b212f508ece27fdc8d07005e7b29f1976..ff1d91ebe2617bf1b61cef6c69390b35ccb7d4a2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -123,15 +123,20 @@
 #include "llleap.h"
 #include "stringize.h"
 #include "llcoros.h"
+#include "llexception.h"
 #if !LL_LINUX
 #include "cef/llceflib.h"
-#endif
+#if LL_WINDOWS
+#include "vlc/libvlc_version.h"
+#endif // LL_WINDOWS
+#endif // LL_LINUX
 
 // Third party library includes
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/regex.hpp>
+#include <boost/throw_exception.hpp>
 
 #if LL_WINDOWS
 #	include <share.h> // For _SH_DENYWR in processMarkerFiles
@@ -233,7 +238,6 @@
 #include "llcoproceduremanager.h"
 #include "llviewereventrecorder.h"
 
-
 // *FIX: These extern globals should be cleaned up.
 // The globals either represent state/config/resource-storage of either 
 // this app, or another 'component' of the viewer. App globals should be 
@@ -771,9 +775,6 @@ bool LLAppViewer::init()
 	//
 	// Start of the application
 	//
-#ifdef LL_DARWIN
-	mMainLoopInitialized = false;
-#endif
 
 	// initialize LLWearableType translation bridge.
 	// Memory will be cleaned up in ::cleanupClass()
@@ -930,7 +931,7 @@ bool LLAppViewer::init()
 	
 	// Provide the text fields with callbacks for opening Urls
 	LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null));
-	LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null));
+	LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false));
 	LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null));
 	LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
 
@@ -1225,6 +1226,23 @@ bool LLAppViewer::init()
         boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1),
         boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS));
 
+	/*----------------------------------------------------------------------*/
+	// nat 2016-06-29 moved the following here from the former mainLoop().
+	mMainloopTimeout = new LLWatchdogTimeout();
+
+	// Create IO Pump to use for HTTP Requests.
+	gServicePump = new LLPumpIO(gAPRPoolp);
+
+	// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
+
+	LLVoiceChannel::initClass();
+	LLVoiceClient::getInstance()->init(gServicePump);
+	LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true);
+
+	joystick = LLViewerJoystick::getInstance();
+	joystick->setNeedsReset(true);
+	/*----------------------------------------------------------------------*/
+
 	return true;
 }
 
@@ -1299,300 +1317,266 @@ static LLTrace::BlockTimerStatHandle FTM_AGENT_UPDATE("Update");
 // externally visible timers
 LLTrace::BlockTimerStatHandle FTM_FRAME("Frame");
 
-bool LLAppViewer::mainLoop()
+bool LLAppViewer::frame()
 {
-#ifdef LL_DARWIN
-	if (!mMainLoopInitialized)
-#endif
-	{
-        LL_INFOS() << "Entering main_loop" << LL_ENDL;
-		mMainloopTimeout = new LLWatchdogTimeout();
-		
-		//-------------------------------------------
-		// Run main loop until time to quit
-		//-------------------------------------------
-		
-		// Create IO Pump to use for HTTP Requests.
-		gServicePump = new LLPumpIO(gAPRPoolp);
-		
-		// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
-		
-		LLVoiceChannel::initClass();
-		LLVoiceClient::getInstance()->init(gServicePump);
-		LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true);
-		
-		joystick = LLViewerJoystick::getInstance();
-		joystick->setNeedsReset(true);
-		
-#ifdef LL_DARWIN
-		// Ensure that this section of code never gets called again on OS X.
-		mMainLoopInitialized = true;
-#endif
-	}
-	// As we do not (yet) send data on the mainloop LLEventPump that varies
-	// with each frame, no need to instantiate a new LLSD event object each
-	// time. Obviously, if that changes, just instantiate the LLSD at the
-	// point of posting.
-	
 	LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
-	
-    LLSD newFrame;
-	
+	LLSD newFrame;
+
 	LLTimer frameTimer,idleTimer;
 	LLTimer debugTime;
-	
+
 	//LLPrivateMemoryPoolTester::getInstance()->run(false) ;
 	//LLPrivateMemoryPoolTester::getInstance()->run(true) ;
 	//LLPrivateMemoryPoolTester::destroy() ;
 
-	// Handle messages
-#ifdef LL_DARWIN
-	if (!LLApp::isExiting())
-#else
-	while (!LLApp::isExiting())
-#endif
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRAME);
-		LLTrace::BlockTimer::processTimes();
-		LLTrace::get_frame_recording().nextPeriod();
-		LLTrace::BlockTimer::logStats();
+	LL_RECORD_BLOCK_TIME(FTM_FRAME);
+	LLTrace::BlockTimer::processTimes();
+	LLTrace::get_frame_recording().nextPeriod();
+	LLTrace::BlockTimer::logStats();
 
-		LLTrace::get_thread_recorder()->pullFromChildren();
+	LLTrace::get_thread_recorder()->pullFromChildren();
 
-		//clear call stack records
-		LL_CLEAR_CALLSTACKS();
+	//clear call stack records
+	LL_CLEAR_CALLSTACKS();
 
-		//check memory availability information
-		checkMemory() ;
-		
-		try
+	//check memory availability information
+	checkMemory() ;
+
+	try
+	{
+		pingMainloopTimeout("Main:MiscNativeWindowEvents");
+
+		if (gViewerWindow)
 		{
-			pingMainloopTimeout("Main:MiscNativeWindowEvents");
+			LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
+			gViewerWindow->getWindow()->processMiscNativeEvents();
+		}
+
+		pingMainloopTimeout("Main:GatherInput");
 
-			if (gViewerWindow)
+		if (gViewerWindow)
+		{
+			LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
+			if (!restoreErrorTrap())
 			{
-				LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
-				gViewerWindow->getWindow()->processMiscNativeEvents();
+				LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
 			}
-		
-			pingMainloopTimeout("Main:GatherInput");
-			
-			if (gViewerWindow)
-			{
-				LL_RECORD_BLOCK_TIME(FTM_MESSAGES);
-				if (!restoreErrorTrap())
-				{
-					LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
-				}
 
-				gViewerWindow->getWindow()->gatherInput();
-			}
+			gViewerWindow->getWindow()->gatherInput();
+		}
 
 #if 1 && !LL_RELEASE_FOR_DOWNLOAD
-			// once per second debug info
-			if (debugTime.getElapsedTimeF32() > 1.f)
-			{
-				debugTime.reset();
-			}
-			
+		// once per second debug info
+		if (debugTime.getElapsedTimeF32() > 1.f)
+		{
+			debugTime.reset();
+		}
+		
 #endif
-			//memory leaking simulation
-			LLFloaterMemLeak* mem_leak_instance =
-				LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
-			if(mem_leak_instance)
-			{
-				mem_leak_instance->idle() ;				
-			}							
+		//memory leaking simulation
+		LLFloaterMemLeak* mem_leak_instance =
+			LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
+		if(mem_leak_instance)
+		{
+			mem_leak_instance->idle() ;				
+		}							
+
+		// canonical per-frame event
+		mainloop.post(newFrame);
 
-            // canonical per-frame event
-            mainloop.post(newFrame);
+		if (!LLApp::isExiting())
+		{
+			pingMainloopTimeout("Main:JoystickKeyboard");
+
+			// Scan keyboard for movement keys.  Command keys and typing
+			// are handled by windows callbacks.  Don't do this until we're
+			// done initializing.  JC
+			if ((gHeadlessClient || gViewerWindow->getWindow()->getVisible())
+				&& gViewerWindow->getActive()
+				&& !gViewerWindow->getWindow()->getMinimized()
+				&& LLStartUp::getStartupState() == STATE_STARTED
+				&& (gHeadlessClient || !gViewerWindow->getShowProgress())
+				&& !gFocusMgr.focusLocked())
+			{
+				joystick->scanJoystick();
+				gKeyboard->scanKeyboard();
+			}
 
-			if (!LLApp::isExiting())
+			// Update state based on messages, user input, object idle.
 			{
-				pingMainloopTimeout("Main:JoystickKeyboard");
+				pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
 				
-				// Scan keyboard for movement keys.  Command keys and typing
-				// are handled by windows callbacks.  Don't do this until we're
-				// done initializing.  JC
-				if ((gHeadlessClient || gViewerWindow->getWindow()->getVisible())
-					&& gViewerWindow->getActive()
-					&& !gViewerWindow->getWindow()->getMinimized()
-					&& LLStartUp::getStartupState() == STATE_STARTED
-					&& (gHeadlessClient || !gViewerWindow->getShowProgress())
-					&& !gFocusMgr.focusLocked())
-				{
-					joystick->scanJoystick();
-					gKeyboard->scanKeyboard();
-				}
+				LL_RECORD_BLOCK_TIME(FTM_IDLE);
+				idle();
 
-				// Update state based on messages, user input, object idle.
-				{
-					pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
-					
-					LL_RECORD_BLOCK_TIME(FTM_IDLE);
-					idle();
+				resumeMainloopTimeout();
+			}
 
-					resumeMainloopTimeout();
-				}
- 
-				if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
-				{
-					pauseMainloopTimeout();
-					saveFinalSnapshot();
-					disconnectViewer();
-					resumeMainloopTimeout();
-				}
+			if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
+			{
+				pauseMainloopTimeout();
+				saveFinalSnapshot();
+				disconnectViewer();
+				resumeMainloopTimeout();
+			}
 
-				// Render scene.
-				// *TODO: Should we run display() even during gHeadlessClient?  DK 2011-02-18
-				if (!LLApp::isExiting() && !gHeadlessClient)
-				{
-					pingMainloopTimeout("Main:Display");
-					gGLActive = TRUE;
-					display();
-					pingMainloopTimeout("Main:Snapshot");
-					LLFloaterSnapshot::update(); // take snapshots
+			// Render scene.
+			// *TODO: Should we run display() even during gHeadlessClient?  DK 2011-02-18
+			if (!LLApp::isExiting() && !gHeadlessClient)
+			{
+				pingMainloopTimeout("Main:Display");
+				gGLActive = TRUE;
+				display();
+				pingMainloopTimeout("Main:Snapshot");
+				LLFloaterSnapshot::update(); // take snapshots
 					LLFloaterOutfitSnapshot::update();
-					gGLActive = FALSE;
-				}
+				gGLActive = FALSE;
 			}
+		}
 
-			pingMainloopTimeout("Main:Sleep");
+		pingMainloopTimeout("Main:Sleep");
+
+		pauseMainloopTimeout();
+
+		// Sleep and run background threads
+		{
+			LL_RECORD_BLOCK_TIME(FTM_SLEEP);
 			
-			pauseMainloopTimeout();
+			// yield some time to the os based on command line option
+			if(mYieldTime >= 0)
+			{
+				LL_RECORD_BLOCK_TIME(FTM_YIELD);
+				ms_sleep(mYieldTime);
+			}
 
-			// Sleep and run background threads
+			// yield cooperatively when not running as foreground window
+			if (   (gViewerWindow && !gViewerWindow->getWindow()->getVisible())
+					|| !gFocusMgr.getAppHasFocus())
 			{
-				LL_RECORD_BLOCK_TIME(FTM_SLEEP);
-				
-				// yield some time to the os based on command line option
-				if(mYieldTime >= 0)
+				// Sleep if we're not rendering, or the window is minimized.
+				S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
+				// don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
+				// of equal priority on Windows
+				if (milliseconds_to_sleep > 0)
 				{
-					LL_RECORD_BLOCK_TIME(FTM_YIELD);
-					ms_sleep(mYieldTime);
+					ms_sleep(milliseconds_to_sleep);
+					// also pause worker threads during this wait period
+					LLAppViewer::getTextureCache()->pause();
+					LLAppViewer::getImageDecodeThread()->pause();
 				}
+			}
+			
+			if (mRandomizeFramerate)
+			{
+				ms_sleep(rand() % 200);
+			}
+
+			if (mPeriodicSlowFrame
+				&& (gFrameCount % 10 == 0))
+			{
+				LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL;
+				ms_sleep(500);
+			}
+
+			const F64Milliseconds max_idle_time = llmin(.005f*10.f*(F32Milliseconds)gFrameTimeSeconds, F32Milliseconds(5)); // 5 ms a second
+			idleTimer.reset();
+			S32 total_work_pending = 0;
+			S32 total_io_pending = 0;	
+			while(1)
+			{
+				S32 work_pending = 0;
+				S32 io_pending = 0;
+				F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f);
+
+				work_pending += updateTextureThreads(max_time);
 
-				// yield cooperatively when not running as foreground window
-				if (   (gViewerWindow && !gViewerWindow->getWindow()->getVisible())
-						|| !gFocusMgr.getAppHasFocus())
 				{
-					// Sleep if we're not rendering, or the window is minimized.
-					S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
-					// don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
-					// of equal priority on Windows
-					if (milliseconds_to_sleep > 0)
-					{
-						ms_sleep(milliseconds_to_sleep);
-						// also pause worker threads during this wait period
-						LLAppViewer::getTextureCache()->pause();
-						LLAppViewer::getImageDecodeThread()->pause();
-					}
+					LL_RECORD_BLOCK_TIME(FTM_VFS);
+ 					io_pending += LLVFSThread::updateClass(1);
 				}
-				
-				if (mRandomizeFramerate)
 				{
-					ms_sleep(rand() % 200);
+					LL_RECORD_BLOCK_TIME(FTM_LFS);
+ 					io_pending += LLLFSThread::updateClass(1);
 				}
 
-				if (mPeriodicSlowFrame
-					&& (gFrameCount % 10 == 0))
+				if (io_pending > 1000)
 				{
-					LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL;
-					ms_sleep(500);
+					ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
 				}
 
-				const F64Milliseconds max_idle_time = llmin(.005f*10.f*(F32Milliseconds)gFrameTimeSeconds, F32Milliseconds(5)); // 5 ms a second
-				idleTimer.reset();
-				S32 total_work_pending = 0;
-				S32 total_io_pending = 0;	
-				while(1)
-				{
-					S32 work_pending = 0;
-					S32 io_pending = 0;
-					F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f);
-
-					work_pending += updateTextureThreads(max_time);
-
-					{
-						LL_RECORD_BLOCK_TIME(FTM_VFS);
-	 					io_pending += LLVFSThread::updateClass(1);
-					}
-					{
-						LL_RECORD_BLOCK_TIME(FTM_LFS);
-	 					io_pending += LLLFSThread::updateClass(1);
-					}
-
-					if (io_pending > 1000)
-					{
-						ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
-					}
-
-					total_work_pending += work_pending ;
-					total_io_pending += io_pending ;
-					
-					if (!work_pending || idleTimer.getElapsedTimeF64() >= max_idle_time)
-					{
-						break;
-					}
-				}
-				gMeshRepo.update() ;
+				total_work_pending += work_pending ;
+				total_io_pending += io_pending ;
 				
-				if(!total_work_pending) //pause texture fetching threads if nothing to process.
+				if (!work_pending || idleTimer.getElapsedTimeF64() >= max_idle_time)
 				{
-					LLAppViewer::getTextureCache()->pause();
-					LLAppViewer::getImageDecodeThread()->pause();
-					LLAppViewer::getTextureFetch()->pause(); 
+					break;
 				}
-				if(!total_io_pending) //pause file threads if nothing to process.
-				{
-					LLVFSThread::sLocal->pause(); 
-					LLLFSThread::sLocal->pause(); 
-				}									
+			}
+			gMeshRepo.update() ;
+			
+			if(!total_work_pending) //pause texture fetching threads if nothing to process.
+			{
+				LLAppViewer::getTextureCache()->pause();
+				LLAppViewer::getImageDecodeThread()->pause();
+				LLAppViewer::getTextureFetch()->pause(); 
+			}
+			if(!total_io_pending) //pause file threads if nothing to process.
+			{
+				LLVFSThread::sLocal->pause(); 
+				LLLFSThread::sLocal->pause(); 
+			}									
 
-				//texture fetching debugger
-				if(LLTextureFetchDebugger::isEnabled())
+			//texture fetching debugger
+			if(LLTextureFetchDebugger::isEnabled())
+			{
+				LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
+					LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
+				if(tex_fetch_debugger_instance)
 				{
-					LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance =
-						LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger");
-					if(tex_fetch_debugger_instance)
-					{
-						tex_fetch_debugger_instance->idle() ;				
-					}
+					tex_fetch_debugger_instance->idle() ;				
 				}
+			}
 
-				if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
-					(frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
-				{
-					gFrameStalls++;
-				}
-				frameTimer.reset();
+			if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
+				(frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
+			{
+				gFrameStalls++;
+			}
+			frameTimer.reset();
 
-				resumeMainloopTimeout();
-	
-				pingMainloopTimeout("Main:End");
-			}	
+			resumeMainloopTimeout();
+
+			pingMainloopTimeout("Main:End");
 		}
-		catch(std::bad_alloc)
-		{			
-			LLMemory::logMemoryInfo(TRUE) ;
+	}
+	catch (const LLContinueError&)
+	{
+		LOG_UNHANDLED_EXCEPTION("");
+	}
+	catch(std::bad_alloc)
+	{
+		LLMemory::logMemoryInfo(TRUE) ;
 
-			//stop memory leaking simulation
-			LLFloaterMemLeak* mem_leak_instance =
-				LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
-			if(mem_leak_instance)
-			{
-				mem_leak_instance->stop() ;				
-				LL_WARNS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ;
-			}
-			else
-			{
-				//output possible call stacks to log file.
-				LLError::LLCallStacks::print() ;
+		//stop memory leaking simulation
+		LLFloaterMemLeak* mem_leak_instance =
+			LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
+		if(mem_leak_instance)
+		{
+			mem_leak_instance->stop() ;
+			LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL ;
+		}
+		else
+		{
+			//output possible call stacks to log file.
+			LLError::LLCallStacks::print() ;
 
-				LL_ERRS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL ;
-			}
+			LL_ERRS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL ;
 		}
 	}
+	catch (...)
+	{
+		CRASH_ON_UNHANDLED_EXCEPTION("");
+	}
 
 	if (LLApp::isExiting())
 	{
@@ -1606,7 +1590,7 @@ bool LLAppViewer::mainLoop()
 			catch(std::bad_alloc)
 			{
 				LL_WARNS() << "Bad memory allocation when saveFinalSnapshot() is called!" << LL_ENDL ;
-				
+
 				//stop memory leaking simulation
 				LLFloaterMemLeak* mem_leak_instance =
 				LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
@@ -1615,16 +1599,20 @@ bool LLAppViewer::mainLoop()
 					mem_leak_instance->stop() ;
 				}
 			}
+			catch (...)
+			{
+				CRASH_ON_UNHANDLED_EXCEPTION("saveFinalSnapshot()");
+			}
 		}
-		
+
 		delete gServicePump;
-		
+
 		destroyMainloopTimeout();
-		
+
 		LL_INFOS() << "Exiting main_loop" << LL_ENDL;
 	}
 
-	return LLApp::isExiting();
+	return ! LLApp::isRunning();
 }
 
 S32 LLAppViewer::updateTextureThreads(F32 max_time)
@@ -3348,6 +3336,19 @@ LLSD LLAppViewer::getViewerInfo() const
 	info["LLCEFLIB_VERSION"] = LLCEFLIB_VERSION;
 #else
 	info["LLCEFLIB_VERSION"] = "Undefined";
+
+#endif
+
+#if LL_WINDOWS
+	std::ostringstream ver_codec;
+	ver_codec << LIBVLC_VERSION_MAJOR;
+	ver_codec << ".";
+	ver_codec << LIBVLC_VERSION_MINOR;
+	ver_codec << ".";
+	ver_codec << LIBVLC_VERSION_REVISION;
+	info["LIBVLC_VERSION"] = ver_codec.str();
+#else
+	info["LIBVLC_VERSION"] = "Undefined";
 #endif
 
 	S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN);
@@ -5552,8 +5553,7 @@ void LLAppViewer::forceErrorInfiniteLoop()
 void LLAppViewer::forceErrorSoftwareException()
 {
    	LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL;
-    // *FIX: Any way to insure it won't be handled?
-    throw; 
+    LLTHROW(LLException("User selected Force Software Exception"));
 }
 
 void LLAppViewer::forceErrorDriverCrash()
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index b5e674bd7b3a8eb672226bc850e6a68138f1bd02..f7c1bb58b481178a071485d84a3f482b4f76512a 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -79,7 +79,7 @@ class LLAppViewer : public LLApp
 	//
 	virtual bool init();			// Override to do application initialization
 	virtual bool cleanup();			// Override to do application cleanup
-	virtual bool mainLoop(); // Override for the application main loop.  Needs to at least gracefully notice the QUITTING state and exit.
+	virtual bool frame(); // Override for application body logic
 
 	// Application control
 	void flushVFSIO(); // waits for vfs transfers to complete
@@ -283,7 +283,6 @@ class LLAppViewer : public LLApp
 	std::string mSerialNumber;
 	bool mPurgeCache;
     bool mPurgeOnExit;
-	bool mMainLoopInitialized;
 	LLViewerJoystick* joystick;
 
 	bool mSavedFinalSnapshot;
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index f5742b29cf09c414ceed55fa749e385810f489ce..6f32aab851ebb2c451490f037ce80637faf0185b 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -95,10 +95,8 @@ int main( int argc, char **argv )
 	}
 
 		// Run the application main loop
-	if(!LLApp::isQuitting()) 
-	{
-		viewer_app_ptr->mainLoop();
-	}
+	while (! viewer_app_ptr->frame()) 
+	{}
 
 	if (!LLApp::isError())
 	{
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index ca219fda59bc971fbcdba41e6731e868057e8fac..4fe1e31668b127316ebafb33292f2c4e455cdd9c 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -117,12 +117,17 @@ void handleQuit()
 	LLAppViewer::instance()->userQuit();
 }
 
-bool runMainLoop()
+// This function is called pumpMainLoop() rather than runMainLoop() because
+// it passes control to the viewer's main-loop logic for a single frame. Like
+// LLAppViewer::frame(), it returns 'true' when it's done. Until then, it
+// expects to be called again by the timer in LLAppDelegate
+// (llappdelegate-objc.mm).
+bool pumpMainLoop()
 {
 	bool ret = LLApp::isQuitting();
 	if (!ret && gViewerAppPtr != NULL)
 	{
-		ret = gViewerAppPtr->mainLoop();
+		ret = gViewerAppPtr->frame();
 	} else {
 		ret = true;
 	}
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 4786f83bfd1825a1c9a1d23c32bbbd75f3994d75..af0cd27fd5b628257829d56d3fe73cdb704a7535 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -317,10 +317,8 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 	}
 	
 	// Run the application main loop
-	if(!LLApp::isQuitting()) 
-	{
-		viewer_app_ptr->mainLoop();
-	}
+	while (! viewer_app_ptr->frame()) 
+	{}
 
 	if (!LLApp::isError())
 	{
@@ -330,33 +328,33 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 		// app cleanup if there was a problem.
 		//
 #if WINDOWS_CRT_MEM_CHECKS
-    LL_INFOS() << "CRT Checking memory:" << LL_ENDL;
-	if (!_CrtCheckMemory())
-	{
-		LL_WARNS() << "_CrtCheckMemory() failed at prior to cleanup!" << LL_ENDL;
-	}
-	else
-	{
-		LL_INFOS() << " No corruption detected." << LL_ENDL;
-	}
+		LL_INFOS() << "CRT Checking memory:" << LL_ENDL;
+		if (!_CrtCheckMemory())
+		{
+			LL_WARNS() << "_CrtCheckMemory() failed at prior to cleanup!" << LL_ENDL;
+		}
+		else
+		{
+			LL_INFOS() << " No corruption detected." << LL_ENDL;
+		}
 #endif
-	
-	gGLActive = TRUE;
 
-	viewer_app_ptr->cleanup();
-	
+		gGLActive = TRUE;
+
+		viewer_app_ptr->cleanup();
+
 #if WINDOWS_CRT_MEM_CHECKS
-    LL_INFOS() << "CRT Checking memory:" << LL_ENDL;
-	if (!_CrtCheckMemory())
-	{
-		LL_WARNS() << "_CrtCheckMemory() failed after cleanup!" << LL_ENDL;
-	}
-	else
-	{
-		LL_INFOS() << " No corruption detected." << LL_ENDL;
-	}
+		LL_INFOS() << "CRT Checking memory:" << LL_ENDL;
+		if (!_CrtCheckMemory())
+		{
+			LL_WARNS() << "_CrtCheckMemory() failed after cleanup!" << LL_ENDL;
+		}
+		else
+		{
+			LL_INFOS() << " No corruption detected." << LL_ENDL;
+		}
 #endif
-	 
+
 	}
 	delete viewer_app_ptr;
 	viewer_app_ptr = NULL;
diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp
index 1819fc74ee1ae6c30c614e457e635f75d7e92c2c..90a5483dc98f2686d779b4851ed51d5945681f53 100644
--- a/indra/newview/llcommandlineparser.cpp
+++ b/indra/newview/llcommandlineparser.cpp
@@ -26,6 +26,7 @@
 
 #include "llviewerprecompiledheaders.h"
 #include "llcommandlineparser.h"
+#include "llexception.h"
 
 // *NOTE: The boost::lexical_cast generates 
 // the warning C4701(local used with out assignment) in VC7.1.
@@ -50,6 +51,7 @@
 #include "llsdserialize.h"
 #include "llerror.h"
 #include "stringize.h"
+#include "llexception.h"
 #include <string>
 #include <set>
 #include <iostream>
@@ -98,14 +100,14 @@ namespace
     bool gPastLastOption = false;
 }
 
-class LLCLPError : public std::logic_error {
+class LLCLPError : public LLException {
 public:
-    LLCLPError(const std::string& what) : std::logic_error(what) {}
+    LLCLPError(const std::string& what) : LLException(what) {}
 };
 
-class LLCLPLastOption : public std::logic_error {
+class LLCLPLastOption : public LLException {
 public:
-    LLCLPLastOption(const std::string& what) : std::logic_error(what) {}
+    LLCLPLastOption(const std::string& what) : LLException(what) {}
 };
 
 class LLCLPValue : public po::value_semantic_codecvt_helper<char> 
@@ -202,17 +204,17 @@ class LLCLPValue : public po::value_semantic_codecvt_helper<char>
     {
         if(gPastLastOption)
         {
-            throw(LLCLPLastOption("Don't parse no more!"));
+            LLTHROW(LLCLPLastOption("Don't parse no more!"));
         }
 
         // Error checks. Needed?
         if (!value_store.empty() && !is_composing()) 
         {
-            throw(LLCLPError("Non composing value with multiple occurences."));
+            LLTHROW(LLCLPError("Non composing value with multiple occurences."));
         }
         if (new_tokens.size() < min_tokens() || new_tokens.size() > max_tokens())
         {
-            throw(LLCLPError("Illegal number of tokens specified."));
+            LLTHROW(LLCLPError("Illegal number of tokens specified."));
         }
         
         if(value_store.empty())
@@ -466,7 +468,7 @@ onevalue(const std::string& option,
     {
         // What does it mean when the user specifies a command-line switch
         // that requires a value, but omits the value? Complain.
-        throw LLCLPError(STRINGIZE("No value specified for --" << option << "!"));
+        LLTHROW(LLCLPError(STRINGIZE("No value specified for --" << option << "!")));
     }
     else if (value.size() > 1)
     {
@@ -484,9 +486,9 @@ void badvalue(const std::string& option,
     // If the user passes an unusable value for a command-line switch, it
     // seems like a really bad idea to just ignore it, even with a log
     // warning.
-    throw LLCLPError(STRINGIZE("Invalid value specified by command-line switch '" << option
-                               << "' for variable '" << varname << "' of type " << type
-                               << ": '" << value << "'"));
+    LLTHROW(LLCLPError(STRINGIZE("Invalid value specified by command-line switch '" << option
+                                 << "' for variable '" << varname << "' of type " << type
+                                 << ": '" << value << "'")));
 }
 
 template <typename T>
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp
index 7721e6729089c65036cb7b1d7a29bfc189e12775..76e16f5a1fffef3ac7445260f02268a28a2773a9 100644
--- a/indra/newview/llcompilequeue.cpp
+++ b/indra/newview/llcompilequeue.cpp
@@ -67,7 +67,9 @@ namespace
 
     const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue");
 
-
+    // ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged 
+    // callback mechanism and the LLEventPump coroutine architecture allowing the 
+    // coroutine to wait for the inventory event.
     class ObjectInventoryFetcher: public LLVOInventoryListener
     {
     public:
@@ -144,7 +146,7 @@ class LLQueuedScriptAssetUpload : public LLScriptAssetUpload
             queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
         }
 
-        return LLSD().with("success", LLSD::Boolean(true));
+        return LLSDMap("success", LLSD::Boolean(true));
     }
 
 
@@ -254,7 +256,6 @@ LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key)
 	setTitle(LLTrans::getString("CompileQueueTitle"));
 	setStartString(LLTrans::getString("CompileQueueStart"));
 														 															 
-//	mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID()));
 }
 
 LLFloaterCompileQueue::~LLFloaterCompileQueue()
@@ -267,7 +268,6 @@ void LLFloaterCompileQueue::experienceIdsReceived( const LLSD& content )
 	{
 		mExperienceIds.insert(it->asUUID());
 	}
-//	nextObject();
 }
 
 BOOL LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const
@@ -277,11 +277,6 @@ BOOL LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const
 
 // //Attempt to record this asset ID.  If it can not be inserted into the set 
 // //then it has already been processed so return false.
-// bool LLFloaterCompileQueue::checkAssetId(const LLUUID &assetId)
-// {
-//     std::pair<uuid_list_t::iterator, bool> result = mAssetIds.insert(assetId);
-//     return result.second;
-// }
 
 void LLFloaterCompileQueue::handleHTTPResponse(std::string pumpName, const LLSD &expresult)
 {
@@ -331,8 +326,10 @@ void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID paren
 
     queue->experienceIdsReceived(result["experience_ids"]);
 
+    // getDerived handle gets a handle that can be resolved to a parent class of the derived object.
     LLHandle<LLFloaterScriptQueue> hFloater(queue->getDerivedHandle<LLFloaterScriptQueue>());
 
+    // note subtle difference here: getDerivedHandle in this case is for an LLFloaterCompileQueue
     fnQueueAction_t fn = boost::bind(LLFloaterCompileQueue::processScript,
         queue->getDerivedHandle<LLFloaterCompileQueue>(), _1, _2, _3);
 
@@ -345,37 +342,35 @@ void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID paren
 
 }
 
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
 bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloater,
     const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
 {
     LLSD result;
-    LLFloaterCompileQueue *that = hfloater.get();
-    bool monocompile = that->mMono;
+    LLCheckedHandle<LLFloaterCompileQueue> floater(hfloater);
+    // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+    // which is caught in objectScriptProcessingQueueCoro
+    bool monocompile = floater->mMono;
     F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
 
-    if (!that)
-        return false;
 
     // Initial test to see if we can (or should) attempt to compile the script.
     LLInventoryItem *item = dynamic_cast<LLInventoryItem *>(inventory);
-    {
 
-        if (!item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) ||
-            !item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
-        {
-            std::string buffer = "Skipping: " + item->getName() + "(Permissions)";
-            that->addStringMessage(buffer);
-            return true;
-        }
+    if (!item)
+    {
+        LL_WARNS("SCRIPTQ") << "item retrieved is not an LLInventoryItem." << LL_ENDL;
+        return true;
+    }
 
-//         if (!that->checkAssetId(item->getAssetUUID()))
-//         {
-//             std::string buffer = "Skipping: " + item->getName() + "(Repeat)";
-//             that->addStringMessage(buffer);
-//             return true;
-//         }
+    if (!item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) ||
+        !item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
+    {
+        std::string buffer = "Skipping: " + item->getName() + "(Permissions)";
+        floater->addStringMessage(buffer);
+        return true;
     }
-    that = NULL;
 
     // Attempt to retrieve the experience
     LLUUID experienceId;
@@ -384,37 +379,30 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
             boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1));
 
         result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
-            LLSD().with("timeout", LLSD::Boolean(true)));
+            LLSDMap("timeout", LLSD::Boolean(true)));
 
-        that = hfloater.get();
-        if (!that)
-        {
-            return false;
-        }
-
-        if (result.has("timeout") && result["timeout"].asBoolean())
-        {
+        if (result.has("timeout"))
+        {   // A timeout filed in the result will always be true if present.
             LLStringUtil::format_map_t args;
             args["[OBJECT_NAME]"] = inventory->getName();
-            std::string buffer = that->getString("Timeout", args);
-            that->addStringMessage(buffer);
+            std::string buffer = floater->getString("Timeout", args);
+            floater->addStringMessage(buffer);
             return true;
         }
 
         if (result.has(LLExperienceCache::EXPERIENCE_ID))
         {
             experienceId = result[LLExperienceCache::EXPERIENCE_ID].asUUID();
-            if (!that->hasExperience(experienceId))
+            if (!floater->hasExperience(experienceId))
             {
-                that->addProcessingMessage("CompileNoExperiencePerm", LLSD()
-                    .with("SCRIPT", inventory->getName())
-                    .with("EXPERIENCE", result[LLExperienceCache::NAME].asString()));
+                floater->addProcessingMessage("CompileNoExperiencePerm", 
+                    LLSDMap("SCRIPT", inventory->getName())
+                        ("EXPERIENCE", result[LLExperienceCache::NAME].asString()));
                 return true;
             }
         }
 
     }
-    that = NULL;
 
     {
         HandleScriptUserData    userData(pump.getName());
@@ -433,32 +421,23 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
             &userData);
 
         result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
-            LLSD().with("timeout", LLSD::Boolean(true)));
-    }
-
-    that = hfloater.get();
-    if (!that)
-    {
-        return false;
+            LLSDMap("timeout", LLSD::Boolean(true)));
     }
 
     if (result.has("timeout"))
-    {
-        if (result.has("timeout") && result["timeout"].asBoolean())
-        {
-            LLStringUtil::format_map_t args;
-            args["[OBJECT_NAME]"] = inventory->getName();
-            std::string buffer = that->getString("Timeout", args);
-            that->addStringMessage(buffer);
-            return true;
-        }
+    {   // A timeout filed in the result will always be true if present.
+        LLStringUtil::format_map_t args;
+        args["[OBJECT_NAME]"] = inventory->getName();
+        std::string buffer = floater->getString("Timeout", args);
+        floater->addStringMessage(buffer);
+        return true;
     }
 
     if (result.has("error"))
     {
         LL_WARNS("SCRIPTQ") << "Inventory fetch returned with error. Code: " << result["error"].asString() << LL_ENDL;
         std::string buffer = result["message"].asString() + " " + inventory->getName();
-        that->addStringMessage(buffer);
+        floater->addStringMessage(buffer);
 
         if (result.has("alert"))
         {
@@ -470,12 +449,9 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
     }
 
     LLUUID assetId = result["asset_id"];
-    that = NULL;
-
 
     std::string url = object->getRegion()->getCapability("UpdateScriptTask");
 
-
     {
         LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(object->getID(), 
             inventory->getUUID(), 
@@ -490,24 +466,15 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
         LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
     }
 
-    result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSD().with("timeout", LLSD::Boolean(true)));
-
-    that = hfloater.get();
-    if (!that)
-    {
-        return false;
-    }
+    result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true)));
 
     if (result.has("timeout"))
-    {
-        if (result.has("timeout") && result["timeout"].asBoolean())
-        {
-            LLStringUtil::format_map_t args;
-            args["[OBJECT_NAME]"] = inventory->getName();
-            std::string buffer = that->getString("Timeout", args);
-            that->addStringMessage(buffer);
-            return true;
-        }
+    { // A timeout filed in the result will always be true if present.
+        LLStringUtil::format_map_t args;
+        args["[OBJECT_NAME]"] = inventory->getName();
+        std::string buffer = floater->getString("Timeout", args);
+        floater->addStringMessage(buffer);
+        return true;
     }
 
     // Bytecode save completed
@@ -515,21 +482,21 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
     {
         std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" succeeded");
 
-        that->addStringMessage(buffer);
+        floater->addStringMessage(buffer);
         LL_INFOS() << buffer << LL_ENDL;
     }
     else
     {
         LLSD compile_errors = result["errors"];
         std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" failed:");
-        that->addStringMessage(buffer);
+        floater->addStringMessage(buffer);
         for (LLSD::array_const_iterator line = compile_errors.beginArray();
             line < compile_errors.endArray(); line++)
         {
             std::string str = line->asString();
             str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
 
-            that->addStringMessage(str);
+            floater->addStringMessage(str);
         }
         LL_INFOS() << result["errors"] << LL_ENDL;
     }
@@ -576,16 +543,18 @@ LLFloaterResetQueue::~LLFloaterResetQueue()
 { 
 }
 
-bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater, 
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
     const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
 {
-    LLFloaterScriptQueue *that = hfloater.get();
-    if (that)
-    {
-        std::string buffer;
-        buffer = that->getString("Resetting") + (": ") + inventory->getName();
-        that->addStringMessage(buffer);
-    }
+    LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+    // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+    // which is caught in objectScriptProcessingQueueCoro
+
+    std::string buffer;
+    buffer = floater->getString("Resetting") + (": ") + inventory->getName();
+    floater->addStringMessage(buffer);
     
     LLMessageSystem* msg = gMessageSystem;
     msg->newMessageFast(_PREHASH_ScriptReset);
@@ -602,6 +571,8 @@ bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hflo
 
 bool LLFloaterResetQueue::startQueue()
 {
+    // Bind the resetObjectScripts method into a QueueAction function and pass it
+    // into the object queue processing coroutine.
     fnQueueAction_t fn = boost::bind(LLFloaterResetQueue::resetObjectScripts,
         getDerivedHandle<LLFloaterScriptQueue>(), _1, _2, _3);
 
@@ -629,16 +600,18 @@ LLFloaterRunQueue::~LLFloaterRunQueue()
 { 
 }
 
-bool LLFloaterRunQueue::runObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater, 
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterRunQueue::runObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
     const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
 {
-    LLFloaterScriptQueue *that = hfloater.get();
-    if (that)
-    {
-        std::string buffer;
-        buffer = that->getString("Running") + (": ") + inventory->getName();
-        that->addStringMessage(buffer);
-    }
+    LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+    // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+    // which is caught in objectScriptProcessingQueueCoro
+
+    std::string buffer;
+    buffer = floater->getString("Running") + (": ") + inventory->getName();
+    floater->addStringMessage(buffer);
 
     LLMessageSystem* msg = gMessageSystem;
     msg->newMessageFast(_PREHASH_SetScriptRunning);
@@ -684,16 +657,18 @@ LLFloaterNotRunQueue::~LLFloaterNotRunQueue()
 { 
 }
 
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
 bool LLFloaterNotRunQueue::stopObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater, 
     const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
 {
-    LLFloaterScriptQueue *that = hfloater.get();
-    if (that)
-    {
-        std::string buffer;
-        buffer = that->getString("NotRunning") + (": ") + inventory->getName();
-        that->addStringMessage(buffer);
-    }
+    LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+    // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+    // which is caught in objectScriptProcessingQueueCoro
+
+    std::string buffer;
+    buffer = floater->getString("NotRunning") + (": ") + inventory->getName();
+    floater->addStringMessage(buffer);
 
     LLMessageSystem* msg = gMessageSystem;
     msg->newMessageFast(_PREHASH_SetScriptRunning);
@@ -732,7 +707,7 @@ void ObjectInventoryFetcher::inventoryChanged(LLViewerObject* object,
     mInventoryList.clear();
     mInventoryList.assign(inventory->begin(), inventory->end());
 
-    mPump.post(LLSD().with("changed", LLSD::Boolean(true)));
+    mPump.post(LLSDMap("changed", LLSD::Boolean(true)));
 
 }
 
@@ -740,115 +715,97 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L
     object_data_list_t objectList, fnQueueAction_t func)
 {
     LLCoros::set_consuming(true);
-    LLFloaterScriptQueue * floater(NULL);
+    LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);    
+    // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. 
+    // This is expected if the dialog closes.
     LLEventMailDrop        maildrop(QUEUE_EVENTPUMP_NAME, true);
     F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
 
-//     floater = hfloater.get();
-//     floater->addProcessingMessage("Starting",
-//         LLSD()
-//         .with("[START]", action)
-//         .with("[COUNT]", LLSD::Integer(objectList.size())));
-//     floater = NULL;
 
-    for (object_data_list_t::iterator itObj(objectList.begin()); (itObj != objectList.end()); ++itObj)
+    try
     {
-        bool firstForObject = true;
-        LLUUID object_id = (*itObj).mObjectId;
-        LL_INFOS("SCRIPTQ") << "Next object in queue with ID=" << object_id.asString() << LL_ENDL;
-
-        LLPointer<LLViewerObject> obj = gObjectList.findObject(object_id);
-        LLInventoryObject::object_list_t inventory;
-        if (obj)
+        for (object_data_list_t::iterator itObj(objectList.begin()); (itObj != objectList.end()); ++itObj)
         {
-            ObjectInventoryFetcher::ptr_t fetcher(new ObjectInventoryFetcher(maildrop, obj, NULL));
+            bool firstForObject = true;
+            LLUUID object_id = (*itObj).mObjectId;
+            LL_INFOS("SCRIPTQ") << "Next object in queue with ID=" << object_id.asString() << LL_ENDL;
 
-            fetcher->fetchInventory();
-
-            floater = hfloater.get();
-            if (floater)
+            LLPointer<LLViewerObject> obj = gObjectList.findObject(object_id);
+            LLInventoryObject::object_list_t inventory;
+            if (obj)
             {
+                ObjectInventoryFetcher::ptr_t fetcher(new ObjectInventoryFetcher(maildrop, obj, NULL));
+
+                fetcher->fetchInventory();
+
                 LLStringUtil::format_map_t args;
                 args["[OBJECT_NAME]"] = (*itObj).mObjectName;
                 floater->addStringMessage(floater->getString("LoadingObjInv", args));
-            }
 
-            LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout,
-                LLSD().with("timeout", LLSD::Boolean(true)));
+                LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout,
+                    LLSDMap("timeout", LLSD::Boolean(true)));
 
-            if (result.has("timeout") && result["timeout"].asBoolean())
-            {
-                LL_WARNS("SCRIPTQ") << "Unable to retrieve inventory for object " << object_id.asString() <<
-                    ". Skipping to next object." << LL_ENDL;
+                if (result.has("timeout"))
+                {    // A timeout filed in the result will always be true if present.
+                    LL_WARNS("SCRIPTQ") << "Unable to retrieve inventory for object " << object_id.asString() <<
+                        ". Skipping to next object." << LL_ENDL;
 
-                // floater could have been closed
-                floater = hfloater.get();
-                if (floater)
-                {
                     LLStringUtil::format_map_t args;
                     args["[OBJECT_NAME]"] = (*itObj).mObjectName;
                     floater->addStringMessage(floater->getString("Timeout", args));
+
+                    continue;
                 }
 
+                inventory.assign(fetcher->getInventoryList().begin(), fetcher->getInventoryList().end());
+            }
+            else
+            {
+                LL_WARNS("SCRIPTQ") << "Unable to retrieve object with ID of " << object_id <<
+                    ". Skipping to next." << LL_ENDL;
                 continue;
             }
 
-            inventory.assign(fetcher->getInventoryList().begin(), fetcher->getInventoryList().end());
-        }
-        else
-        {
-            LL_WARNS("SCRIPTQ") << "Unable to retrieve object with ID of " << object_id <<
-                ". Skipping to next." << LL_ENDL;
-            continue;
-        }
+            // TODO: Get the name of the object we are looking at here so that we can display it below.
+            //std::string objName = (dynamic_cast<LLInventoryObject *>(obj.get()))->getName();
+            LL_DEBUGS("SCRIPTQ") << "Object has " << inventory.size() << " items." << LL_ENDL;
 
-        // TODO: Get the name of the object we are looking at here so that we can display it below.
-        //std::string objName = (dynamic_cast<LLInventoryObject *>(obj.get()))->getName();
-        LL_DEBUGS("SCRIPTQ") << "Object has " << inventory.size() << " items." << LL_ENDL;
-
-        for (LLInventoryObject::object_list_t::iterator itInv = inventory.begin();
-            itInv != inventory.end(); ++itInv)
-        {
-            floater = hfloater.get();
-            if (!floater)
+            for (LLInventoryObject::object_list_t::iterator itInv = inventory.begin();
+                itInv != inventory.end(); ++itInv)
             {
-                LL_WARNS("SCRIPTQ") << "Script Queue floater closed! Canceling remaining ops" << LL_ENDL;
-                break;
-            }
+                floater.check();
 
-            // note, we have a smart pointer to the obj above... but if we didn't we'd check that 
-            // it still exists here.
+                // note, we have a smart pointer to the obj above... but if we didn't we'd check that 
+                // it still exists here.
 
-            if (((*itInv)->getType() == LLAssetType::AT_LSL_TEXT))
-            {
-                LL_DEBUGS("SCRIPTQ") << "Inventory item " << (*itInv)->getUUID().asString() << "\"" << (*itInv)->getName() << "\"" << LL_ENDL;
-                if (firstForObject)
+                if (((*itInv)->getType() == LLAssetType::AT_LSL_TEXT))
                 {
-                    //floater->addStringMessage(objName + ":");
-                    firstForObject = false;
+                    LL_DEBUGS("SCRIPTQ") << "Inventory item " << (*itInv)->getUUID().asString() << "\"" << (*itInv)->getName() << "\"" << LL_ENDL;
+                    if (firstForObject)
+                    {
+                        //floater->addStringMessage(objName + ":");
+                        firstForObject = false;
+                    }
+
+                    if (!func(obj, (*itInv), maildrop))
+                    {
+                        continue;
+                    }
                 }
 
-                if (!func(obj, (*itInv), maildrop))
-                {
-                    continue;
-                }
+                // no other explicit suspension point in this loop.  func(...) MIGHT suspend
+                // but offers no guarantee of doing so.
+                llcoro::suspend();
             }
-
-            llcoro::suspend();
-        }
-        // Just test to be sure the floater is still present before calling the func
-        if (!hfloater.get())
-        {
-            LL_WARNS("SCRIPTQ") << "Script Queue floater dismissed." << LL_ENDL;
-            break;
         }
 
-    }
-
-    floater = hfloater.get();
-    if (floater)
-    {
         floater->addStringMessage("Done");
         floater->getChildView("close")->setEnabled(TRUE);
     }
+    catch (LLCheckedHandleBase::Stale &)
+    {
+        // This is expected.  It means that floater has been closed before 
+        // processing was completed.
+        LL_DEBUGS("SCRIPTQ") << "LLExeceptionStaleHandle caught! Floater has most likely been closed." << LL_ENDL;
+    }
 }
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 024e315632812112cd6bbe12e206adb7ac0b5724..dece3fc1ea69fe736613c58ac2c22a92af792594 100644
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -55,7 +55,8 @@ LLFloaterWebContent::_Params::_Params()
 	preferred_media_size("preferred_media_size"),
 	trusted_content("trusted_content", false),
 	show_page_title("show_page_title", true),
-    clean_browser("clean_browser", false)
+	clean_browser("clean_browser", false),
+	dev_mode("dev_mode", false)
 {}
 
 LLFloaterWebContent::LLFloaterWebContent( const Params& params )
@@ -74,14 +75,16 @@ LLFloaterWebContent::LLFloaterWebContent( const Params& params )
 	mShowPageTitle(params.show_page_title),
     mAllowNavigation(true),
     mCurrentURL(""),
-    mDisplayURL("")
+    mDisplayURL(""),
+    mDevelopMode(params.dev_mode) // if called from "Develop" Menu, set a flag and change things to be more useful for devs
 {
 	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 ));
+	mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind(&LLFloaterWebContent::onPopExternal, this));
+	mCommitCallbackRegistrar.add( "WebContent.TestURL", boost::bind(&LLFloaterWebContent::onTestURL, this, _2));
 }
 
 BOOL LLFloaterWebContent::postBuild()
@@ -195,8 +198,6 @@ void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
 						width + getRect().getWidth() - browser_rect.getWidth(), 
 						height + getRect().getHeight() - browser_rect.getHeight());
 
-	LL_DEBUGS() << "geometry change: " << geom << LL_ENDL;
-	
 	LLRect new_rect;
 	getParent()->screenRectToLocal(geom, &new_rect);
 	setShape(new_rect);	
@@ -205,8 +206,6 @@ void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
 // static
 void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p)
 {
-	LL_DEBUGS() << "url = " << p.url() << ", target = " << p.target() << ", uuid = " << p.id() << LL_ENDL;
-
 	if (!p.id.isProvided())
 	{
 		p.id = LLUUID::generateNewID().asString();
@@ -224,12 +223,6 @@ void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p)
 		// and close the least recently opened one if this will put us over the limit.
 
 		LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList(p.window_class);
-		LL_DEBUGS() << "total instance count is " << instances.size() << LL_ENDL;
-
-		for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
-		{
-			LL_DEBUGS() << "    " << (*iter)->getKey()["target"] << LL_ENDL;
-		}
 
 		if(instances.size() >= (size_t)browser_window_limit)
 		{
@@ -241,16 +234,19 @@ void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p)
 
 void LLFloaterWebContent::open_media(const Params& p)
 {
-	// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
 	LLViewerMedia::proxyWindowOpened(p.target(), p.id());
-	mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML);
+	mWebBrowser->setHomePageUrl(p.url);
 	mWebBrowser->setTarget(p.target);
-	mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML, p.clean_browser);
+	mWebBrowser->navigateTo(p.url);
 	
 	set_current_url(p.url);
 
 	getChild<LLLayoutPanel>("status_bar")->setVisible(p.show_chrome);
 	getChild<LLLayoutPanel>("nav_controls")->setVisible(p.show_chrome);
+
+	// turn additional debug controls on but only for Develop mode (Develop menu open)
+	getChild<LLLayoutPanel>("debug_controls")->setVisible(mDevelopMode);
+
 	bool address_entry_enabled = p.allow_address_entry && !p.trusted_content;
     mAllowNavigation = p.allow_back_forward_navigation;
 	getChildView("address")->setEnabled(address_entry_enabled);
@@ -499,7 +495,7 @@ void LLFloaterWebContent::onEnterAddress()
     LLStringUtil::trim(url);
 	if ( url.length() > 0 )
 	{
-		mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		mWebBrowser->navigateTo(url);
 	};
 }
 
@@ -508,9 +504,18 @@ 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();
-    LLStringUtil::trim(url);
-	if ( url.length() > 0 )
+	LLStringUtil::trim(url);
+	if (url.length() > 0)
+	{
+		LLWeb::loadURLExternal(url);
+	};
+}
+
+void LLFloaterWebContent::onTestURL(std::string url)
+{
+	LLStringUtil::trim(url);
+	if (url.length() > 0)
 	{
-		LLWeb::loadURLExternal( url );
+		mWebBrowser->navigateTo(url);
 	};
 }
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h
index 4291fd9f2c391f56a7c2baaa2b640f2a9adffeaf..0bf93504c28623293b7e7360d61948041f09dc85 100644
--- a/indra/newview/llfloaterwebcontent.h
+++ b/indra/newview/llfloaterwebcontent.h
@@ -58,7 +58,8 @@ class LLFloaterWebContent :
                                 allow_back_forward_navigation,
 								trusted_content,
 								show_page_title,
-                                clean_browser;
+								clean_browser,
+								dev_mode;
 		Optional<LLRect>		preferred_media_size;
 
 		_Params();
@@ -92,6 +93,7 @@ class LLFloaterWebContent :
 	void onClickStop();
 	void onEnterAddress();
 	void onPopExternal();
+	void onTestURL(std::string url);
 
 	static void preCreate(Params& p);
 	void open_media(const Params& );
@@ -113,6 +115,7 @@ class LLFloaterWebContent :
 	std::string		mUUID;
 	bool			mShowPageTitle;
     bool            mAllowNavigation;
+	bool			mDevelopMode;
 };
 
 #endif  // LL_LLFLOATERWEBCONTENT_H
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index 763657ebad51fa7651c2bdf1b52328178520269e..0bcd8a9e63cfa21b1bd797ea46ef869d4430d40a 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -95,7 +95,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
 	mVolumeSliderVisible(0),
 	mWindowShade(NULL),
 	mHideImmediately(false),
-    mSecureURL(false)
+    mSecureURL(false),
+	mMediaPlaySliderCtrlMouseDownValue(0.0)
 {
 	mCommitCallbackRegistrar.add("MediaCtrl.Close",		boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
 	mCommitCallbackRegistrar.add("MediaCtrl.Back",		boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
@@ -109,7 +110,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
 	mCommitCallbackRegistrar.add("MediaCtrl.Open",		boost::bind(&LLPanelPrimMediaControls::onClickOpen, this));
 	mCommitCallbackRegistrar.add("MediaCtrl.Zoom",		boost::bind(&LLPanelPrimMediaControls::onClickZoom, this));
 	mCommitCallbackRegistrar.add("MediaCtrl.CommitURL",	boost::bind(&LLPanelPrimMediaControls::onCommitURL, this));
-	mCommitCallbackRegistrar.add("MediaCtrl.JumpProgress",		boost::bind(&LLPanelPrimMediaControls::onCommitSlider, this));
+	mCommitCallbackRegistrar.add("MediaCtrl.MouseDown", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown, this));
+	mCommitCallbackRegistrar.add("MediaCtrl.MouseUp", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp, this));
 	mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp",	boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this));
 	mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown",	boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this));
 	mCommitCallbackRegistrar.add("MediaCtrl.Volume",	boost::bind(&LLPanelPrimMediaControls::onCommitVolumeSlider, this));
@@ -1246,26 +1248,38 @@ void LLPanelPrimMediaControls::setCurrentURL()
 #endif	// USE_COMBO_BOX_FOR_MEDIA_URL
 }
 
-void LLPanelPrimMediaControls::onCommitSlider()
+
+void LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown()
 {
-	focusOnTarget();
+	mMediaPlaySliderCtrlMouseDownValue = mMediaPlaySliderCtrl->getValue().asReal();
 
-	LLViewerMediaImpl* media_impl = getTargetMediaImpl();
-	if (media_impl) 
+	mUpdateSlider = false;
+}
+
+void LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp()
+{
+	F64 cur_value = mMediaPlaySliderCtrl->getValue().asReal();
+
+	if (mMediaPlaySliderCtrlMouseDownValue != cur_value)
 	{
-		// get slider value
-		F64 slider_value = mMediaPlaySliderCtrl->getValue().asReal();
-		if(slider_value <= 0.0)
-		{	
-			media_impl->stop();
-		}
-		else 
+		focusOnTarget();
+
+		LLViewerMediaImpl* media_impl = getTargetMediaImpl();
+		if (media_impl)
 		{
-			media_impl->seek(slider_value*mMovieDuration);
-			//mUpdateSlider= false;
+			if (cur_value <= 0.0)
+			{
+				media_impl->stop();
+			}
+			else
+			{
+				media_impl->seek(cur_value * mMovieDuration);
+			}
 		}
+
+		mUpdateSlider = true;
 	}
-}		
+}
 
 void LLPanelPrimMediaControls::onCommitVolumeUp()
 {
diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h
index 6d2eb3430e456290445fbaa5c816cab2c951e47f..21d52360744d7e53c0f4847bccb14efb3029a5b7 100644
--- a/indra/newview/llpanelprimmediacontrols.h
+++ b/indra/newview/llpanelprimmediacontrols.h
@@ -107,8 +107,10 @@ class LLPanelPrimMediaControls : public LLPanel
 	
 	void updateZoom();
 	void setCurrentURL();
-	void onCommitSlider();
-	
+
+	void onMediaPlaySliderCtrlMouseDown();
+	void onMediaPlaySliderCtrlMouseUp();
+
 	void onCommitVolumeUp();
 	void onCommitVolumeDown();
 	void onCommitVolumeSlider();
@@ -219,6 +221,8 @@ class LLPanelPrimMediaControls : public LLPanel
 	S32 mVolumeSliderVisible;
 
 	LLNotificationPtr mActiveNotification;
+
+	F64 mMediaPlaySliderCtrlMouseDownValue;
 };
 
 #endif // LL_PANELPRIMMEDIACONTROLS_H
diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp
index 4f9f83b6f26364dbec03a1269a4091c5441f6d25..72d7cf1e4522eebcf56bfb455976d79dd7abc000 100644
--- a/indra/newview/llsecapi.cpp
+++ b/indra/newview/llsecapi.cpp
@@ -29,6 +29,8 @@
 #include "llviewerprecompiledheaders.h"
 #include "llsecapi.h"
 #include "llsechandler_basic.h"
+#include "llexception.h"
+#include "stringize.h"
 #include <openssl/evp.h>
 #include <openssl/err.h>
 #include <map>
@@ -64,12 +66,12 @@ void initializeSecHandler()
 		}
 		catch (LLProtectedDataException e)
 		{
-			exception_msg = e.getMessage();
+			exception_msg = e.what();
 		}
 	}
 	if (!exception_msg.empty())  // an exception was thrown.
 	{
-		throw LLProtectedDataException(exception_msg.c_str());
+		LLTHROW(LLProtectedDataException(exception_msg));
 	}
 
 }
@@ -101,6 +103,7 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred)
 LLSD LLCredential::getLoginParams()
 {
 	LLSD result = LLSD::emptyMap();
+	std::string username;
 	try 
 	{
 		if (mIdentifier["type"].asString() == "agent")
@@ -109,17 +112,19 @@ LLSD LLCredential::getLoginParams()
 			result["passwd"] = "$1$" + mAuthenticator["secret"].asString();
 			result["first"] = mIdentifier["first_name"];
 			result["last"] = mIdentifier["last_name"];
-		
+			username = result["first"].asString() + " " + result["last"].asString();
 		}
 		else if (mIdentifier["type"].asString() == "account")
 		{
 			result["username"] = mIdentifier["account_name"];
 			result["passwd"] = mAuthenticator["secret"];
-										
+			username = result["username"].asString();
 		}
 	}
 	catch (...)
 	{
+		// nat 2016-08-18: not clear what exceptions the above COULD throw?!
+		LOG_UNHANDLED_EXCEPTION(STRINGIZE("for '" << username << "'"));
 		// we could have corrupt data, so simply return a null login param if so
 		LL_WARNS("AppInit") << "Invalid credential" << LL_ENDL;
 	}
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index 6fe3ee31cf0369b7d8ba12424ce941868a9aef6d..6af5a28fa5eb1fc8fc1372e5d233fdfb8b522d81 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -32,6 +32,7 @@
 #include <openssl/x509.h>
 #include <ostream>
 #include "llpointer.h"
+#include "llexception.h"
 
 #ifdef LL_WINDOWS
 #pragma warning(disable:4250)
@@ -116,17 +117,13 @@
 
 
 
-class LLProtectedDataException
+struct LLProtectedDataException: public LLException
 {
-public:
-	LLProtectedDataException(const char *msg) 
+	LLProtectedDataException(const std::string& msg):
+		LLException(msg)
 	{
-		LL_WARNS("SECAPI") << "Protected Data Error: " << (std::string)msg << LL_ENDL;
-		mMsg = (std::string)msg;
+		LL_WARNS("SECAPI") << "Protected Data Error: " << msg << LL_ENDL;
 	}
-	std::string getMessage() { return mMsg; }
-protected:
-	std::string mMsg;
 };
 
 // class LLCertificate
@@ -334,22 +331,21 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred);
 
 // All error handling is via exceptions.
 
-class LLCertException
+class LLCertException: public LLException
 {
 public:
-	LLCertException(LLPointer<LLCertificate> cert, const char* msg)
+	LLCertException(LLPointer<LLCertificate> cert, const std::string& msg):
+		LLException(msg)
 	{
 
 		mCert = cert;
 
-		LL_WARNS("SECAPI") << "Certificate Error: " << (std::string)msg << LL_ENDL;
-		mMsg = (std::string)msg;
+		LL_WARNS("SECAPI") << "Certificate Error: " << msg << LL_ENDL;
 	}
-	LLPointer<LLCertificate> getCert() { return mCert; }
-	std::string getMessage() { return mMsg; }
+	virtual ~LLCertException() throw() {}
+	LLPointer<LLCertificate> getCert() const { return mCert; }
 protected:
 	LLPointer<LLCertificate> mCert;
-	std::string mMsg;
 };
 
 class LLInvalidCertificate : public LLCertException
@@ -358,6 +354,7 @@ class LLInvalidCertificate : public LLCertException
 	LLInvalidCertificate(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalid")
 	{
 	}
+	virtual ~LLInvalidCertificate() throw() {}
 protected:
 };
 
@@ -367,6 +364,7 @@ class LLCertValidationTrustException : public LLCertException
 	LLCertValidationTrustException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertUntrusted")
 	{
 	}
+	virtual ~LLCertValidationTrustException() throw() {}
 protected:
 };
 
@@ -378,7 +376,7 @@ class LLCertValidationHostnameException : public LLCertException
 	{
 		mHostname = hostname;
 	}
-	
+	virtual ~LLCertValidationHostnameException() throw() {}
 	std::string getHostname() { return mHostname; }
 protected:
 	std::string mHostname;
@@ -392,6 +390,7 @@ class LLCertValidationExpirationException : public LLCertException
 	{
 		mTime = current_time;
 	}
+	virtual ~LLCertValidationExpirationException() throw() {}
 	LLDate GetTime() { return mTime; }
 protected:
 	LLDate mTime;
@@ -403,6 +402,7 @@ class LLCertKeyUsageValidationException : public LLCertException
 	LLCertKeyUsageValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertKeyUsage")
 	{
 	}
+	virtual ~LLCertKeyUsageValidationException() throw() {}
 protected:
 };
 
@@ -412,6 +412,7 @@ class LLCertBasicConstraintsValidationException : public LLCertException
 	LLCertBasicConstraintsValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertBasicConstraints")
 	{
 	}
+	virtual ~LLCertBasicConstraintsValidationException() throw() {}
 protected:
 };
 
@@ -421,6 +422,7 @@ class LLCertValidationInvalidSignatureException : public LLCertException
 	LLCertValidationInvalidSignatureException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidSignature")
 	{
 	}
+	virtual ~LLCertValidationInvalidSignatureException() throw() {}
 protected:
 };
 
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 40516f9bbb6243d0fe978f2a193b66f416135046..d6fb801cc0089f5bef88255708eb05e20eb6832d 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -35,6 +35,8 @@
 #include "llfile.h"
 #include "lldir.h"
 #include "llviewercontrol.h"
+#include "llexception.h"
+#include "stringize.h"
 #include <vector>
 #include <ios>
 #include <openssl/ossl_typ.h>
@@ -72,14 +74,14 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert)
 	if(pem_bio == NULL)
 	{
 		LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;
-		throw LLInvalidCertificate(this);
+		LLTHROW(LLInvalidCertificate(this));
 	}
 	mCert = NULL;
 	PEM_read_bio_X509(pem_bio, &mCert, 0, NULL);
 	BIO_free(pem_bio);
 	if (!mCert)
 	{
-		throw LLInvalidCertificate(this);
+		LLTHROW(LLInvalidCertificate(this));
 	}
 }
 
@@ -88,7 +90,7 @@ LLBasicCertificate::LLBasicCertificate(X509* pCert)
 {
 	if (!pCert || !pCert->cert_info)
 	{
-		throw LLInvalidCertificate(this);
+		LLTHROW(LLInvalidCertificate(this));
 	}	
 	mCert = X509_dup(pCert);
 }
@@ -617,7 +619,7 @@ void LLBasicCertificateStore::load_from_file(const std::string& filename)
 				}
 				catch (...)
 				{
-					LL_WARNS("SECAPI") << "Failure creating certificate from the certificate store file." << LL_ENDL;
+					LOG_UNHANDLED_EXCEPTION("creating certificate from the certificate store file");
 				}
 				X509_free(cert_x509);
 				cert_x509 = NULL;
@@ -873,22 +875,22 @@ void _validateCert(int validation_policy,
 	// check basic properties exist in the cert
 	if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING))
 	{
-		throw LLCertException(cert, "Cert doesn't have a Subject Name");				
+		LLTHROW(LLCertException(cert, "Cert doesn't have a Subject Name"));
 	}
 	
 	if(!current_cert_info.has(CERT_ISSUER_NAME_STRING))
 	{
-		throw LLCertException(cert, "Cert doesn't have an Issuer Name");				
+		LLTHROW(LLCertException(cert, "Cert doesn't have an Issuer Name"));
 	}
 	
 	// check basic properties exist in the cert
 	if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO))
 	{
-		throw LLCertException(cert, "Cert doesn't have an expiration period");				
+		LLTHROW(LLCertException(cert, "Cert doesn't have an expiration period"));
 	}
 	if (!current_cert_info.has(CERT_SHA1_DIGEST))
 	{
-		throw LLCertException(cert, "No SHA1 digest");
+		LLTHROW(LLCertException(cert, "No SHA1 digest"));
 	}
 
 	if (validation_policy & VALIDATION_POLICY_TIME)
@@ -903,7 +905,7 @@ void _validateCert(int validation_policy,
 		if((validation_date < current_cert_info[CERT_VALID_FROM].asDate()) ||
 		   (validation_date > current_cert_info[CERT_VALID_TO].asDate()))
 		{
-			throw LLCertValidationExpirationException(cert, validation_date);
+			LLTHROW(LLCertValidationExpirationException(cert, validation_date));
 		}
 	}
 	if (validation_policy & VALIDATION_POLICY_SSL_KU)
@@ -914,14 +916,14 @@ void _validateCert(int validation_policy,
 			!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], 
 									  LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT)))))
 		{
-			throw LLCertKeyUsageValidationException(cert);
+			LLTHROW(LLCertKeyUsageValidationException(cert));
 		}
 		// only validate EKU if the cert has it
 		if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() &&	   
 		   (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], 
 									LLSD((std::string)CERT_EKU_SERVER_AUTH))))
 		{
-			throw LLCertKeyUsageValidationException(cert);			
+			LLTHROW(LLCertKeyUsageValidationException(cert));
 		}
 	}
 	if (validation_policy & VALIDATION_POLICY_CA_KU)
@@ -930,7 +932,7 @@ void _validateCert(int validation_policy,
 			(!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], 
 									   (std::string)CERT_KU_CERT_SIGN)))
 			{
-				throw LLCertKeyUsageValidationException(cert);						
+				LLTHROW(LLCertKeyUsageValidationException(cert));
 			}
 	}
 	
@@ -942,13 +944,13 @@ void _validateCert(int validation_policy,
 		if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) ||
 		   !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA])
 		{
-				throw LLCertBasicConstraintsValidationException(cert);
+				LLTHROW(LLCertBasicConstraintsValidationException(cert));
 		}
 		if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) &&
 			((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) &&
 			 (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger())))
 		{
-			throw LLCertBasicConstraintsValidationException(cert);					
+			LLTHROW(LLCertBasicConstraintsValidationException(cert));
 		}
 	}
 }
@@ -1018,7 +1020,7 @@ void LLBasicCertificateStore::validate(int validation_policy,
 
 	if(cert_chain->size() < 1)
 	{
-		throw LLCertException(NULL, "No certs in chain");
+		LLTHROW(LLCertException(NULL, "No certs in chain"));
 	}
 	iterator current_cert = cert_chain->begin();
 	LLSD 	current_cert_info;
@@ -1033,11 +1035,11 @@ void LLBasicCertificateStore::validate(int validation_policy,
 		(*current_cert)->getLLSD(current_cert_info);
 		if(!validation_params.has(CERT_HOSTNAME))
 		{
-			throw LLCertException((*current_cert), "No hostname passed in for validation");			
+			LLTHROW(LLCertException((*current_cert), "No hostname passed in for validation"));
 		}
 		if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info[CERT_SUBJECT_NAME].has(CERT_NAME_CN))
 		{
-			throw LLInvalidCertificate((*current_cert));				
+			LLTHROW(LLInvalidCertificate((*current_cert)));
 		}
 		
 		LL_DEBUGS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() << 
@@ -1054,7 +1056,7 @@ void LLBasicCertificateStore::validate(int validation_policy,
 	X509* cert_x509 = (*current_cert)->getOpenSSLX509();
 	if(!cert_x509)
 	{
-		throw LLInvalidCertificate((*current_cert));			
+		LLTHROW(LLInvalidCertificate((*current_cert)));
 	}
 	std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH);
 	X509_free( cert_x509 );
@@ -1075,7 +1077,7 @@ void LLBasicCertificateStore::validate(int validation_policy,
 			if((validation_date < cache_entry->second.first) ||
 			   (validation_date > cache_entry->second.second))
 			{
-				throw LLCertValidationExpirationException((*current_cert), validation_date);
+				LLTHROW(LLCertValidationExpirationException((*current_cert), validation_date));
 			}
 		}
 		// successfully found in cache
@@ -1107,7 +1109,7 @@ void LLBasicCertificateStore::validate(int validation_policy,
 			if(!_verify_signature((*current_cert),
 								  previous_cert))
 			{
-			   throw LLCertValidationInvalidSignatureException(previous_cert);
+			   LLTHROW(LLCertValidationInvalidSignatureException(previous_cert));
 			}
 		}
 		_validateCert(local_validation_policy,
@@ -1156,7 +1158,7 @@ void LLBasicCertificateStore::validate(int validation_policy,
 			if(!_verify_signature((*found_store_cert),
 								  (*current_cert)))
 			{
-				throw LLCertValidationInvalidSignatureException(*current_cert);
+				LLTHROW(LLCertValidationInvalidSignatureException(*current_cert));
 			}			
 			// successfully validated.
 			mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);		
@@ -1173,7 +1175,7 @@ void LLBasicCertificateStore::validate(int validation_policy,
 	if (validation_policy & VALIDATION_POLICY_TRUSTED)
 	{
 		// we reached the end without finding a trusted cert.
-		throw LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1]);
+		LLTHROW(LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1]));
 
 	}
 	mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);	
@@ -1261,7 +1263,7 @@ void LLSecAPIBasicHandler::_readProtectedData()
 		protected_data_stream.read((char *)salt, STORE_SALT_SIZE);
 		if (protected_data_stream.gcount() < STORE_SALT_SIZE)
 		{
-			throw LLProtectedDataException("Config file too short.");
+			LLTHROW(LLProtectedDataException("Config file too short."));
 		}
 
 		cipher.decrypt(salt, STORE_SALT_SIZE);		
@@ -1301,7 +1303,7 @@ void LLSecAPIBasicHandler::_readProtectedData()
 		if (parser->parse(parse_stream, mProtectedDataMap, 
 						  LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
 		{
-			throw LLProtectedDataException("Config file cannot be decrypted.");
+			LLTHROW(LLProtectedDataException("Config file cannot be decrypted."));
 		}
 	}
 }
@@ -1364,7 +1366,7 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 	}
 	catch (...)
 	{
-		LL_WARNS() << "LLProtectedDataException(Error writing Protected Data Store)" << LL_ENDL;
+		LOG_UNHANDLED_EXCEPTION("LLProtectedDataException(Error writing Protected Data Store)");
 		// it's good practice to clean up any secure information on error
 		// (even though this file isn't really secure.  Perhaps in the future
 		// it may be, however.
@@ -1372,39 +1374,39 @@ void LLSecAPIBasicHandler::_writeProtectedData()
 
 		// EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData()
 		// Decided throwing an exception here was overkill until we figure out why this happens
-		//throw LLProtectedDataException("Error writing Protected Data Store");
+		//LLTHROW(LLProtectedDataException("Error writing Protected Data Store"));
 	}
 
-    try
-    {
-        // move the temporary file to the specified file location.
-        if(((   (LLFile::isfile(mProtectedDataFilename) != 0)
-             && (LLFile::remove(mProtectedDataFilename) != 0)))
-           || (LLFile::rename(tmp_filename, mProtectedDataFilename)))
-        {
-            LL_WARNS() << "LLProtectedDataException(Could not overwrite protected data store)" << LL_ENDL;
-            LLFile::remove(tmp_filename);
+	try
+	{
+		// move the temporary file to the specified file location.
+		if(((	(LLFile::isfile(mProtectedDataFilename) != 0)
+			 && (LLFile::remove(mProtectedDataFilename) != 0)))
+		   || (LLFile::rename(tmp_filename, mProtectedDataFilename)))
+		{
+			LL_WARNS() << "LLProtectedDataException(Could not overwrite protected data store)" << LL_ENDL;
+			LLFile::remove(tmp_filename);
 
-            // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData()
-            // Decided throwing an exception here was overkill until we figure out why this happens
-            //throw LLProtectedDataException("Could not overwrite protected data store");
-        }
+			// EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData()
+			// Decided throwing an exception here was overkill until we figure out why this happens
+			//LLTHROW(LLProtectedDataException("Could not overwrite protected data store"));
+		}
 	}
 	catch (...)
 	{
-		LL_WARNS() << "LLProtectedDataException(Error renaming '" << tmp_filename
-                   << "' to '" << mProtectedDataFilename << "')" << LL_ENDL;
+		LOG_UNHANDLED_EXCEPTION(STRINGIZE("renaming '" << tmp_filename << "' to '"
+										  << mProtectedDataFilename << "'"));
 		// it's good practice to clean up any secure information on error
 		// (even though this file isn't really secure.  Perhaps in the future
-		// it may be, however.
+		// it may be, however).
 		LLFile::remove(tmp_filename);
 
 		//crash in LLSecAPIBasicHandler::_writeProtectedData()
 		// Decided throwing an exception here was overkill until we figure out why this happens
-		//throw LLProtectedDataException("Error writing Protected Data Store");
+		//LLTHROW(LLProtectedDataException("Error writing Protected Data Store"));
 	}
 }
-		
+
 // instantiate a certificate from a pem string
 LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert)
 {
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 2d06b8599c2152de1f1db604ac008852613806c5..d28a7cc048859852fc0622d4d3f63881eeb52b17 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -230,8 +230,8 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
 	const F32 xyScaleInv = (1.f / xyScale)*(0.2222222222f);
 
 	F32 vec[3] = {
-					fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f),
-					fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f),
+                    (F32)fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f),
+                    (F32)fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f),
 					0.f
 				};
 	F32 rand_val = llclamp(noise2(vec)* 0.75f + 0.5f, 0.f, 1.f);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 670ce7df56308eedf0f7f52b582a63880a554c5e..e9ee67a929885a9d52775481e6590b6c83455b27 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7918,7 +7918,7 @@ void handle_web_browser_test(const LLSD& param)
 void handle_web_content_test(const LLSD& param)
 {
 	std::string url = param.asString();
-	LLWeb::loadURLInternal(url);
+	LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true);
 }
 
 void handle_show_url(const LLSD& param)
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index b37e41fb857429e0e2f8343f6b9eada2a52ea1a3..8026dc3ea8e32212441022fec1b3c9ed2442c716 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -104,10 +104,10 @@ void LLWeb::loadURL(const std::string& url, const std::string& target, const std
 
 // static
 // Explicitly open a Web URL using the Web content floater
-void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid)
+void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid, bool dev_mode)
 {
 	LLFloaterWebContent::Params p;
-	p.url(url).target(target).id(uuid);
+	p.url(url).target(target).id(uuid).dev_mode(dev_mode);
 	LLFloaterReg::showInstance("web_content", p);
 }
 
diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h
index 7c90badbfe643eabae9349d16489e59e3f3c90ac..7149ce9baf49b265f1de93ee560b40faa7e03296 100644
--- a/indra/newview/llweb.h
+++ b/indra/newview/llweb.h
@@ -57,7 +57,7 @@ class LLWeb
 
 	static void loadURL(const std::string& url, const std::string& target = LLStringUtil::null, const std::string& uuid = LLStringUtil::null);
 	// load content using built-in browser
-	static void loadURLInternal(const std::string &url, const std::string& target = LLStringUtil::null, const std::string& uuid = LLStringUtil::null);
+	static void loadURLInternal(const std::string &url, const std::string& target = LLStringUtil::null, const std::string& uuid = LLStringUtil::null, bool dev_mode = false);
 
 	/// Returns escaped url (eg, " " to "%20") - used by all loadURL methods
 	static std::string escapeURL(const std::string& url);
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 11d3706821fa5cf20411502ce71ddd05f57c526a..cee47a591e36058e1846e60284d5c3804f4a4a17 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -957,10 +957,10 @@ void LLWorld::updateWaterObjects()
 	center_y = min_y + (wy >> 1);
 
 	S32 add_boundary[4] = {
-		512 - (max_x - region_x),
-		512 - (max_y - region_y),
-		512 - (region_x - min_x),
-		512 - (region_y - min_y) };
+		(S32)(512 - (max_x - region_x)),
+		(S32)(512 - (max_y - region_y)),
+		(S32)(512 - (region_x - min_x)),
+		(S32)(512 - (region_y - min_y)) };
 		
 	S32 dir;
 	for (dir = 0; dir < 8; dir++)
diff --git a/indra/newview/skins/default/textures/icons/Video_URL_Off.png b/indra/newview/skins/default/textures/icons/Video_URL_Off.png
new file mode 100644
index 0000000000000000000000000000000000000000..40e5df7d81372cf23f9e924e6f2dc9241a48f0f8
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Video_URL_Off.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index a9a4913b21a6a891c41db2000f19b6d8ccdf05fb..670410c3d494572af8e781338064ddc863ea5df8 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -676,7 +676,10 @@ with the same filename but different name
   <texture name="Unread_Chiclet" file_name="bottomtray/Unread_Chiclet.png" preload="false" />
 
   <texture name="UpArrow_Off" file_name="icons/UpArrow_Off.png" preload="false" />
-	<texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png" scale.left="2" scale.right="7" scale.bottom="8" scale.top="120"  scale_type="scale_outer"/>
+
+  <texture name="Video_URL_Off" file_name="icons/Video_URL_Off.png" preload="true" />
+  
+  <texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png" scale.left="2" scale.right="7" scale.bottom="8" scale.top="120"  scale_type="scale_outer"/>
 
     <texture name="Volume_Background" file_name="windows/Volume_Background.png" preload="false"
            scale.left="6" scale.top="33" scale.right="63" scale.bottom="10" />
diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml
index a80440e844892d3cefe08f35cbed13a7bdd6efb4..4473ce0cdac4cc4bd01a1ad14c4912825606654f 100644
--- a/indra/newview/skins/default/xui/en/floater_web_content.xml
+++ b/indra/newview/skins/default/xui/en/floater_web_content.xml
@@ -153,6 +153,136 @@
           function="WebContent.PopExternal" />
       </button>
     </layout_panel>
+    <layout_panel
+     height="22"
+     layout="topleft"
+     left_delta="0"
+     name="debug_controls"
+     top_delta="0"
+     auto_resize="false"
+     width="585">
+      <button
+        image_overlay="Home_Off"
+            image_disabled="PushButton_Disabled"
+            image_disabled_selected="PushButton_Disabled"
+            image_selected="PushButton_Selected"
+            image_unselected="PushButton_Off"
+        chrome="true"
+        tool_tip="Web tests home page"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="1"
+        name="web_test_home_page"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.TestURL"
+          parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/>
+      </button>
+
+      <button
+        image_overlay="Video_URL_Off"
+            image_disabled="PushButton_Disabled"
+            image_disabled_selected="PushButton_Disabled"
+            image_selected="PushButton_Selected"
+            image_unselected="PushButton_Off"
+        chrome="true"
+        tool_tip="MPEG4 Video Test"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="27"
+        name="VLC Plugin Test"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.TestURL"
+          parameter="https://callum-linden.s3.amazonaws.com/sample_media/ss.mp4"/>
+      </button>
+      <button
+        image_overlay="Video_URL_Off"
+            image_disabled="PushButton_Disabled"
+            image_disabled_selected="PushButton_Disabled"
+            image_selected="PushButton_Selected"
+            image_unselected="PushButton_Off"
+        chrome="true"
+        tool_tip="MKV Video Test"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="51"
+        name="VLC Plugin Test"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.TestURL"
+          parameter="https://callum-linden.s3.amazonaws.com/sample_media/jellyfish.mkv"/>
+      </button>
+      <button
+        image_overlay="Video_URL_Off"
+            image_disabled="PushButton_Disabled"
+            image_disabled_selected="PushButton_Disabled"
+            image_selected="PushButton_Selected"
+            image_unselected="PushButton_Off"
+        chrome="true"
+        tool_tip="WebM Video Test"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="75"
+        name="VLC Plugin Test"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.TestURL"
+          parameter="https://callum-linden.s3.amazonaws.com/sample_media/jumprope.webm"/>
+      </button>
+      <button
+        image_overlay="Video_URL_Off"
+            image_disabled="PushButton_Disabled"
+            image_disabled_selected="PushButton_Disabled"
+            image_selected="PushButton_Selected"
+            image_unselected="PushButton_Off"
+        chrome="true"
+        tool_tip="MP3 audio Test"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="99"
+        name="VLC Plugin Test"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.TestURL"
+          parameter="https://callum-linden.s3.amazonaws.com/alegria.mp3"/>
+      </button>
+      <button
+        image_overlay="Video_URL_Off"
+            image_disabled="PushButton_Disabled"
+            image_disabled_selected="PushButton_Disabled"
+            image_selected="PushButton_Selected"
+            image_unselected="PushButton_Off"
+        chrome="true"
+        tool_tip="FLV Test"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="123"
+        name="VLC Plugin Test"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.TestURL"
+          parameter="https://callum-linden.s3.amazonaws.com/sample_media/vandal.flv"/>
+      </button>
+    </layout_panel>
     <layout_panel
       height="40"
       layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index dcf2da52f140dbbb7e60e28542cdca0134d9f35e..a39ee5fddd8d2a9f6fdd37adb2230ed472f91c29 100644
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -225,11 +225,11 @@
              parameter="message_critical" />
         </menu_item_call>
       <menu_item_call
-       label="Web Content Floater Debug Test"
-       name="Web Content Floater Debug Test">
+       label="Media Browser"
+       name="Media Browser">
         <menu_item_call.on_click
          function="Advanced.WebContentTest"
-         parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/>
+         parameter="http://google.com"/>
       </menu_item_call>
       <menu
        create_jump_keys="true"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 6da9797dc403976556b63729901d24b2f8049d37..ea826d2243843b323599b428ee2a235ba0185275 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -3141,30 +3141,13 @@
          label="UI"
          name="UI"
          tear_off="true">
-         <!--   <menu_item_check
-             label="New Bottom Bar"
-             name="New Bottom Bar">
-                <menu_item_check.on_check
-                 function="CheckControl"
-                 parameter="BottomPanelNew" />
-                <menu_item_check.on_click
-                 function="ToggleControl"
-                 parameter="BottomPanelNew" />
-            </menu_item_check>-->
-            <menu_item_call
-             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
-           label="Web Content Browser"
-           name="Web Content Browser"
-           shortcut="control|shift|Z">
+           label="Media Browser"
+           name="Media Browser"
+           shortcut="control|alt|shift|Z">
             <menu_item_call.on_click
              function="Advanced.WebContentTest"
-             parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/>
+             parameter="http://google.com"/>
           </menu_item_call>
           <menu_item_call
            label="FB Connect Test"
diff --git a/indra/newview/skins/default/xui/en/mime_types.xml b/indra/newview/skins/default/xui/en/mime_types.xml
index 7cb4a6e53b17d6f23f8e00eb0fe1e555eb41d2ef..c27fac6731bf3a5e79d23df78e94c14a5ac48849 100644
--- a/indra/newview/skins/default/xui/en/mime_types.xml
+++ b/indra/newview/skins/default/xui/en/mime_types.xml
@@ -130,10 +130,21 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_cef
 		</impl>
 	</scheme>
-	<mimetype name="blank">
+  <scheme name="libvlc">
+    <label name="libvlc_label">
+      LibVLC supported media
+    </label>
+    <widgettype>
+      movie
+    </widgettype>
+    <impl>
+      media_plugin_libvlc
+    </impl>
+  </scheme>
+  <mimetype name="blank">
 		<label name="blank_label">
 			- None -
 		</label>
@@ -163,7 +174,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/*">
@@ -174,7 +185,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="image/*">
@@ -196,7 +207,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="application/javascript">
@@ -218,7 +229,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/pdf">
@@ -295,7 +306,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="audio/mpeg">
@@ -306,7 +317,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="audio/x-aiff">
@@ -317,7 +328,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="audio/x-wav">
@@ -328,7 +339,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/bmp">
@@ -438,7 +449,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/mp4">
@@ -449,10 +460,21 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
-	<mimetype menu="1" name="video/quicktime">
+  <mimetype name="application/octet-stream">
+    <label name="video/octet-stream">
+      Movie
+    </label>
+    <widgettype>
+      movie
+    </widgettype>
+    <impl>
+      media_plugin_libvlc
+    </impl>
+  </mimetype>
+  <mimetype menu="1" name="video/quicktime">
 		<label name="video/quicktime_label">
 			Movie (QuickTime)
 		</label>
@@ -460,7 +482,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/x-ms-asf">
@@ -471,7 +493,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/x-ms-wmv">
@@ -482,7 +504,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="video/x-msvideo">
@@ -493,7 +515,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_quicktime
+			media_plugin_cef
 		</impl>
 	</mimetype>
 </mimetypes>
diff --git a/indra/newview/skins/default/xui/en/mime_types_linux.xml b/indra/newview/skins/default/xui/en/mime_types_linux.xml
index 84aeaf3b54b1a858c9ecfa652899fff85f4cf2f0..7188b1e69937899213ce1bf737d156e017981b20 100644
--- a/indra/newview/skins/default/xui/en/mime_types_linux.xml
+++ b/indra/newview/skins/default/xui/en/mime_types_linux.xml
@@ -130,7 +130,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</scheme>
 	<mimetype name="blank">
@@ -163,7 +163,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/*">
@@ -174,7 +174,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="image/*">
@@ -196,7 +196,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="application/javascript">
@@ -218,7 +218,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="application/pdf">
@@ -295,7 +295,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="audio/mpeg">
@@ -306,7 +306,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="audio/x-aiff">
@@ -317,7 +317,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="audio/x-wav">
@@ -328,7 +328,7 @@
 			audio
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/bmp">
@@ -438,7 +438,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/mp4">
@@ -449,7 +449,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="video/quicktime">
@@ -460,7 +460,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/x-ms-asf">
@@ -471,7 +471,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype name="video/x-ms-wmv">
@@ -482,7 +482,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="video/x-msvideo">
@@ -493,7 +493,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_gstreamer
+			media_plugin_libvlc
 		</impl>
 	</mimetype>
 </mimetypes>
diff --git a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
index eb67d076016e279c0774ce3def8d3e26744d0b76..068e4420bc02296149b93cad7a02f54a121fe272 100644
--- a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
@@ -374,9 +374,11 @@
 		  layout="topleft"
 		  tool_tip="Movie play progress"
 		  width="200">
-		<slider_bar.commit_callback
-			function="MediaCtrl.JumpProgress" />
-	  </slider_bar>
+      <slider_bar.mouse_down_callback
+        function="MediaCtrl.MouseDown" />
+      <slider_bar.mouse_up_callback
+        function="MediaCtrl.MouseUp" />
+    </slider_bar>
 	</layout_panel>
 	<layout_panel
 		name="skip_back"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index f0df5c62a6e29e90442bf27cc372c423fe7dec46..6420644f09d6125c83873acbfba9bebe7e987dfe 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -51,13 +51,14 @@ OpenGL Version: [OPENGL_VERSION]
 J2C Decoder Version: [J2C_VERSION]
 Audio Driver Version: [AUDIO_DRIVER_VERSION]
 LLCEFLib/CEF Version: [LLCEFLIB_VERSION]
+LibVLC Version: [LIBVLC_VERSION]
 Voice Server Version: [VOICE_VERSION]
 	</string>
 	<string name="AboutTraffic">Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%)</string>
 	<string name="AboutTime">[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second,datetime,slt]</string>
 	<string name="ErrorFetchingServerReleaseNotesURL">Error fetching server release notes URL.</string>
 	<string name="BuildConfiguration">Build Configuration</string>
-
+	
 	<!--  progress -->
 	<string name="ProgressRestoring">Restoring...</string>
 	<string name="ProgressChangingResolution">Changing resolution...</string>
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index f3d89bb8660388fe5a7b12821a976086631bf181..66d730d1aca8d0391944147c6328ed9e5ecc2513 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -444,6 +444,11 @@ def construct(self):
             self.path("media_plugin_cef.dll")
             self.end_prefix()
 
+        # Media plugins - LibVLC
+        if self.prefix(src='../media_plugins/libvlc/%s' % self.args['configuration'], dst="llplugin"):
+            self.path("media_plugin_libvlc.dll")
+            self.end_prefix()
+
         # winmm.dll shim
         if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst=""):
             self.path("winmm.dll")
@@ -550,6 +555,12 @@ def construct(self):
             self.path("zh-TW.pak")
             self.end_prefix()
 
+            if self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'release'), dst="llplugin"):
+                self.path("libvlc.dll")
+                self.path("libvlccore.dll")
+                self.path("plugins/")
+                self.end_prefix()
+
         # pull in the crash logger and updater from other projects
         # tag:"crash-logger" here as a cue to the exporter
         self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
@@ -1089,8 +1100,18 @@ def construct(self):
         # plugins
         if self.prefix(src="", dst="bin/llplugin"):
             self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
+            self.path("../media_plugins/libvlc/libmedia_plugin_libvlc.so", "libmedia_plugin_libvlc.so")
             self.end_prefix("bin/llplugin")
 
+        if self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"):
+            self.path( "plugins.dat" )
+            self.path( "*/*.so" )
+            self.end_prefix()
+
+        if self.prefix(src=os.path.join(os.pardir, 'packages', 'lib' ), dst="lib"):
+            self.path( "libvlc*.so*" )
+            self.end_prefix()
+
         # llcommon
         if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"):
             print "Skipping llcommon.so (assuming llcommon was linked statically)"
@@ -1144,7 +1165,7 @@ def package_finish(self):
     def strip_binaries(self):
         if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
             print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
-            self.run_command(r"find %(d)r/bin %(d)r/lib -type f \! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
+            self.run_command(r"find %(d)r/bin %(d)r/lib -type f \! -name update_install \! -name *.dat | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
 
 class Linux_i686_Manifest(LinuxManifest):
     def construct(self):
diff --git a/indra/test/llapp_tut.cpp b/indra/test/llapp_tut.cpp
index aa5c0672e691eacfe7c6c096096d43a08ad966ff..98e714a497a961bb53ff1691f65d9e2280340e88 100644
--- a/indra/test/llapp_tut.cpp
+++ b/indra/test/llapp_tut.cpp
@@ -41,7 +41,7 @@ namespace tut
 		public:
 			virtual bool init() { return true; }
 			virtual bool cleanup() { return true; }
-			virtual bool mainLoop() { return true; }
+			virtual bool frame() { return true; }
 		};
 		LLTestApp* mApp;
 		application()
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 53d4acc9e0157ce76165ba54400aa94247254166..c767d52c7bd3aac30f2d33ec681ac549cf3d42b1 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -42,6 +42,8 @@
 #include "llevents.h"
 #include "lleventfilter.h"
 #include "lleventcoro.h"
+#include "llexception.h"
+#include "stringize.h"
 
 //*********************
 // LLLogin
@@ -128,30 +130,23 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
 
 void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
 {
-	try
-	{
-	LLSD printable_params = login_params;
-	//if(printable_params.has("params") 
-	//	&& printable_params["params"].has("passwd")) 
-	//{
-	//	printable_params["params"]["passwd"] = "*******";
-	//}
-	LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName()
+    LLSD printable_params = login_params;
+    if (printable_params.has("params") 
+        && printable_params["params"].has("passwd")) 
+    {
+        printable_params["params"]["passwd"] = "*******";
+    }
+    try
+    {
+    LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName()
                         << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL;
 
-	// Arriving in SRVRequest state
-    LLEventStream replyPump("SRVreply", true);
-    // Should be an array of one or more uri strings.
-
     LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction"));
     // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used
     // to share them -- but the EXT-3934 fix made it possible for an abandoned
     // SRV response to arrive just as we were expecting the XMLRPC response.
     LLEventStream loginReplyPump("loginreply", true);
 
-    // Loop through the rewrittenURIs, counting attempts along the way.
-    // Because of possible redirect responses, we may make more than one
-    // attempt per rewrittenURIs entry.
     LLSD::Integer attempts = 0;
 
     LLSD request(login_params);
@@ -167,11 +162,11 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
         LLSD progress_data;
         progress_data["attempt"] = attempts;
         progress_data["request"] = request;
-		if(progress_data["request"].has("params")
-			&& progress_data["request"]["params"].has("passwd"))
-		{
-			progress_data["request"]["params"]["passwd"] = "*******";
-		}
+        if (progress_data["request"].has("params")
+            && progress_data["request"]["params"].has("passwd"))
+        {
+            progress_data["request"]["params"]["passwd"] = "*******";
+        }
         sendProgressEvent("offline", "authenticating", progress_data);
 
         // We expect zero or more "Downloading" status events, followed by
@@ -189,8 +184,8 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
             // Still Downloading -- send progress update.
             sendProgressEvent("offline", "downloading");
         }
-	
-		LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
+
+        LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
         status = mAuthResponse["status"].asString();
 
         // Okay, we've received our final status event for this
@@ -202,7 +197,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
             break;
         }
 
-		sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
+        sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
 
         // Here the login service at the current URI is redirecting us
         // to some other URI ("indeterminate" -- why not "redirect"?).
@@ -212,8 +207,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
         request["method"] = mAuthResponse["responses"]["next_method"].asString();
     } // loop back to try the redirected URI
 
-    // Here we're done with redirects for the current rewrittenURIs
-    // entry.
+    // Here we're done with redirects.
     if (status == "Complete")
     {
         // StatusComplete does not imply auth success. Check the
@@ -230,14 +224,14 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
         return;             // Done!
     }
 
-// 	/* Sometimes we end with "Started" here. Slightly slow server?
-// 		* Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
-// 		*/
-// 	if( status == "Started")
-// 	{
-// 		LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
-// 		continue;
-// 	}
+//  /* Sometimes we end with "Started" here. Slightly slow server?
+//   * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
+//   */
+//  if( status == "Started")
+//  {
+//      LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
+//      continue;
+//  }
 
     // If we don't recognize status at all, trouble
     if (! (status == "CURLError"
@@ -250,27 +244,25 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
     }
 
     // Here status IS one of the errors tested above.
-
-    // Here we got through all the rewrittenURIs without succeeding. Tell
-    // caller this didn't work out so well. Of course, the only failure data
-    // we can reasonably show are from the last of the rewrittenURIs.
-
-	// *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an
-	// llsd with no "responses" node. To make the output from an incomplete login symmetrical 
-	// to success, add a data/message and data/reason fields.
-	LLSD error_response;
-	error_response["reason"] = mAuthResponse["status"];
-	error_response["errorcode"] = mAuthResponse["errorcode"];
-	error_response["message"] = mAuthResponse["error"];
-	if(mAuthResponse.has("certificate"))
-	{
-		error_response["certificate"] = mAuthResponse["certificate"];
-	}
-	sendProgressEvent("offline", "fail.login", error_response);
-	}
-	catch (...) {
-		LL_ERRS() << "login exception caught" << LL_ENDL; 
-	}
+    // Tell caller this didn't work out so well.
+
+    // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an
+    // llsd with no "responses" node. To make the output from an incomplete login symmetrical 
+    // to success, add a data/message and data/reason fields.
+    LLSD error_response;
+    error_response["reason"] = mAuthResponse["status"];
+    error_response["errorcode"] = mAuthResponse["errorcode"];
+    error_response["message"] = mAuthResponse["error"];
+    if(mAuthResponse.has("certificate"))
+    {
+        error_response["certificate"] = mAuthResponse["certificate"];
+    }
+    sendProgressEvent("offline", "fail.login", error_response);
+    }
+    catch (...) {
+        CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName()
+                                               << "('" << uri << "', " << printable_params << ")"));
+    }
 }
 
 void LLLogin::Impl::disconnect()
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
index 382689afa0a9f772f020c34199c0c136ee002e04..04e0395c50493780bdd8f0cddb8d8925c554a697 100644
--- a/indra/viewer_components/updater/llupdatedownloader.cpp
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -27,7 +27,7 @@
 
 #include "llupdatedownloader.h"
 #include "httpcommon.h"
-#include <stdexcept>
+#include "llexception.h"
 #include <boost/format.hpp>
 #include <boost/lexical_cast.hpp>
 #include <curl/curl.h>
@@ -85,11 +85,11 @@ class LLUpdateDownloader::Implementation:
 
 namespace {
 	class DownloadError:
-		public std::runtime_error
+		public LLException
 	{
 	public:
 		DownloadError(const char * message):
-			std::runtime_error(message)
+			LLException(message)
 		{
 			; // No op.
 		}
@@ -467,7 +467,7 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u
 
 	if(!mCurl)
 	{
-		throw DownloadError("failed to initialize curl");
+		LLTHROW(DownloadError("failed to initialize curl"));
 	}
     throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOSIGNAL, true));
 	throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_FOLLOWLOCATION, true));
@@ -508,7 +508,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)
 	mHeaderList = curl_slist_append(mHeaderList, rangeHeaderFormat.str().c_str());
 	if(mHeaderList == 0)
 	{
-		throw DownloadError("cannot add Range header");
+		LLTHROW(DownloadError("cannot add Range header"));
 	}
 	throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPHEADER, mHeaderList));
 
@@ -524,7 +524,7 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std
 	mDownloadData["hash"] = hash;
 	mDownloadData["current_version"] = ll_get_version();
 	LLSD path = uri.pathArray();
-	if(path.size() == 0) throw DownloadError("no file path");
+	if(path.size() == 0) LLTHROW(DownloadError("no file path"));
 	std::string fileName = path[path.size() - 1].asString();
 	std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName);
 	mDownloadData["path"] = filePath;
@@ -547,9 +547,9 @@ void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code)
 	if(code != CURLE_OK) {
 		const char * errorString = curl_easy_strerror(code);
 		if(errorString != 0) {
-			throw DownloadError(curl_easy_strerror(code));
+			LLTHROW(DownloadError(curl_easy_strerror(code)));
 		} else {
-			throw DownloadError("unknown curl error");
+			LLTHROW(DownloadError("unknown curl error"));
 		}
 	} else {
 		; // No op.
diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp
index a0e2c0b362172ff2606e09011be84a5afc41f45b..1c7629da232c8d27f79b73d2011592139ae76cda 100644
--- a/indra/viewer_components/updater/llupdateinstaller.cpp
+++ b/indra/viewer_components/updater/llupdateinstaller.cpp
@@ -30,23 +30,25 @@
 #include "llupdateinstaller.h"
 #include "lldir.h" 
 #include "llsd.h"
+#include "llexception.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 {};
-	
-	
+	struct RelocateError: public LLException
+	{
+		RelocateError(): LLException("llupdateinstaller: RelocateError") {}
+	};
+
 	std::string copy_to_temp(std::string const & path)
 	{
 		std::string scriptFile = gDirUtilp->getBaseFileName(path);
 		std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile);
 		apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp);
-		if(status != APR_SUCCESS) throw RelocateError();
+		if(status != APR_SUCCESS) LLTHROW(RelocateError());
 		
 		return newPath;
 	}
diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
index 788955a1b2729af75e7373fd655e90b93099a81d..1665e41e7029546e6b4281807adb6a8d9ad7d731 100644
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -32,6 +32,7 @@
 #include "lltimer.h"
 #include "llupdatechecker.h"
 #include "llupdateinstaller.h"
+#include "llexception.h"
 
 #include <boost/scoped_ptr.hpp>
 #include <boost/weak_ptr.hpp>
@@ -190,8 +191,8 @@ void LLUpdaterServiceImpl::initialize(const std::string&  channel,
 {
 	if(mIsChecking || mIsDownloading)
 	{
-		throw LLUpdaterService::UsageError("LLUpdaterService::initialize call "
-										   "while updater is running.");
+		LLTHROW(LLUpdaterService::UsageError("LLUpdaterService::initialize call "
+											  "while updater is running."));
 	}
 		
 	mChannel = channel;
@@ -222,8 +223,8 @@ void LLUpdaterServiceImpl::startChecking(bool install_if_ready)
 {
 	if(mChannel.empty() || mVersion.empty())
 	{
-		throw LLUpdaterService::UsageError("Set params before call to "
-			"LLUpdaterService::startCheck().");
+		LLTHROW(LLUpdaterService::UsageError("Set params before call to "
+											 "LLUpdaterService::startCheck()."));
 	}
 
 	mIsChecking = true;
diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h
index 95bbe1695ce13c96ddcec7254e62f077c0dac69a..78e8c6b290f682fba51dc36ddaa61bb9b6836c46 100644
--- a/indra/viewer_components/updater/llupdaterservice.h
+++ b/indra/viewer_components/updater/llupdaterservice.h
@@ -29,16 +29,17 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/function.hpp>
 #include "llhasheduniqueid.h"
+#include "llexception.h"
 
 class LLUpdaterServiceImpl;
 
 class LLUpdaterService
 {
 public:
-	class UsageError: public std::runtime_error
+	class UsageError: public LLException
 	{
 	public:
-		UsageError(const std::string& msg) : std::runtime_error(msg) {}
+		UsageError(const std::string& msg) : LLException(msg) {}
 	};
 	
 	// Name of the event pump through which update events will be delivered.
diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp
index 23c29e6b18807be639d60bf2fe3c445da124addf..167acf6ac7b623745613429b08022ea8db981797 100644
--- a/indra/win_crash_logger/llcrashloggerwindows.cpp
+++ b/indra/win_crash_logger/llcrashloggerwindows.cpp
@@ -454,7 +454,7 @@ void LLCrashLoggerWindows::gatherPlatformSpecificFiles()
 	//mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo();  //Not initialized.
 }
 
-bool LLCrashLoggerWindows::mainLoop()
+bool LLCrashLoggerWindows::frame()
 {	
 	LL_INFOS() << "CrashSubmitBehavior is " << mCrashBehavior << LL_ENDL;
 
@@ -503,14 +503,14 @@ bool LLCrashLoggerWindows::mainLoop()
 			TranslateMessage(&msg);
 			DispatchMessage(&msg);
 		}
-		return msg.wParam;
+		return true; // msg.wParam;
 	}
 	else
 	{
 		LL_WARNS() << "Unknown crash behavior " << mCrashBehavior << LL_ENDL;
-		return 1;
+		return true; // 1;
 	}
-	return 0;
+	return true; // 0;
 }
 
 void LLCrashLoggerWindows::updateApplication(const std::string& message)
diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h
index 1812e2737ec1d2f01a6fb46641ba8360a2bd8598..f89b8708dc9386567547b875c518a0ef07522e36 100644
--- a/indra/win_crash_logger/llcrashloggerwindows.h
+++ b/indra/win_crash_logger/llcrashloggerwindows.h
@@ -46,7 +46,7 @@ class LLCrashLoggerWindows : public LLCrashLogger
 	static LLCrashLoggerWindows* sInstance; 
 
 	virtual bool init();
-	virtual bool mainLoop();
+	virtual bool frame();
 	virtual void updateApplication(const std::string& message = LLStringUtil::null);
 	virtual bool cleanup();
 	virtual void gatherPlatformSpecificFiles();
diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp
index 366edd894b970766a0e621e5067b70c954b9f7d2..7466dbb76638a131d86d4f353a019ccd43d06eff 100644
--- a/indra/win_crash_logger/win_crash_logger.cpp
+++ b/indra/win_crash_logger/win_crash_logger.cpp
@@ -52,7 +52,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
 	}
 
 	app.processingLoop();
-	app.mainLoop();
+	app.frame();
 	app.cleanup();
 	LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;
 	return 0;