diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index e06923279830b8d71a0193fe09b648eebc57479f..233e9d33892998a89091fed99f3c4d6c9cc9f945 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -84,7 +84,7 @@ namespace LLError
 	LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel);
 	LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
 	LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
-	void setTagLevel(const std::string& file_name, LLError::ELevel);
+	LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel);
 	
 	LL_COMMON_API void configure(const LLSD&);
 		// the LLSD can configure all of the settings
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h
index aee7c6ee1e35737bf9c71dfda21d1562950b42d5..71c6fc059192e85fe03ca70fded4c6a8d90ceaba 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -36,7 +36,7 @@
 const S32 LL_VERSION_MAJOR = 1;
 const S32 LL_VERSION_MINOR = 31;
 const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 2822;
+const S32 LL_VERSION_BUILD = 3256;
 
 const char * const LL_CHANNEL = "Second Life Server";
 
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 9a230516d579b15e6a5a89dfb0fbeeb6cad49276..082d054ba2efa5a6d53bf6bed1c8e86d561c4bb4 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -36,7 +36,7 @@
 const S32 LL_VERSION_MAJOR = 2;
 const S32 LL_VERSION_MINOR = 0;
 const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 2822;
+const S32 LL_VERSION_BUILD = 3256;
 
 const char * const LL_CHANNEL = "Second Life Developer";
 
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index e019cdcf21dfee37b13372881b82153131c0915b..2a343fd0c917492734543be636b9522ee734a7a6 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -133,6 +133,7 @@ void LLPluginClassMedia::reset()
 	mCurrentTime = 0.0f;
 	mDuration = 0.0f;
 	mCurrentRate = 0.0f;
+	mLoadedDuration = 0.0f;
 }
 
 void LLPluginClassMedia::idle(void)
@@ -705,6 +706,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			
 
 			bool time_duration_updated = false;
+			int previous_percent = mProgressPercent;
 
 			if(message.hasValue("current_time"))
 			{
@@ -722,11 +724,32 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 				mCurrentRate = message.getValueReal("current_rate");
 			}
 			
+			if(message.hasValue("loaded_duration"))
+			{
+				mLoadedDuration = message.getValueReal("loaded_duration");
+				time_duration_updated = true;
+			}
+			else
+			{
+				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
+				mLoadedDuration = mDuration;
+			}
+			
+			// Calculate a percentage based on the loaded duration and total duration.
+			if(mDuration != 0.0f)	// Don't divide by zero.
+			{
+				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
+			}
+
 			if(time_duration_updated)
 			{
 				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
 			}
 			
+			if(previous_percent != mProgressPercent)
+			{
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
+			}
 		}
 		else if(message_name == "media_status")
 		{
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 97f2a11ef2ccf6fd5d590e532241bf7d8c12d717..697deec353052ad6113dfc4d2244649bc336f02f 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -231,6 +231,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	F64 getCurrentTime(void) const { return mCurrentTime; };
 	F64 getDuration(void) const { return mDuration; };
 	F64 getCurrentPlayRate(void) { return mCurrentRate; };
+	F64 getLoadedDuration(void) const { return mLoadedDuration; };
 	
 	// Initialize the URL history of the plugin by sending
 	// "init_history" message 
@@ -339,6 +340,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	F64				mCurrentTime;
 	F64				mDuration;
 	F64				mCurrentRate;
+	F64				mLoadedDuration;
 	
 };
 
diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
index fbda65120d729708844453c2cc7bb967b349b424..556865f771aea88793db83dcdd7a6135e4fb311b 100644
--- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
+++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
@@ -103,6 +103,7 @@ class MediaPluginQuickTime : public MediaPluginBase
 			message.setValueReal("current_time", getCurrentTime());
 			message.setValueReal("duration", getDuration());
 			message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle)));
+			message.setValueReal("loaded_duration", getLoadedDuration());
 		}
 			
 		sendMessage(message);
@@ -593,6 +594,19 @@ class MediaPluginQuickTime : public MediaPluginBase
 		return (F64)duration / (F64)scale;
 	};
 
+	F64 getLoadedDuration()
+	{
+		TimeValue duration;
+		if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr)
+		{
+			// If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie.
+			duration = GetMovieDuration( mMovieHandle );
+		}
+		TimeValue scale = GetMovieTimeScale( mMovieHandle );
+
+		return (F64)duration / (F64)scale;
+	};
+
 	F64 getCurrentTime()
 	{
 		TimeValue curr_time = GetMovieTime( mMovieHandle, 0 );
diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings
index afa5a877b5b96d2a70cf5925803c0271051c9a65..dceaba9a4343eedec10fe62f2cff7fee2c1e8941 100644
--- a/indra/newview/English.lproj/InfoPlist.strings
+++ b/indra/newview/English.lproj/InfoPlist.strings
@@ -2,6 +2,6 @@
 
 CFBundleName = "Second Life";
 
-CFBundleShortVersionString = "Second Life version 2.0.0.2822";
-CFBundleGetInfoString = "Second Life version 2.0.0.2822, Copyright 2004-2009 Linden Research, Inc.";
+CFBundleShortVersionString = "Second Life version 2.0.0.3256";
+CFBundleGetInfoString = "Second Life version 2.0.0.3256, Copyright 2004-2009 Linden Research, Inc.";
 
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index 1df5102f5f0506c4763e4d8904f8b0677a707df2..7aec8a343d60697b9e5d02297c8add0a4d6cd861 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -32,7 +32,7 @@
 		</dict>
 	</array>
 	<key>CFBundleVersion</key>
-	<string>2.0.0.2822</string>
+	<string>2.0.0.3256</string>
 	<key>CSResourcesFileMapped</key>
 	<true/>
 </dict>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index ecad5dfe4109b3d7ce5064a6b6e3a1166404ebb8..f1e5acdd74b4f4941562d6a845a48038258a463c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9981,7 +9981,7 @@
       <key>Comment</key>
       <string>Versioning Channel Name.</string>
       <key>Persist</key>
-      <integer>1</integer>
+      <integer>0</integer>
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index 3a1b47554cc1a97aec38f5325308bcb208694c92..f797f15865176a6de41ba5e804ac81765f07fa97 100644
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -182,15 +182,20 @@ LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
 LLMediaDataClient::Responder::RetryTimer::~RetryTimer() 
 {
 	LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL;
+
+	// XXX This is weird: Instead of doing the work in tick()  (which re-schedules
+	// a timer, which might be risky), do it here, in the destructor.  Yes, it is very odd.
+	// Instead of retrying, we just put the request back onto the queue
+	LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << "retrying" << LL_ENDL;
+	mResponder->getRequest()->reEnqueue();
+
+	// Release the ref to the responder.
 	mResponder = NULL;
 }
 
 // virtual
 BOOL LLMediaDataClient::Responder::RetryTimer::tick()
 {
-	// Instead of retrying, we just put the request back onto the queue
-	LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << "retrying" << LL_ENDL;
-	mResponder->getRequest()->reEnqueue();
 	// Don't fire again
 	return TRUE;
 }
@@ -357,7 +362,7 @@ BOOL LLMediaDataClient::QueueTimer::tick()
 		return TRUE;
 	}
 
-	LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue is:	  " << queue << LL_ENDL;
+	LL_INFOS("LLMediaDataClient") << "QueueTimer::tick() started, queue is:	  " << queue << LL_ENDL;
 
 	// Peel one off of the items from the queue, and execute request
 	request_ptr_t request = queue.top();
@@ -382,9 +387,13 @@ BOOL LLMediaDataClient::QueueTimer::tick()
 		}
 	}
 	else {
-		if (!object->hasMedia())
+		if (NULL == object) 
 		{
-			LL_INFOS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
+			LL_WARNS("LLMediaDataClient") << "Not Sending request for " << *request << " NULL object!" << LL_ENDL;
+		}
+		else if (!object->hasMedia())
+		{
+			LL_WARNS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
 		}
 	}
 	bool exceeded_retries = request->getRetryCount() > mMDC->mMaxNumRetries;
@@ -414,6 +423,9 @@ void LLMediaDataClient::startQueueTimer()
 		// LLEventTimer automagically takes care of the lifetime of this object
 		new QueueTimer(mQueueTimerDelay, this);
 	}
+	else { 
+		LL_DEBUGS("LLMediaDataClient") << "not starting queue timer (it's already running, right???)" << LL_ENDL;
+	}
 }
 	
 void LLMediaDataClient::stopQueueTimer()
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 3a503f22a0f30c245264b7d97dbe05f5f6030149..6a40c767578ed361dd7a62df3731bfd555832607 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1017,6 +1017,9 @@ void LLViewerMediaImpl::navigateHome()
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type,  bool rediscover_type, bool server_request)
 {
+	// Helpful to have media urls in log file. Shouldn't be spammy.
+	llinfos << "url=" << url << " mime_type=" << mime_type << llendl;
+	
 	if(server_request)
 	{
 		setNavState(MEDIANAVSTATE_SERVER_SENT);
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index 1b1b7cedb1a1d06b01a6c40b753fe1d6d0a4494e..db31714f16632f9f13a771e65a0d6a75831b5445 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -290,6 +290,11 @@ BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 {
 	if(mMediaImpl.notNull())
 		mMediaImpl->handleKeyHere(key, mask);
+
+	if (key == KEY_ESCAPE && mMediaHUD.get())
+	{
+		mMediaHUD.get()->close();
+	}
 	return true;
 }
 
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index 63b76d4f5d1cbe1d781a9d2167169b439b011b9b..433070ce343994999732af519451ce2f844d5c6a 100644
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -134,8 +134,8 @@ TOOLMEDIAOPEN           CURSOR                  "toolmediaopen.cur"
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,0,2822
- PRODUCTVERSION 2,0,0,2822
+ FILEVERSION 2,0,0,3256
+ PRODUCTVERSION 2,0,0,3256
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -152,12 +152,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Linden Lab"
             VALUE "FileDescription", "Second Life"
-            VALUE "FileVersion", "2.0.0.2822"
+            VALUE "FileVersion", "2.0.0.3256"
             VALUE "InternalName", "Second Life"
             VALUE "LegalCopyright", "Copyright © 2001-2008, Linden Research, Inc."
             VALUE "OriginalFilename", "SecondLife.exe"
             VALUE "ProductName", "Second Life"
-            VALUE "ProductVersion", "2.0.0.2822"
+            VALUE "ProductVersion", "2.0.0.3256"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
index a884ed02659198f4cf24165740c6ccd8df04d0ef..445ec7aa344cd13f1f1903a8ed3bf262dea9f969 100644
--- a/indra/newview/tests/llmediadataclient_test.cpp
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -29,6 +29,8 @@
  * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
+
+#include "linden_common.h"
 #include "../llviewerprecompiledheaders.h"
  
 #include <iostream>
@@ -46,7 +48,14 @@
 #include "../../llprimitive/lltextureentry.cpp"
 #include "../../llmessage/tests/llcurl_stub.cpp"
 
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable : 4702) // boost::lexical_cast generates this warning
+#endif
 #include <boost/lexical_cast.hpp>
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
 
 #define VALID_OBJECT_ID   "3607d5c4-644b-4a8a-871a-8b78471af2a2"
 #define VALID_OBJECT_ID_1 "11111111-1111-1111-1111-111111111111"
@@ -186,6 +195,15 @@ class LLMediaDataClientObjectTest : public LLMediaDataClientObject
 	int mNumBounceBacks;
 };
 
+// This special timer delay should ensure that the timer will fire on the very
+// next pump, no matter what (though this does make an assumption about the
+// implementation of LLEventTimer::updateClass()):
+const F32 NO_PERIOD = -1000.0f;
+
+static void pump_timers()
+{
+	LLEventTimer::updateClass();
+}
 
 namespace tut
 {
@@ -194,9 +212,9 @@ namespace tut
 		mediadataclient() {
 			gPostRecords = &mLLSD;
 			
-// 			LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
-// 			LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
-//			LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
+ 			//LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ 			//LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
+			//LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
 		}
 		LLSD mLLSD;
     };
@@ -256,14 +274,13 @@ namespace tut
 		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
 		int num_refs_start = o->getNumRefs();
 		{
-			// queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick()
-			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);  
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
 			mdc->fetchMedia(o);
 
 			// Make sure no posts happened yet...
 			ensure("post records", gPostRecords->size(), 0);
 
-			LLEventTimer::updateClass();
+			::pump_timers();
 		
 			ensure("post records", gPostRecords->size(), 1);
 			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
@@ -288,11 +305,11 @@ namespace tut
 
 		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
 		{
-			// queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick()
-			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);  
+			// queue time w/ no delay ensures that ::pump_timers() will hit the tick()
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);  
 			mdc->updateMedia(o);
 			ensure("post records", gPostRecords->size(), 0);
-			LLEventTimer::updateClass();
+			::pump_timers();
 		
 			ensure("post records", gPostRecords->size(), 1);
 			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
@@ -318,11 +335,11 @@ namespace tut
 
 		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
 		{		
-			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4);
+			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
 			const char *TEST_URL = "http://example.com";
 			mdc->navigate(o, 0, TEST_URL);
 			ensure("post records", gPostRecords->size(), 0);
-			LLEventTimer::updateClass();
+			::pump_timers();
 
 			// ensure no bounce back
 			ensure("bounce back", dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), 0);
@@ -354,7 +371,7 @@ namespace tut
 		LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(
 			_DATA(VALID_OBJECT_ID_3,"2.0","1.0"));
 		{
-			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);  
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);  
 			const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 };
 			mdc->fetchMedia(o1);
 			mdc->fetchMedia(o2);
@@ -364,11 +381,11 @@ namespace tut
 			ensure("post records", gPostRecords->size(), 0);
 
 			// tick 3 times...
-			LLEventTimer::updateClass();
+			::pump_timers();
 			ensure("post records", gPostRecords->size(), 1);
-			LLEventTimer::updateClass();
+			::pump_timers();
 			ensure("post records", gPostRecords->size(), 2);
-			LLEventTimer::updateClass();
+			::pump_timers();
 			ensure("post records", gPostRecords->size(), 3);
 		
 			for( int i=0; i < 3; i++ )
@@ -405,7 +422,7 @@ namespace tut
 		int num_refs_start = o->getNumRefs();
 		{
 			const int NUM_RETRIES = 5;
-			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,NUM_RETRIES);
+			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD,NUM_RETRIES);
 
 			// This should generate a retry
 			mdc->fetchMedia(o);
@@ -418,15 +435,16 @@ namespace tut
 			// Third, fires queue timer again
 			for (int i=0; i<NUM_RETRIES; ++i)
 			{
-				LLEventTimer::updateClass();
-				ensure("post records " + STR(i), gPostRecords->size(), i+1);
-				LLEventTimer::updateClass();
+				::pump_timers();  // Should pump (fire) the queue timer, causing a retry timer to be scheduled
+				// XXX This ensure is not guaranteed, because scheduling a timer might actually get it pumped in the same loop
+				//ensure("post records " + STR(i), gPostRecords->size(), i+1);
+				::pump_timers();  // Should pump (fire) the retry timer, scheduling the queue timer
 			}
 
-			// Do some extre pumps to make sure no other timer work occurs.
-			LLEventTimer::updateClass();
-			LLEventTimer::updateClass();
-			LLEventTimer::updateClass();
+			// Do some extra pumps to make sure no other timer work occurs.
+			::pump_timers();
+			::pump_timers();
+			::pump_timers();
 			
 			// Make sure there were 2 posts
 			ensure("post records after", gPostRecords->size(), NUM_RETRIES);
@@ -458,11 +476,11 @@ namespace tut
 					   FAKE_OBJECT_MEDIA_CAP_URL,
 					   FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR));
 		{		
-			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4);
+			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
 			const char *TEST_URL = "http://example.com";
 			mdc->navigate(o, 0, TEST_URL);
 			ensure("post records", gPostRecords->size(), 0);
-			LLEventTimer::updateClass();
+			::pump_timers();
 
 			// ensure bounce back
 			ensure("bounce back", 
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 41aa13614ec7720f912050bae481dfc69baf312a..f2e89ef062a7333c87e8ec8ec9dcde03ce55f10b 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -626,7 +626,7 @@ def package_finish(self):
         # make sure we don't have stale files laying about
         self.remove(sparsename, finalname)
 
-        self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 500 -layout SPUD' % {
+        self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
                 'sparse':sparsename,
                 'vol':volname})
 
diff --git a/indra/test_apps/llplugintest/CMakeLists.txt b/indra/test_apps/llplugintest/CMakeLists.txt
index 295882c49ad9a1cdd11e44218c871df1054708a1..88c4ba8ad9a739959f6940c49bde2da5f93c2dce 100644
--- a/indra/test_apps/llplugintest/CMakeLists.txt
+++ b/indra/test_apps/llplugintest/CMakeLists.txt
@@ -28,7 +28,7 @@ include_directories(
 
 if (DARWIN)
     include(CMakeFindFrameworks)
-    find_library(CARBON_LIBRARY Carbon)
+    find_library(COREFOUNDATION_LIBRARY CoreFoundation)
 endif (DARWIN)
 
 ### demo_plugin
@@ -261,6 +261,7 @@ set(llmediaplugintest_SOURCE_FILES
 
 add_executable(llmediaplugintest
     WIN32
+    MACOSX_BUNDLE
     ${llmediaplugintest_SOURCE_FILES}
 )
 
@@ -280,6 +281,13 @@ target_link_libraries(llmediaplugintest
   ${PLUGIN_API_WINDOWS_LIBRARIES}
 )
 
+if (DARWIN)
+  # The testbed needs to use a couple of CoreFoundation calls now, to deal with being a bundled app.
+  target_link_libraries(llmediaplugintest
+    ${COREFOUNDATION_LIBRARY}
+  )
+endif (DARWIN)
+
 add_dependencies(llmediaplugintest
   stage_third_party_libs
   SLPlugin
@@ -300,22 +308,64 @@ endif (DARWIN OR LINUX)
 
 # Gather build products of the various dependencies into the build directory for the testbed.
 
+if (DARWIN)
+  # path inside the app bundle where we'll need to copy plugins and other related files
+  set(PLUGINS_DESTINATION_DIR
+    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llmediaplugintest.app/Contents/Resources
+  )
+  
+  # create the Contents/Resources directory
+  add_custom_command(
+    TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    ARGS
+      -E
+      make_directory
+      ${PLUGINS_DESTINATION_DIR}
+    COMMENT "Creating Resources directory in app bundle."
+  )
+
+  # copy the llcommon dylib and its dependencies to Contents/Resources.
+  get_target_property(BUILT_LLCOMMON llcommon LOCATION)
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON}  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${BUILT_LLCOMMON}
+  )
+  # FIXME: these paths should come from somewhere reliable.  The canonical list seems to be in indra/newview/viewer_manifest.py
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib
+  )
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib
+  )
+  add_custom_command(TARGET llmediaplugintest POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libexpat.0.5.0.dylib  ${PLUGINS_DESTINATION_DIR}
+    DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libexpat.0.5.0.dylib
+  )
+else (DARWIN)
+  set(PLUGINS_DESTINATION_DIR
+    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+  )
+endif (DARWIN)
+
 get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION)
 add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN}  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN}  ${PLUGINS_DESTINATION_DIR}
   DEPENDS ${BUILT_SLPLUGIN}
 )
 
 if (DARWIN OR WINDOWS)
   get_target_property(BUILT_WEBKIT_PLUGIN media_plugin_webkit LOCATION)
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN}  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${BUILT_WEBKIT_PLUGIN}
   )
 
   get_target_property(BUILT_QUICKTIME_PLUGIN media_plugin_quicktime LOCATION)
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_QUICKTIME_PLUGIN}  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_QUICKTIME_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${BUILT_QUICKTIME_PLUGIN}
   )
   
@@ -325,16 +375,16 @@ if (DARWIN OR WINDOWS)
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/
     DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
   )
-  # also copy it to the build configuration directory, which is what the mac wants...
+  # also copy it to the same place as SLPlugin, which is what the mac wants...
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
   )
 endif (DARWIN OR WINDOWS)
 
 if (DARWIN)
   add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${PLUGINS_DESTINATION_DIR}
     DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib
   )
 endif (DARWIN)
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index f9568a9b5dd2c611349323a677ddafda09902b7d..ba66b449f39ed160d77addb23eb69f01339e8b7c 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -44,6 +44,7 @@
 
 #if __APPLE__
 	#include <GLUT/glut.h>
+	#include <CoreFoundation/CoreFoundation.h>
 #else
 	#define FREEGLUT_STATIC
 	#include "GL/freeglut.h"
@@ -2111,6 +2112,25 @@ void glutMouseButton( int button, int state, int x, int y )
 //
 int main( int argc, char* argv[] )
 {
+#if LL_DARWIN
+	// Set the current working directory to <application bundle>/Contents/Resources/
+	CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
+	if(resources_url != NULL)
+	{
+		CFStringRef resources_string = CFURLCopyFileSystemPath(resources_url, kCFURLPOSIXPathStyle);
+		CFRelease(resources_url);
+		if(resources_string != NULL)
+		{
+			char buffer[PATH_MAX] = "";
+			if(CFStringGetCString(resources_string, buffer, sizeof(buffer), kCFStringEncodingUTF8))
+			{
+				chdir(buffer);
+			}
+			CFRelease(resources_string);
+		}
+	}
+#endif
+
 	glutInit( &argc, argv );
 	glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );