diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 9739f7c607a7657d43ed5d5fe6adadb9f55f0d48..12fc1bbcfcb92031efe3098e8a1ab8b00ecc487f 100755
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -40,6 +40,7 @@ set(llmessage_SOURCE_FILES
     llchainio.cpp
     llcircuit.cpp
     llclassifiedflags.cpp
+    llcoproceduremanager.cpp
     llcorehttputil.cpp
     llcurl.cpp
     lldatapacker.cpp
@@ -128,6 +129,7 @@ set(llmessage_HEADER_FILES
     llcipher.h
     llcircuit.h
     llclassifiedflags.h
+    llcoproceduremanager.h
     llcorehttputil.h
     llcurl.h
     lldatapacker.h
diff --git a/indra/newview/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
similarity index 96%
rename from indra/newview/llcoproceduremanager.cpp
rename to indra/llmessage/llcoproceduremanager.cpp
index db01c130799724a83250cc4f00deaecaf8898908..062f2e6e426013345d59769ed6866b0974685aef 100644
--- a/indra/newview/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -25,11 +25,7 @@
 * $/LicenseInfo$
 */
 
-#include "llviewerprecompiledheaders.h"
 #include "linden_common.h" 
-
-#include "llviewercontrol.h"
-
 #include "llcoproceduremanager.h"
 
 //=========================================================================
@@ -141,9 +137,13 @@ LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std::
 {
     // Attempt to look up a pool size in the configuration.  If found use that
     std::string keyName = "PoolSize" + poolName;
-    int size = 5;
+    int size = 0;
+
+    if (mPropertyQueryFn && !mPropertyQueryFn.empty())
+    {
+        size = mPropertyQueryFn(keyName);
+    }
 
-    size = gSavedSettings.getU32(keyName);
     if (size == 0)
     {   // if not found grab the know default... if there is no known 
         // default use a reasonable number like 5.
@@ -152,7 +152,9 @@ LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std::
             size = DEFAULT_POOL_SIZE;
         else
             size = (*it).second;
-        gSavedSettings.declareU32(keyName, size, "Coroutine Pool size for " + poolName, LLControlVariable::PERSIST_ALWAYS);
+
+        if (mPropertyDefineFn && !mPropertyDefineFn.empty())
+            mPropertyDefineFn(keyName, size, "Coroutine Pool size for " + poolName);
         LL_WARNS() << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL;
     }
 
@@ -207,6 +209,12 @@ void LLCoprocedureManager::shutdown(bool hardShutdown)
     mPoolMap.clear();
 }
 
+void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn)
+{
+    mPropertyQueryFn = queryfn;
+    mPropertyDefineFn = updatefn;
+}
+
 //-------------------------------------------------------------------------
 size_t LLCoprocedureManager::countPending() const
 {
diff --git a/indra/newview/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h
similarity index 88%
rename from indra/newview/llcoproceduremanager.h
rename to indra/llmessage/llcoproceduremanager.h
index d7f74af76b21bcf414d77b98375dea4ab617645d..497367b80cdc5713415a1cbd5f27320fcde950a8 100644
--- a/indra/newview/llcoproceduremanager.h
+++ b/indra/llmessage/llcoproceduremanager.h
@@ -37,7 +37,12 @@ class LLCoprocedurePool;
 
 class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
 {
+    friend class LLSingleton < LLCoprocedureManager > ;
+
 public:
+    typedef boost::function<U32(const std::string &)> SettingQuery_t;
+    typedef boost::function<void(const std::string &, U32, const std::string &)> SettingUpdate_t;
+
     typedef boost::function<void(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, const LLUUID &id)> CoProcedure_t;
 
     LLCoprocedureManager();
@@ -60,6 +65,8 @@ class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
     /// an immediate kill on the upload coroutine.
     void shutdown(bool hardShutdown = false);
 
+    void setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn);
+
     /// Returns the number of coprocedures in the queue awaiting processing.
     ///
     size_t countPending() const;
@@ -76,12 +83,16 @@ class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
     size_t count(const std::string &pool) const;
 
 private:
+
     typedef boost::shared_ptr<LLCoprocedurePool> poolPtr_t;
     typedef std::map<std::string, poolPtr_t> poolMap_t;
 
     poolMap_t mPoolMap;
 
     poolPtr_t initializePool(const std::string &poolName);
+
+    SettingQuery_t mPropertyQueryFn;
+    SettingUpdate_t mPropertyDefineFn;
 };
 
 #endif
diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp
index 34c42103593d20e600774b6cd52e097caaf9610d..36a4fc8823742e6419bd5832208a90a898f2e322 100644
--- a/indra/llmessage/llexperiencecache.cpp
+++ b/indra/llmessage/llexperiencecache.cpp
@@ -26,53 +26,51 @@
 #include "llexperiencecache.h"
 
 #include "llavatarname.h"
-#include "llframetimer.h"
 #include "llhttpclient.h"
 #include "llsdserialize.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "lleventfilter.h"
+#include "llcoproceduremanager.h"
+#include "lldir.h"
 #include <set>
 #include <map>
-#include "boost/tokenizer.hpp"
+#include <boost/tokenizer.hpp>
 #include <boost/concept_check.hpp>
 
-
-typedef std::map<LLUUID, LLUUID> KeyMap;
-KeyMap privateToPublicKeyMap;
-
-
-std::string sLookupURL;
-
-typedef std::map<LLUUID, F64> pending_queue_t;
-pending_queue_t sPendingQueue;
-
-int sMaximumLookups = 10;
-
-LLFrameTimer sRequestTimer;
-
-// Periodically clean out expired entries from the cache
-LLFrameTimer sEraseExpiredTimer;
-
-
 //=========================================================================
 namespace LLExperienceCacheImpl
 {
-	bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
 	void mapKeys(const LLSD& legacyKeys);
+    F64 getErrorRetryDeltaTime(S32 status, LLSD headers);
+    bool maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age);
+
+    static const std::string PRIVATE_KEY    = "private_id";
+    static const std::string EXPERIENCE_ID  = "public_id";
+
+    static const std::string MAX_AGE("max-age");
+    static const boost::char_separator<char> EQUALS_SEPARATOR("=");
+    static const boost::char_separator<char> COMMA_SEPARATOR(",");
+
+    // *TODO$: this seems to be tied to mapKeys which is used by bootstrap.... but I don't think that bootstrap is used.
+    typedef std::map<LLUUID, LLUUID> KeyMap;
+    KeyMap privateToPublicKeyMap;
 }
 
 //=========================================================================
 const std::string LLExperienceCache::PRIVATE_KEY	= "private_id";
 const std::string LLExperienceCache::MISSING       	= "DoesNotExist";
 
-const std::string LLExperienceCache::AGENT_ID      	= "agent_id";
-const std::string LLExperienceCache::GROUP_ID      	= "group_id";
+const std::string LLExperienceCache::AGENT_ID      = "agent_id";
+const std::string LLExperienceCache::GROUP_ID      = "group_id";
 const std::string LLExperienceCache::EXPERIENCE_ID	= "public_id";
 const std::string LLExperienceCache::NAME			= "name";
 const std::string LLExperienceCache::PROPERTIES		= "properties";
 const std::string LLExperienceCache::EXPIRES		= "expiration";  
 const std::string LLExperienceCache::DESCRIPTION	= "description";
 const std::string LLExperienceCache::QUOTA         	= "quota";
-const std::string LLExperienceCache::MATURITY      	= "maturity";
-const std::string LLExperienceCache::METADATA      	= "extended_metadata";
+const std::string LLExperienceCache::MATURITY      = "maturity";
+const std::string LLExperienceCache::METADATA      = "extended_metadata";
 const std::string LLExperienceCache::SLURL         	= "slurl";
 
 // should be in sync with experience-api/experiences/models.py
@@ -80,20 +78,51 @@ const int LLExperienceCache::PROPERTY_INVALID		= 1 << 0;
 const int LLExperienceCache::PROPERTY_PRIVILEGED	= 1 << 3;
 const int LLExperienceCache::PROPERTY_GRID			= 1 << 4;
 const int LLExperienceCache::PROPERTY_PRIVATE		= 1 << 5;
-const int LLExperienceCache::PROPERTY_DISABLED		= 1 << 6;  
-const int LLExperienceCache::PROPERTY_SUSPENDED		= 1 << 7;
+const int LLExperienceCache::PROPERTY_DISABLED	= 1 << 6;  
+const int LLExperienceCache::PROPERTY_SUSPENDED	= 1 << 7;
 
 // default values
-const F64 LLExperienceCache::DEFAULT_EXPIRATION		= 600.0;
+const F64 LLExperienceCache::DEFAULT_EXPIRATION	= 600.0;
 const S32 LLExperienceCache::DEFAULT_QUOTA			= 128; // this is megabytes
 
 //=========================================================================
-LLExperienceCache::LLExperienceCache()
+LLExperienceCache::LLExperienceCache():
+    mShutdown(false)
 {
 }
 
 LLExperienceCache::~LLExperienceCache()
 {
+
+}
+
+void LLExperienceCache::initSingleton()
+{
+    mCacheFileName = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
+
+    LL_INFOS("ExperienceCache") << "Loading " << mCacheFileName << LL_ENDL;
+    llifstream cache_stream(mCacheFileName.c_str());
+
+    if (cache_stream.is_open())
+    {
+        cache_stream >> (*this);
+    }
+
+    LLCoros::instance().launch("LLExperienceCache::idleCoro",
+        boost::bind(&LLExperienceCache::idleCoro, this));
+
+}
+
+void LLExperienceCache::cleanup()
+{
+    LL_INFOS("ExperienceCache") << "Saving " << mCacheFileName << LL_ENDL;
+
+    llofstream cache_stream(mCacheFileName.c_str());
+    if (cache_stream.is_open())
+    {
+        cache_stream << (*this);
+    }
+    mShutdown = true;
 }
 
 //-------------------------------------------------------------------------
@@ -110,18 +139,18 @@ void LLExperienceCache::importFile(std::istream& istr)
     for (; it != experiences.endMap(); ++it)
     {
         public_key.set(it->first);
-        sCache[public_key] = it->second;
+        mCache[public_key] = it->second;
     }
 
-    LL_DEBUGS("ExperienceCache") << "importFile() loaded " << sCache.size() << LL_ENDL;
+    LL_DEBUGS("ExperienceCache") << "importFile() loaded " << mCache.size() << LL_ENDL;
 }
 
 void LLExperienceCache::exportFile(std::ostream& ostr) const
 {
     LLSD experiences;
 
-    cache_t::const_iterator it = sCache.begin();
-    for (; it != sCache.end(); ++it)
+    cache_t::const_iterator it = mCache.begin();
+    for (; it != mCache.end(); ++it)
     {
         if (!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() ||
             it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID))
@@ -136,7 +165,7 @@ void LLExperienceCache::exportFile(std::ostream& ostr) const
     LLSDSerialize::toPrettyXML(data, ostr);
 }
 
-// *TODO$: Rider: These three functions not seem to be used... it may be useful in testing.
+// *TODO$: Rider: This method does not seem to be used... it may be useful in testing.
 void LLExperienceCache::bootstrap(const LLSD& legacyKeys, int initialExpiration)
 {
 	LLExperienceCacheImpl::mapKeys(legacyKeys);
@@ -166,8 +195,8 @@ LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_i
     if (private_key.isNull())
         return LLUUID::null;
 
-    KeyMap::const_iterator it = privateToPublicKeyMap.find(private_key);
-    if (it == privateToPublicKeyMap.end())
+    LLExperienceCacheImpl::KeyMap::const_iterator it = LLExperienceCacheImpl::privateToPublicKeyMap.find(private_key);
+    if (it == LLExperienceCacheImpl::privateToPublicKeyMap.end())
     {
         if (null_if_not_found)
         {
@@ -182,8 +211,10 @@ LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_i
 //=========================================================================
 void LLExperienceCache::processExperience(const LLUUID& public_key, const LLSD& experience)
 {
-	sCache[public_key]=experience;
-	LLSD & row = sCache[public_key];
+    LL_INFOS("ExperienceCache") << "Processing experience \"" << experience[NAME] << "\" with key " << public_key.asString() << LL_ENDL;
+
+	mCache[public_key]=experience;
+	LLSD & row = mCache[public_key];
 
 	if(row.has(EXPIRES))
 	{
@@ -192,233 +223,148 @@ void LLExperienceCache::processExperience(const LLUUID& public_key, const LLSD&
 
 	if(row.has(EXPERIENCE_ID))
 	{
-		sPendingQueue.erase(row[EXPERIENCE_ID].asUUID());
+		mPendingQueue.erase(row[EXPERIENCE_ID].asUUID());
 	}
 
 	//signal
-	signal_map_t::iterator sig_it =	sSignalMap.find(public_key);
-	if (sig_it != sSignalMap.end())
+	signal_map_t::iterator sig_it =	mSignalMap.find(public_key);
+	if (sig_it != mSignalMap.end())
 	{
 		signal_ptr signal = sig_it->second;
 		(*signal)(experience);
 
-		sSignalMap.erase(public_key);
+		mSignalMap.erase(public_key);
 	}
 }
 
 const LLExperienceCache::cache_t& LLExperienceCache::getCached()
 {
-	return sCache;
-}
-
-void LLExperienceCache::setMaximumLookups(int maximumLookups)
-{
-	sMaximumLookups = maximumLookups;
+	return mCache;
 }
 
-
-bool LLExperienceCache::expirationFromCacheControl(LLSD headers, F64 *expires)
+void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, std::string url, RequestQueue_t requests)
 {
-	// Allow the header to override the default
-	LLSD cache_control_header = headers["cache-control"];
-	if (cache_control_header.isDefined())
-	{
-		S32 max_age = 0;
-		std::string cache_control = cache_control_header.asString();
-		if (max_age_from_cache_control(cache_control, &max_age))
-		{
-			LL_WARNS("ExperienceCache") 
-				<< "got EXPIRES from headers, max_age " << max_age 
-				<< LL_ENDL;
-			F64 now = LLFrameTimer::getTotalSeconds();
-			*expires = now + (F64)max_age;
-			return true;
-		}
-	}
-	return false;
-}
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
 
+    //LL_INFOS("requestExperiencesCoro") << "url: " << url << LL_ENDL;
 
-static const std::string MAX_AGE("max-age");
-static const boost::char_separator<char> EQUALS_SEPARATOR("=");
-static const boost::char_separator<char> COMMA_SEPARATOR(",");
+    LLSD result = httpAdapter->getAndYield(httpRequest, url);
+        
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
 
+    if (!status)
+    {
+        F64 now = LLFrameTimer::getTotalSeconds();
 
-class LLExperienceResponder : public LLHTTPClient::Responder
-{
-public:
-	LLExperienceResponder(const ask_queue_t& keys)
-		:mKeys(keys)
-	{
-
-	}
-
-	/*virtual*/ void httpCompleted()
-	{
-		LLSD experiences = getContent()["experience_keys"];
-		LLSD::array_const_iterator it = experiences.beginArray();
-		for( /**/ ; it != experiences.endArray(); ++it)
-		{
-			const LLSD& row = *it;
-			LLUUID public_key = row[EXPERIENCE_ID].asUUID();
-
-
-			LL_DEBUGS("ExperienceCache") << "Received result for " << public_key 
-				<< " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL ;
-
-			processExperience(public_key, row);
-		}
-
-		LLSD error_ids = getContent()["error_ids"];
-		LLSD::array_const_iterator errIt = error_ids.beginArray();
-		for( /**/ ; errIt != error_ids.endArray() ; ++errIt )
-		{
-			LLUUID id = errIt->asUUID();		
-			LLSD exp;
-			exp[EXPIRES]=DEFAULT_EXPIRATION;
-			exp[EXPERIENCE_ID] = id;
-			exp[PROPERTIES]=PROPERTY_INVALID;
-			exp[MISSING]=true;
-            exp[QUOTA] = DEFAULT_QUOTA;
-
-			processExperience(id, exp);
-			LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL ;
-		}
-
-		LL_DEBUGS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL;
-	}
-
-	/*virtual*/ void httpFailure()
-	{
- 		LL_WARNS("ExperienceCache") << "Request failed "<<getStatus()<<" "<<getReason()<< LL_ENDL;
- 		// We're going to construct a dummy record and cache it for a while,
- 		// either briefly for a 503 Service Unavailable, or longer for other
- 		// errors.
- 		F64 retry_timestamp = errorRetryTimestamp(getStatus());
- 
- 
- 		// Add dummy records for all agent IDs in this request
- 		ask_queue_t::const_iterator it = mKeys.begin();
- 		for ( ; it != mKeys.end(); ++it)
-		{
-
-			LLSD exp = get(it->first);
+        LLSD headers = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+        // build dummy entries for the failed requests
+        for (RequestQueue_t::const_iterator it = requests.begin(); it != requests.end(); ++it)
+        {
+            LLSD exp = get(*it);
             //leave the properties alone if we already have a cache entry for this xp
-            if(exp.isUndefined())
+            if (exp.isUndefined())
             {
-                exp[PROPERTIES]=PROPERTY_INVALID;
+                exp[PROPERTIES] = PROPERTY_INVALID;
             }
-			exp[EXPIRES]=retry_timestamp;
-			exp[EXPERIENCE_ID] = it->first;
-			exp["key_type"] = it->second;
-			exp["uuid"] = it->first;
-			exp["error"] = (LLSD::Integer)getStatus();
+            exp[EXPIRES] = now + LLExperienceCacheImpl::getErrorRetryDeltaTime(status, headers);
+            exp[EXPERIENCE_ID] = *it;
+            exp["key_type"] = EXPERIENCE_ID;
+            exp["uuid"] = *it;
+            exp["error"] = (LLSD::Integer)status.getType();
             exp[QUOTA] = DEFAULT_QUOTA;
 
- 			LLExperienceCache::processExperience(it->first, exp);
- 		}
-
-	}
-
-	// Return time to retry a request that generated an error, based on
-	// error type and headers.  Return value is seconds-since-epoch.
-	F64 errorRetryTimestamp(S32 status)
-	{
+            processExperience(*it, exp);
+        }
+        return;
+    }
 
-		// Retry-After takes priority
-		LLSD retry_after = getResponseHeaders()["retry-after"];
-		if (retry_after.isDefined())
-		{
-			// We only support the delta-seconds type
-			S32 delta_seconds = retry_after.asInteger();
-			if (delta_seconds > 0)
-			{
-				// ...valid delta-seconds
-				return F64(delta_seconds);
-			}
-		}
+    LLSD experiences = result["experience_keys"];
+    
+    for (LLSD::array_const_iterator it = experiences.beginArray(); 
+        it != experiences.endArray(); ++it)
+    {
+        const LLSD& row = *it;
+        LLUUID public_key = row[EXPERIENCE_ID].asUUID();
 
-		// If no Retry-After, look for Cache-Control max-age
-		F64 expires = 0.0;
-		if (LLExperienceCache::expirationFromCacheControl(getResponseHeaders(), &expires))
-		{
-			return expires;
-		}
+        LL_DEBUGS("ExperienceCache") << "Received result for " << public_key
+            << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL;
 
-		// No information in header, make a guess
-		if (status == 503)
-		{
-			// ...service unavailable, retry soon
-			const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
-			return SERVICE_UNAVAILABLE_DELAY;
-		}
-		else if (status == 499)
-		{
-			// ...we were probably too busy, retry quickly
-			const F64 BUSY_DELAY = 10.0; // 10 seconds
-			return BUSY_DELAY;
+        processExperience(public_key, row);
+    }
 
-		}
-		else
-		{
-			// ...other unexpected error
-			const F64 DEFAULT_DELAY = 3600.0; // 1 hour
-			return DEFAULT_DELAY;
-		}
-	}
+    LLSD error_ids = result["error_ids"];
+    
+    for (LLSD::array_const_iterator errIt = error_ids.beginArray(); 
+        errIt != error_ids.endArray(); ++errIt)
+    {
+        LLUUID id = errIt->asUUID();
+        LLSD exp;
+        exp[EXPIRES] = DEFAULT_EXPIRATION;
+        exp[EXPERIENCE_ID] = id;
+        exp[PROPERTIES] = PROPERTY_INVALID;
+        exp[MISSING] = true;
+        exp[QUOTA] = DEFAULT_QUOTA;
+
+        processExperience(id, exp);
+        LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL;
+    }
 
-private:
-	ask_queue_t mKeys;
-};
+}
 
 
 void LLExperienceCache::requestExperiences()
 {
-	if(sAskQueue.empty() || sLookupURL.empty())
-		return;
-
-	F64 now = LLFrameTimer::getTotalSeconds();
+    if (mCapability.empty())
+    {
+        LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+        return;
+    }
 
-	const U32 EXP_URL_SEND_THRESHOLD = 3000;
-	const U32 PAGE_SIZE = EXP_URL_SEND_THRESHOLD/UUID_STR_LENGTH;
+    std::string urlBase = mCapability("GetExperienceInfo");
+    if (urlBase.empty())
+    {
+        LL_WARNS("ExperienceCache") << "No Experience capability." << LL_ENDL;
+        return;
+    }
 
-	std::ostringstream ostr;
+    if (*urlBase.rbegin() != '/')
+    {
+        urlBase += "/";
+    }
+    urlBase += "id/";
 
-	ask_queue_t keys;
 
-	ostr << sLookupURL << "?page_size=" << PAGE_SIZE;
+	F64 now = LLFrameTimer::getTotalSeconds();
 
-	int request_count = 0;
-	while(!sAskQueue.empty() && request_count < sMaximumLookups)
-	{
-		ask_queue_t::iterator it = sAskQueue.begin();
-		const LLUUID& key = it->first;
-		const std::string& key_type = it->second;
+    const U32 EXP_URL_SEND_THRESHOLD = 3000;
+    const U32 PAGE_SIZE = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH;
 
-		ostr << '&' << key_type << '=' << key.asString() ;
-		
-		keys[key]=key_type;
-		request_count++;
+    std::ostringstream ostr;
+    ostr << urlBase << "?page_size=" << PAGE_SIZE;
+    RequestQueue_t  requests;
 
-		sPendingQueue[key] = now;
-			
-		if(ostr.tellp() > EXP_URL_SEND_THRESHOLD)
-		{
-			LL_DEBUGS("ExperienceCache") <<  "requestExperiences() query: " << ostr.str() << LL_ENDL;
-			LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
-			ostr.clear();
-			ostr.str(sLookupURL);
-			ostr << "?page_size=" << PAGE_SIZE;
-			keys.clear();
-		}
-		sAskQueue.erase(it);
-	}
+    while (!mRequestQueue.empty())
+    {
+        RequestQueue_t::iterator it = mRequestQueue.begin();
+        LLUUID key = (*it);
+        mRequestQueue.erase(it);
+        requests.insert(key);
+
+        ostr << "&" << EXPERIENCE_ID << "=" << key.asString();
+        mPendingQueue[key] = now;
+        
+        if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD))
+        {   // request is placed in the coprocedure pool for the ExpCache cache.  Throttling is done by the pool itself.
+            LLCoprocedureManager::getInstance()->enqueueCoprocedure("ExpCache", "Request",
+                boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, ostr.str(), requests) );
+
+            ostr.str(std::string());
+            ostr << urlBase << "?page_size=" << PAGE_SIZE;
+            requests.clear();
+        }
+    }
 
-	if(ostr.tellp() > sLookupURL.size())
-	{
-		LL_DEBUGS("ExperienceCache") <<  "requestExperiences() query 2: " << ostr.str() << LL_ENDL;
-		LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
-	}
 }
 
 
@@ -427,9 +373,9 @@ bool LLExperienceCache::isRequestPending(const LLUUID& public_key)
 	bool isPending = false;
 	const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
 
-	pending_queue_t::const_iterator it = sPendingQueue.find(public_key);
+    PendingQueue_t::const_iterator it = mPendingQueue.find(public_key);
 
-	if(it != sPendingQueue.end())
+	if(it != mPendingQueue.end())
 	{
 		F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS;
 		isPending = (it->second > expire_time);
@@ -438,69 +384,70 @@ bool LLExperienceCache::isRequestPending(const LLUUID& public_key)
 	return isPending;
 }
 
-
-void LLExperienceCache::setLookupURL(const std::string& lookup_url)
+void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t queryfn)
 {
-	sLookupURL = lookup_url;
-	if(!sLookupURL.empty())
-	{
-		sLookupURL += "id/";
-	}
+    mCapability = queryfn;
 }
 
-bool LLExperienceCache::hasLookupURL()
-{
-	return !sLookupURL.empty();
-}
 
-void LLExperienceCache::idle()
+void LLExperienceCache::idleCoro()
 {
-	const F32 SECS_BETWEEN_REQUESTS = 0.1f;
-	if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
-	{
-		return;
-	}
+    const F32 SECS_BETWEEN_REQUESTS = 0.5f;
+    const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
 
-	// Must be large relative to above
-	const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
-	if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
-	{
-		eraseExpired();
-	}
+    LL_INFOS("ExperienceCache") << "Launching Experience cache idle coro." << LL_ENDL;
+    LLEventTimeout timeout;
 
-	if(!sAskQueue.empty())
-	{
-		requestExperiences();
-	}
+    do 
+    {
+        timeout.eventAfter(SECS_BETWEEN_REQUESTS, LLSD());
+        llcoro::waitForEventOn(timeout);
+
+        if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
+        {
+            eraseExpired();
+        }
+
+        if (!mRequestQueue.empty())
+        {
+            requestExperiences();
+        }
+
+    } while (!mShutdown);
+
+    // The coroutine system will likely be shut down by the time we get to this point
+    // (or at least no further cycling will occur on it since the user has decided to quit.)
 }
 
 void LLExperienceCache::erase(const LLUUID& key)
 {
-	cache_t::iterator it = sCache.find(key);
+	cache_t::iterator it = mCache.find(key);
 				
-	if(it != sCache.end())
+	if(it != mCache.end())
 	{
-		sCache.erase(it);
+		mCache.erase(it);
 	}
 }
 
 void LLExperienceCache::eraseExpired()
 {
 	F64 now = LLFrameTimer::getTotalSeconds();
-	cache_t::iterator it = sCache.begin();
-	while (it != sCache.end())
+	cache_t::iterator it = mCache.begin();
+	while (it != mCache.end())
 	{
 		cache_t::iterator cur = it;
 		LLSD& exp = cur->second;
 		++it;
 
+        //LL_INFOS("ExperienceCache") << "Testing experience \"" << exp[NAME] << "\" with exp time " << exp[EXPIRES].asReal() << "(now = " << now << ")" << LL_ENDL;
+
 		if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now)
 		{
             if(!exp.has(EXPERIENCE_ID))
 			{
                 LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ;
-                sCache.erase(cur);
-				}
+                mCache.erase(cur);
+			}
             else
             {
                 LLUUID id = exp[EXPERIENCE_ID].asUUID();
@@ -512,7 +459,7 @@ void LLExperienceCache::eraseExpired()
 				else
 				{
                     LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ;
-					sCache.erase(cur);
+					mCache.erase(cur);
 				}
 			}
 		}
@@ -521,11 +468,11 @@ void LLExperienceCache::eraseExpired()
 	
 bool LLExperienceCache::fetch(const LLUUID& key, bool refresh/* = true*/)
 {
-	if(!key.isNull() && !isRequestPending(key) && (refresh || sCache.find(key)==sCache.end()))
+	if(!key.isNull() && !isRequestPending(key) && (refresh || mCache.find(key)==mCache.end()))
 	{
-		LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL ;
-		sAskQueue[key]=EXPERIENCE_ID;
+		LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL;
 
+        mRequestQueue.insert(key);
 		return true;
 	}
 	return false;
@@ -549,13 +496,12 @@ const LLSD& LLExperienceCache::get(const LLUUID& key)
 	
 	if(key.isNull()) 
 		return empty;
-	cache_t::const_iterator it = sCache.find(key);
+	cache_t::const_iterator it = mCache.find(key);
 
-	if (it != sCache.end())
+	if (it != mCache.end())
 	{
 		return it->second;
 	}
-
 	fetch(key);
 
 	return empty;
@@ -565,8 +511,8 @@ void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::Callback_t slo
 	if(key.isNull()) 
 		return;
 
-	cache_t::const_iterator it = sCache.find(key);
-	if (it != sCache.end())
+	cache_t::const_iterator it = mCache.find(key);
+	if (it != mCache.end())
 	{
 		// ...name already exists in cache, fire callback now
 		callback_signal_t signal;
@@ -580,28 +526,10 @@ void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::Callback_t slo
 
 	signal_ptr signal = signal_ptr(new callback_signal_t());
 	
-	std::pair<signal_map_t::iterator, bool> result = sSignalMap.insert(signal_map_t::value_type(key, signal));
+	std::pair<signal_map_t::iterator, bool> result = mSignalMap.insert(signal_map_t::value_type(key, signal));
 	if (!result.second)
-		signal = result.first.second;
+		signal = (*result.first).second;
 	signal->connect(slot);
-	
-#if 0
-	// always store additional callback, even if request is pending
-	signal_map_t::iterator sig_it = sSignalMap.find(key);
-	if (sig_it == sSignalMap.end())
-	{
-		// ...new callback for this id
-		signal_ptr signal = signal_ptr(new callback_signal_t());
-		signal->connect(slot);
-		sSignalMap[key] = signal;
-	}
-	else
-	{
-		// ...existing callback, bind additional slot
-		callback_signal_t* signal = sig_it->second;
-		signal->connect(slot);
-	}
-#endif
 }
 
 //=========================================================================
@@ -610,14 +538,71 @@ void LLExperienceCacheImpl::mapKeys(const LLSD& legacyKeys)
 	LLSD::array_const_iterator exp = legacyKeys.beginArray();
 	for (/**/; exp != legacyKeys.endArray(); ++exp)
 	{
-		if (exp->has(LLExperienceCache::EXPERIENCE_ID) && exp->has(LLExperienceCache::PRIVATE_KEY))
+        if (exp->has(LLExperienceCacheImpl::EXPERIENCE_ID) && exp->has(LLExperienceCacheImpl::PRIVATE_KEY))
 		{
-			privateToPublicKeyMap[(*exp)[LLExperienceCache::PRIVATE_KEY].asUUID()] = (*exp)[LLExperienceCache::EXPERIENCE_ID].asUUID();
+            LLExperienceCacheImpl::privateToPublicKeyMap[(*exp)[LLExperienceCacheImpl::PRIVATE_KEY].asUUID()] = 
+                (*exp)[LLExperienceCacheImpl::EXPERIENCE_ID].asUUID();
 		}
 	}
 }
 
-bool LLExperienceCacheImpl::max_age_from_cache_control(const std::string& cache_control, S32 *max_age)
+// Return time to retry a request that generated an error, based on
+// error type and headers.  Return value is seconds-since-epoch.
+F64 LLExperienceCacheImpl::getErrorRetryDeltaTime(S32 status, LLSD headers)
+{
+
+    // Retry-After takes priority
+    LLSD retry_after = headers["retry-after"];
+    if (retry_after.isDefined())
+    {
+        // We only support the delta-seconds type
+        S32 delta_seconds = retry_after.asInteger();
+        if (delta_seconds > 0)
+        {
+            // ...valid delta-seconds
+            return F64(delta_seconds);
+        }
+    }
+
+    // If no Retry-After, look for Cache-Control max-age
+    // Allow the header to override the default
+    LLSD cache_control_header = headers["cache-control"];
+    if (cache_control_header.isDefined())
+    {
+        S32 max_age = 0;
+        std::string cache_control = cache_control_header.asString();
+        if (LLExperienceCacheImpl::maxAgeFromCacheControl(cache_control, &max_age))
+        {
+            LL_WARNS("ExperienceCache")
+                << "got EXPIRES from headers, max_age " << max_age
+                << LL_ENDL;
+            return (F64)max_age;
+        }
+    }
+
+    // No information in header, make a guess
+    if (status == 503)
+    {
+        // ...service unavailable, retry soon
+        const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
+        return SERVICE_UNAVAILABLE_DELAY;
+    }
+    else if (status == 499)
+    {
+        // ...we were probably too busy, retry quickly
+        const F64 BUSY_DELAY = 10.0; // 10 seconds
+        return BUSY_DELAY;
+
+    }
+    else
+    {
+        // ...other unexpected error
+        const F64 DEFAULT_DELAY = 3600.0; // 1 hour
+        return DEFAULT_DELAY;
+    }
+}
+
+bool LLExperienceCacheImpl::maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age)
 {
 	// Split the string on "," to get a list of directives
 	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h
index 8da038a8c34f3ef3c6c265c3e45f30b8cebaee13..937225a80af890e84b77dbea414be86f0dbc9b64 100644
--- a/indra/llmessage/llexperiencecache.h
+++ b/indra/llmessage/llexperiencecache.h
@@ -31,7 +31,9 @@
 
 #include "linden_common.h"
 #include "llsingleton.h"
+#include "llframetimer.h"
 #include "llsd.h"
+#include "llcorehttputil.h"
 #include <boost/signals2.hpp>
 #include <boost/function.hpp>
 
@@ -44,8 +46,11 @@ class LLExperienceCache: public LLSingleton < LLExperienceCache >
     friend class LLSingleton < LLExperienceCache > ;
 
 public:
+    typedef boost::function<std::string(const std::string &)> CapabilityQuery_t;
     typedef boost::function<void(const LLSD &)> Callback_t;
 
+    void cleanup();
+
     void erase(const LLUUID& key);
     bool fetch(const LLUUID& key, bool refresh = false);
     void insert(const LLSD& experience_data);
@@ -54,7 +59,39 @@ class LLExperienceCache: public LLSingleton < LLExperienceCache >
     // If name information is in cache, callback will be called immediately.
     void get(const LLUUID& key, Callback_t slot);
 
+    bool isRequestPending(const LLUUID& public_key);
+
+    void setCapabilityQuery(CapabilityQuery_t queryfn);
+
+    static const std::string NAME;			// "name"
+    static const std::string EXPERIENCE_ID;	// "public_id"
+    static const std::string AGENT_ID;      // "agent_id"
+    static const std::string GROUP_ID;      // "group_id"
+    static const std::string PROPERTIES;	// "properties"
+    static const std::string EXPIRES;		// "expiration"  
+    static const std::string DESCRIPTION;	// "description"
+    static const std::string QUOTA;         // "quota"
+    static const std::string MATURITY;      // "maturity"
+    static const std::string METADATA;      // "extended_metadata"
+    static const std::string SLURL;         // "slurl"
+
+    static const std::string MISSING;       // "DoesNotExist"
+
+    // should be in sync with experience-api/experiences/models.py
+    static const int PROPERTY_INVALID;		// 1 << 0
+    static const int PROPERTY_PRIVILEGED;	// 1 << 3
+    static const int PROPERTY_GRID;			// 1 << 4
+    static const int PROPERTY_PRIVATE;		// 1 << 5
+    static const int PROPERTY_DISABLED;		// 1 << 6  
+    static const int PROPERTY_SUSPENDED;	// 1 << 7
+
 private:
+    LLExperienceCache();
+    virtual ~LLExperienceCache();
+
+    virtual void initSingleton();
+
+
     // Callback types for get() 
     typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t;
 	typedef boost::shared_ptr<callback_signal_t> signal_ptr;
@@ -64,63 +101,43 @@ class LLExperienceCache: public LLSingleton < LLExperienceCache >
 	typedef std::map<LLUUID, signal_ptr> signal_map_t;
 	typedef std::map<LLUUID, LLSD> cache_t;
 	
-	typedef std::set<LLUUID> ask_queue_t;
-	
-	
+	typedef std::set<LLUUID> RequestQueue_t;
+    typedef std::map<LLUUID, F64> PendingQueue_t;
+
 	//--------------------------------------------
 	static const std::string PRIVATE_KEY;	// "private_id"
-	static const std::string MISSING;       // "DoesNotExist"
-	
-	static const std::string AGENT_ID;      // "agent_id"
-	static const std::string GROUP_ID;      // "group_id"
-	static const std::string EXPERIENCE_ID;	// "public_id"
-	static const std::string NAME;			// "name"
-	static const std::string PROPERTIES;	// "properties"
-	static const std::string EXPIRES;		// "expiration"  
-	static const std::string DESCRIPTION;	// "description"
-	static const std::string QUOTA;         // "quota"
-	static const std::string MATURITY;      // "maturity"
-	static const std::string METADATA;      // "extended_metadata"
-	static const std::string SLURL;         // "slurl"
-	
-	// should be in sync with experience-api/experiences/models.py
-	static const int PROPERTY_INVALID;		// 1 << 0
-	static const int PROPERTY_PRIVILEGED;	// 1 << 3
-	static const int PROPERTY_GRID;			// 1 << 4
-	static const int PROPERTY_PRIVATE;		// 1 << 5
-	static const int PROPERTY_DISABLED;		// 1 << 6  
-	static const int PROPERTY_SUSPENDED;	// 1 << 7
 	
 	// default values
 	static const F64 DEFAULT_EXPIRATION; 	// 600.0
 	static const S32 DEFAULT_QUOTA; 		// 128 this is megabytes
 	
-//--------------------------------------------
-    LLExperienceCache();
-    virtual ~LLExperienceCache();
-
-    void exportFile(std::ostream& ostr) const;
-    void importFile(std::istream& istr);
-
 //--------------------------------------------
     void processExperience(const LLUUID& public_key, const LLSD& experience);
 
 //--------------------------------------------
-	cache_t			sCache;
-	signal_map_t	sSignalMap;	
-	ask_queue_t		sAskQueue;
-	
+	cache_t			mCache;
+	signal_map_t	mSignalMap;	
+	RequestQueue_t	mRequestQueue;
+    PendingQueue_t  mPendingQueue;
+
+    LLFrameTimer    mRequestTimer;
+    LLFrameTimer    mEraseExpiredTimer;    // Periodically clean out expired entries from the cache
+    CapabilityQuery_t mCapability;
+    std::string     mCacheFileName;
+    bool            mShutdown;
+
+    void idleCoro();
 	void eraseExpired();
-	
-	void setLookupURL(const std::string& lookup_url);
-	bool hasLookupURL();
+    void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t);
+    void requestExperiences();
 
 	void setMaximumLookups(int maximumLookups);
 
-	void idle();
-	void bootstrap(const LLSD& legacyKeys, int initialExpiration);
-	
+    void bootstrap(const LLSD& legacyKeys, int initialExpiration);
+    void exportFile(std::ostream& ostr) const;
+    void importFile(std::istream& istr);
 
+    // 
 	const cache_t& getCached();
 
 	// maps an experience private key to the experience id
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 259fbde80601d912826f03ce09e56c5e5ad23bbf..d192aac4487745993b9e9d8d7c7c05e0bfac4889 100755
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -11,11 +11,13 @@ include(LLMessage)
 include(LLCoreHttp)
 include(LLRender)
 include(LLWindow)
+include(LLCoreHttp)
 include(LLVFS)
 include(LLXML)
 
 include_directories(
     ${LLCOMMON_INCLUDE_DIRS}
+    ${LLCOREHTTP_INCLUDE_DIRS}
     ${LLIMAGE_INCLUDE_DIRS}
     ${LLINVENTORY_INCLUDE_DIRS}
     ${LLMATH_INCLUDE_DIRS}
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index eb7f98e6187565520908dce19b463f09b80bdd1b..e76f2a15505bb8f455606bf3b7ad0b132374737b 100755
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -1430,7 +1430,7 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const
         return LLTrans::getString("ExperienceNameNull");
     }
 
-    const LLSD& experience_details = LLExperienceCache::get(experience_id);
+    const LLSD& experience_details = LLExperienceCache::getInstance()->get(experience_id);
     if(!experience_details.isUndefined())
     {
 		std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
@@ -1438,7 +1438,7 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const
     }
 
     addObserver(experience_id_string, url, cb);
-    LLExperienceCache::get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
+    LLExperienceCache::getInstance()->get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
     return LLTrans::getString("LoadingData");
 
 }
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index fe9c7c0fc06677f3455de5812011b604ae09c7df..090879e372aa972f7282c59cd2ceb314320b9979 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -161,7 +161,6 @@ set(viewer_SOURCE_FILES
     llconversationloglistitem.cpp
     llconversationmodel.cpp
     llconversationview.cpp
-    llcoproceduremanager.cpp
     llcurrencyuimanager.cpp
     llcylinder.cpp
     lldateutil.cpp
@@ -771,7 +770,6 @@ set(viewer_HEADER_FILES
     llconversationloglistitem.h
     llconversationmodel.h
     llconversationview.h
-    llcoproceduremanager.h
     llcurrencyuimanager.h
     llcylinder.h
     lldateutil.h
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index e7dd378edd0ce9ceb2658c307cd2748accc06518..3316f1e6544eb62fa195fed27c0fac5fe938b2c2 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -953,6 +953,15 @@ BOOL LLAgent::inPrelude()
 }
 
 
+std::string LLAgent::getRegionCapability(const std::string &name)
+{
+    if (!mRegionp)
+        return std::string();
+    
+    return mRegionp->getCapability(name);
+}
+
+
 //-----------------------------------------------------------------------------
 // canManageEstate()
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 0ba3dea42783a965177b4e676035b3818bfc45f0..5731f4db89a07ea691accb740bffbc6565a273ee 100755
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -262,6 +262,9 @@ class LLAgent : public LLOldEvents::LLObservable
 	LLHost			getRegionHost() const;
 	BOOL			inPrelude();
 
+    // Capability 
+    std::string     getRegionCapability(const std::string &name); // short hand for if (getRegion()) { getRegion()->getCapability(name) }
+
 	/**
 	 * Register a boost callback to be called when the agent changes regions
 	 * Note that if you need to access a capability for the region, you may need to wait
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 9b9b591cd14d92f4fe5c9702d3e0dfe8565435a7..e13a9d96c7007f2ba1b60809acc97d66baa92b83 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -228,7 +228,7 @@
 #include "llmachineid.h"
 #include "llmainlooprepeater.h"
 
-
+#include "llcoproceduremanager.h"
 #include "llviewereventrecorder.h"
 
 
@@ -755,8 +755,11 @@ void fast_exit(int rc)
 {
 	_exit(rc);
 }
+
+
 }
 
+
 bool LLAppViewer::init()
 {	
 	setupErrorHandling(mSecondInstance);
@@ -1216,6 +1219,12 @@ bool LLAppViewer::init()
 
 	LLAgentLanguage::init();
 
+    /// Tell the Coprocedure manager how to discover and store the pool sizes
+    // what I wanted
+    LLCoprocedureManager::getInstance()->setPropertyMethods(
+        boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1),
+        boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS));
+
 	return true;
 }
 
@@ -4700,31 +4709,6 @@ void LLAppViewer::saveNameCache()
 }
 
 
-void LLAppViewer::saveExperienceCache()
-{
-	std::string filename =
-		gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
-	LL_INFOS("ExperienceCache") << "Saving " << filename << LL_ENDL;
-	llofstream cache_stream(filename.c_str());
-	if(cache_stream.is_open())
-	{
-		LLExperienceCache::exportFile(cache_stream);
-	}
-}
-
-void LLAppViewer::loadExperienceCache()
-{
-	std::string filename =
-		gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
-	LL_INFOS("ExperienceCache") << "Loading " << filename << LL_ENDL;
-	llifstream cache_stream(filename.c_str());
-	if(cache_stream.is_open())
-	{
-		LLExperienceCache::importFile(cache_stream);
-	}
-}
-
-
 /*!	@brief		This class is an LLFrameTimer that can be created with
 				an elapsed time that starts counting up from the given value
 				rather than 0.0.
@@ -4920,7 +4904,6 @@ void LLAppViewer::idle()
 	    // floating throughout the various object lists.
 	    //
 		idleNameCache();
-		idleExperienceCache();
 		idleNetwork();
 	    	        
 
@@ -5350,22 +5333,6 @@ void LLAppViewer::idleNameCache()
 	LLAvatarNameCache::idle();
 }
 
-void LLAppViewer::idleExperienceCache()
-{
-	LLViewerRegion* region = gAgent.getRegion();
-	if (!region) return;
-	
-	std::string lookup_url=region->getCapability("GetExperienceInfo"); 
-	if(!lookup_url.empty() && *lookup_url.rbegin() != '/')
-	{
-		lookup_url += '/';
-	}
-	
-	LLExperienceCache::setLookupURL(lookup_url);
-
-	LLExperienceCache::idle();
-}
-
 //
 // Handle messages, and all message related stuff
 //
@@ -5528,7 +5495,9 @@ void LLAppViewer::disconnectViewer()
 	}
 
 	saveNameCache();
-	saveExperienceCache();
+    LLExperienceCache *expCache = LLExperienceCache::getIfExists();
+    if (expCache)
+        expCache->cleanup();
 
 	// close inventory interface, close all windows
 	LLFloaterInventory::cleanup();
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 718871138eba3350cb37456bd653f51d504b4baf..e8a1ca036b8887bbf294b392b553248a8ff6c624 100755
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -122,9 +122,6 @@ class LLAppViewer : public LLApp
     void loadNameCache();
     void saveNameCache();
 
-	void loadExperienceCache();
-	void saveExperienceCache();
-
 	void removeMarkerFiles();
 	
 	void removeDumpDir();
@@ -233,7 +230,6 @@ class LLAppViewer : public LLApp
     void idle(); 
     void idleShutdown();
 	// update avatar SLID and display name caches
-	void idleExperienceCache();
 	void idleNameCache();
     void idleNetwork();
 
diff --git a/indra/newview/llexperienceassociationresponder.cpp b/indra/newview/llexperienceassociationresponder.cpp
index b50c81eedcf04e777993f8c73c80b23159abc967..cd4a7516b1ba1b4ee834f65e531a953786f09074 100644
--- a/indra/newview/llexperienceassociationresponder.cpp
+++ b/indra/newview/llexperienceassociationresponder.cpp
@@ -83,7 +83,7 @@ void ExperienceAssociationResponder::httpSuccess()
         return;
     }
 
-    LLExperienceCache::get(getContent()["experience"].asUUID(), boost::bind(&ExperienceAssociationResponder::sendResult, this, _1));
+    LLExperienceCache::getInstance()->get(getContent()["experience"].asUUID(), boost::bind(&ExperienceAssociationResponder::sendResult, this, _1));
 
 }
 
diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp
index 197162487d8998af379717da0d88d7a618741c44..8a04f9e4cc59d4b04df2659ae52486d568499d99 100644
--- a/indra/newview/llfloaterexperienceprofile.cpp
+++ b/indra/newview/llfloaterexperienceprofile.cpp
@@ -99,7 +99,7 @@ class LLExperienceHandler : public LLCommandHandler
         if(params.size() != 2 || params[1].asString() != "profile")
             return false;
 
-        LLExperienceCache::get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1));
+        LLExperienceCache::getInstance()->get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1));
         return true;
     }
 
@@ -288,8 +288,8 @@ BOOL LLFloaterExperienceProfile::postBuild()
 
     if (mExperienceId.notNull())
     {
-        LLExperienceCache::fetch(mExperienceId, true);
-        LLExperienceCache::get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback, 
+        LLExperienceCache::getInstance()->fetch(mExperienceId, true);
+        LLExperienceCache::getInstance()->get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback,
             getDerivedHandle<LLFloaterExperienceProfile>(), _1)); 
         
         LLViewerRegion* region = gAgent.getRegion();
@@ -799,8 +799,8 @@ void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content )
     }
  
     refreshExperience(*it);
-    LLExperienceCache::insert(*it);
-    LLExperienceCache::fetch(id, true);
+    LLExperienceCache::getInstance()->insert(*it);
+    LLExperienceCache::getInstance()->fetch(id, true);
 
     if(mSaveCompleteAction==VIEW)
     {
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 370d0f4f1b5d1e7e40e04557d13b1e0e2d06d612..714d8d0e8fbfca36c396dd5f8af5a29d36bda935 100755
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -268,7 +268,7 @@ void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id)
 
 	if (LLUUID::null != mExperienceID)
 	{
-		const LLSD& experience = LLExperienceCache::get(mExperienceID);
+        const LLSD& experience = LLExperienceCache::getInstance()->get(mExperienceID);
 		std::stringstream desc;
 
 		if(experience.isDefined())
diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp
index fc4ee9862e93425d2f73586dadcab99197bacc0a..20fe0c52fa4c31e638d3a505212364916c28d0f1 100644
--- a/indra/newview/llpanelexperiencelisteditor.cpp
+++ b/indra/newview/llpanelexperiencelisteditor.cpp
@@ -183,7 +183,7 @@ void LLPanelExperienceListEditor::onItems()
 		columns[0]["value"] = getString("loading");
 		mItems->addElement(item);
 
-		LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback, 
+        LLExperienceCache::getInstance()->get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
 			getDerivedHandle<LLPanelExperienceListEditor>(), _1));
 	}
 
diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp
index df03ef752616d4869e9ef7f2ec555d00ac784528..9329d900b1e35439a8ab741599041cb2bb9e5ef4 100644
--- a/indra/newview/llpanelexperiencelog.cpp
+++ b/indra/newview/llpanelexperiencelog.cpp
@@ -140,7 +140,7 @@ void LLPanelExperienceLog::refresh()
 				}
 				const LLSD event = dayArray[i];
 				LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
-				const LLSD& experience = LLExperienceCache::get(id);
+                const LLSD& experience = LLExperienceCache::getInstance()->get(id);
 				if(experience.isUndefined()){
 					waiting = true;
 					waiting_id = id;
@@ -168,7 +168,7 @@ void LLPanelExperienceLog::refresh()
 	{
 		mEventList->deleteAllItems();
 		mEventList->setCommentText(getString("loading"));
-		LLExperienceCache::get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
+        LLExperienceCache::getInstance()->get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
 	}
 	else
 	{
diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp
index c7a353a6afecfbce787f62c73c1651a015b6664c..7c19e32e7e04ff7d6cf167cacd2b07dbb1338a41 100644
--- a/indra/newview/llpanelexperiencepicker.cpp
+++ b/indra/newview/llpanelexperiencepicker.cpp
@@ -238,7 +238,7 @@ void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLS
 	LLSD::array_const_iterator it = experiences.beginArray();
 	for ( ; it != experiences.endArray(); ++it)
 	{
-		LLExperienceCache::insert(*it);
+        LLExperienceCache::getInstance()->insert(*it);
 	}
 
 	getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url"));
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index a548d7b705e4958d9c4ff558f6fb29d8ee7eb19c..4f5d21b6beda2f2a95560758dd52e246610e7c46 100755
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -1326,7 +1326,7 @@ void LLLiveLSLEditor::buildExperienceList()
 			position = ADD_TOP;
 		}
 		
-		const LLSD& experience = LLExperienceCache::get(id);
+        const LLSD& experience = LLExperienceCache::getInstance()->get(id);
 		if(experience.isUndefined())
 		{
 			mExperiences->add(getString("loading"), id, position);
@@ -1345,7 +1345,7 @@ void LLLiveLSLEditor::buildExperienceList()
 
 	if(!foundAssociated )
 	{
-		const LLSD& experience = LLExperienceCache::get(associated);
+        const LLSD& experience = LLExperienceCache::getInstance()->get(associated);
 		if(experience.isDefined())
 		{
 			std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
@@ -1366,7 +1366,7 @@ void LLLiveLSLEditor::buildExperienceList()
 	if(last.notNull())
 	{
 		mExperiences->setEnabled(FALSE);
-		LLExperienceCache::get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this));  
+        LLExperienceCache::getInstance()->get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this));
 	}
 	else
 	{
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 46f75c4f57453c37d2607e50880c71dd4523cc84..361cc6c48b17ad38b97ca1492c87e8c42ae463f1 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2821,9 +2821,10 @@ void LLStartUp::initNameCache()
 
 void LLStartUp::initExperiences()
 {   
-    // just a get instance here.  Should trigger loading the cache.
-    LLExperienceCache::getInstance();
-	LLAppViewer::instance()->loadExperienceCache();
+    // Should trigger loading the cache.
+    LLExperienceCache::getInstance()->setCapabilityQuery(
+        boost::bind(&LLAgent::getRegionCapability, &gAgent, _1));
+
 	LLExperienceLog::instance().initialize();
 }
 
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 886725be7912e4d195db604e9a68f9eb57c76196..4e1a86bb71148d0dff2e2d4cc20d55325d3cb706 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -6653,7 +6653,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
 			else if(experienceid.notNull())
 			{
 				payload["experience"]=experienceid;
-				LLExperienceCache::get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
+                LLExperienceCache::getInstance()->get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
 				return;
 			}