diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 895400fc89921fb280db5f047b657efbc5f0b718..d7ec4e0eade10e4c0ef905c3eca6642e851a5264 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5882,39 +5882,38 @@ bool handle_teleport_access_blocked(LLSD& llsdBlock)
 	return returnValue;
 }
 
-bool attempt_standard_notification(LLMessageSystem* msgsystem)
+bool handle_home_position_set(std::string notificationID, LLSD& llsdBlock)
 {
-	// if we have additional alert data
-	if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0)
-	{
-		// notification was specified using the new mechanism, so we can just handle it here
-		std::string notificationID;
-		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
-		if (!LLNotifications::getInstance()->templateExists(notificationID))
-		{
-			return false;
-		}
+    std::string snap_filename = gDirUtilp->getLindenUserDir();
+    snap_filename += gDirUtilp->getDirDelimiter();
+    snap_filename += SCREEN_HOME_FILENAME;
+    gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE);
 
-		std::string llsdRaw;
-		LLSD llsdBlock;
-		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
-		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw);
-		if (llsdRaw.length())
-		{
-			std::istringstream llsdData(llsdRaw);
-			if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length()))
-			{
-				llwarns << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << llendl;
-			}
-		}
-		
-		if (
-			(notificationID == "RegionEntryAccessBlocked") ||
-			(notificationID == "LandClaimAccessBlocked") ||
-			(notificationID == "LandBuyAccessBlocked")
-		   )
-		{
-			/*---------------------------------------------------------------------
+    return false;
+}
+
+bool handle_experience_maturity_exceeded(std::string notificationID, LLSD& llsdBlock)
+{
+    if(llsdBlock.has("experience_id"))
+    {
+        llsdBlock["EXPERIENCE_SLURL"]=LLSLURL("experience", llsdBlock["experience_id"].asUUID(), "profile").getSLURLString();
+    }
+    return false;
+}
+
+typedef boost::function<bool (std::string&, LLSD&)> standard_exception_function_t;
+typedef std::map<std::string, standard_exception_function_t> standard_exception_map_t;
+
+standard_exception_map_t sStandardExceptions;
+
+bool process_exceptions(std::string notificationID, LLSD& llsdBlock)
+{
+    if(sStandardExceptions.empty())
+    {
+        sStandardExceptions["RegionEntryAccessBlocked"] = handle_special_notification;
+        sStandardExceptions["LandClaimAccessBlocked"] = handle_special_notification;
+        sStandardExceptions["LandBuyAccessBlocked"] = handle_special_notification;
+        /*---------------------------------------------------------------------
 			 (Commented so a grep will find the notification strings, since
 			 we construct them on the fly; if you add additional notifications,
 			 please update the comment.)
@@ -5939,21 +5938,55 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem)
 				LandBuyAccessBlocked_AdultsOnlyContent
 			 
 			-----------------------------------------------------------------------*/ 
-			if (handle_special_notification(notificationID, llsdBlock))
-			{
-				return true;
-			}
+
+
+        sStandardExceptions["HomePositionSet"] = handle_home_position_set;
+        sStandardExceptions["ExperienceMaturityExceeded"] = handle_experience_maturity_exceeded;
+    }
+
+    standard_exception_map_t::iterator it = sStandardExceptions.find(notificationID);
+
+    if(it == sStandardExceptions.end())
+    {
+        return false;
+    }
+
+    return it->second(notificationID, llsdBlock);
+}
+
+
+
+bool attempt_standard_notification(LLMessageSystem* msgsystem)
+{
+	// if we have additional alert data
+	if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0)
+	{
+		// notification was specified using the new mechanism, so we can just handle it here
+		std::string notificationID;
+		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
+		if (!LLNotifications::getInstance()->templateExists(notificationID))
+		{
+			return false;
 		}
-		// HACK -- handle callbacks for specific alerts.
-		if( notificationID == "HomePositionSet" )
+
+		std::string llsdRaw;
+		LLSD llsdBlock;
+		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
+		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw);
+		if (llsdRaw.length())
 		{
-			// save the home location image to disk
-			std::string snap_filename = gDirUtilp->getLindenUserDir();
-			snap_filename += gDirUtilp->getDirDelimiter();
-			snap_filename += SCREEN_HOME_FILENAME;
-			gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE);
+			std::istringstream llsdData(llsdRaw);
+			if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length()))
+			{
+				llwarns << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << llendl;
+			}
 		}
-		
+
+        if(process_exceptions(notificationID, llsdBlock))
+        {
+            return true;
+        }
+			
 		LLNotificationsUtil::add(notificationID, llsdBlock);
 		return true;
 	}	
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 0f9a728116a26d1e3d3eb7f5d0d309822579750a..0acdf100a4cd239965880767c24aaaf310a15cd9 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6985,10 +6985,22 @@ Is this OK?
        text="Block"/>
     </form>
   </notification>
+  <notification
+    icon="notify.tga"
+    name="ExperienceMaturityExceeded"
+    persist="false"
+    type="notify">
+You have declined participation in the following experience which exceeds your content ratings preferences:
+[EXPERIENCE_SLURL]
+    <form name="form">
+      <ignore name="ignore"
+              text="Experience declined due to content ratings"/>
+    </form>
+  </notification>
   <notification
    icon="notify.tga"
    name="ScriptQuestionExperience"
-   persist="true"
+   persist="false"
    type="notify">
 &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos;, an object owned by &apos;[NAME]&apos;, requests your participation in the [GRID_WIDE]experience: