diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1fea6dea9f3b493cd4c827486f1fd41d22b77b67..746991a6f0623d0963e7525cb3fb31c59fe9242c 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -199,6 +199,7 @@ set(viewer_SOURCE_FILES
     llfilteredwearablelist.cpp
     llfirstuse.cpp
     llflexibleobject.cpp
+    llflickrconnect.cpp
     llfloaterabout.cpp
     llfloaterbvhpreview.cpp
     llfloaterauction.cpp
@@ -228,6 +229,7 @@ set(viewer_SOURCE_FILES
     llfloatereditwater.cpp
     llfloaterenvironmentsettings.cpp
     llfloaterevent.cpp
+    llfloaterflickr.cpp
     llfloaterfonttest.cpp
     llfloatergesture.cpp
     llfloatergodtools.cpp
@@ -286,6 +288,7 @@ set(viewer_SOURCE_FILES
     llfloatertos.cpp
     llfloatertoybox.cpp
     llfloatertranslationsettings.cpp
+    llfloatertwitter.cpp
     llfloateruipreview.cpp
     llfloaterurlentry.cpp
     llfloatervoiceeffect.cpp
@@ -567,6 +570,7 @@ set(viewer_SOURCE_FILES
     lltransientdockablefloater.cpp
     lltransientfloatermgr.cpp
     lltranslate.cpp
+    lltwitterconnect.cpp
     lluilistener.cpp
     lluploaddialog.cpp
     lluploadfloaterobservers.cpp
@@ -787,6 +791,7 @@ set(viewer_HEADER_FILES
     llfilteredwearablelist.h
     llfirstuse.h
     llflexibleobject.h
+    llflickrconnect.h
     llfloaterabout.h
     llfloaterbvhpreview.h
     llfloaterauction.h
@@ -816,6 +821,7 @@ set(viewer_HEADER_FILES
     llfloatereditwater.h
     llfloaterenvironmentsettings.h
     llfloaterevent.h
+    llfloaterflickr.h
     llfloaterfonttest.h
     llfloatergesture.h
     llfloatergodtools.h
@@ -874,6 +880,7 @@ set(viewer_HEADER_FILES
     llfloatertos.h
     llfloatertoybox.h
     llfloatertranslationsettings.h
+    llfloatertwitter.h
     llfloateruipreview.h
     llfloaterurlentry.h
     llfloatervoiceeffect.h
@@ -1145,6 +1152,7 @@ set(viewer_HEADER_FILES
     lltransientdockablefloater.h
     lltransientfloatermgr.h
     lltranslate.h
+    lltwitterconnect.h
     lluiconstants.h
     lluilistener.h
     lluploaddialog.h
diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml
index 60c942094aad44fcc98f66c0a29ae3da1975dfd2..f4e9cc0136c1c3bfd2d78a9375e2bb72442ae49b 100755
--- a/indra/newview/app_settings/commands.xml
+++ b/indra/newview/app_settings/commands.xml
@@ -226,6 +226,26 @@
            is_running_function="Floater.IsOpen"
            is_running_parameters="social"
            />
+  <command name="flickr"
+           available_in_toybox="true"
+           icon="Command_Flickr_Icon"
+           label_ref="Command_Flickr_Label"
+           tooltip_ref="Command_Flickr_Tooltip"
+           execute_function="Floater.ToggleOrBringToFront"
+           execute_parameters="flickr"
+           is_running_function="Floater.IsOpen"
+           is_running_parameters="flickr"
+           />
+  <command name="twitter"
+           available_in_toybox="true"
+           icon="Command_Twitter_Icon"
+           label_ref="Command_Twitter_Label"
+           tooltip_ref="Command_Twitter_Tooltip"
+           execute_function="Floater.ToggleOrBringToFront"
+           execute_parameters="twitter"
+           is_running_function="Floater.IsOpen"
+           is_running_parameters="twitter"
+           />
   <command name="speak"
            available_in_toybox="true"
            icon="Command_Speak_Icon"
diff --git a/indra/newview/app_settings/toolbars.xml b/indra/newview/app_settings/toolbars.xml
index 86f99128156335e29c9951d10754a7541094062e..c65b79affbe2d2589a5e90eff0206f6c2eca93a0 100755
--- a/indra/newview/app_settings/toolbars.xml
+++ b/indra/newview/app_settings/toolbars.xml
@@ -6,7 +6,6 @@
     <command name="speak"/>
     <command name="destinations"/>
     <command name="people"/>
-    <command name="social"/>
     <command name="profile"/>
     <command name="move"/>
     <command name="view"/>
@@ -22,5 +21,6 @@
     <command name="voice"/>
     <command name="minimap"/>
     <command name="snapshot"/>
+    <command name="social"/>
   </left_toolbar>
 </toolbars>
diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp
index f82c5a05a0492137bd183e051c032b17fb46af29..0a662b4671cb5bcf93c73b476c784f1b037e915e 100644
--- a/indra/newview/llfacebookconnect.cpp
+++ b/indra/newview/llfacebookconnect.cpp
@@ -28,6 +28,8 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llfacebookconnect.h"
+#include "llflickrconnect.h"
+#include "lltwitterconnect.h"
 
 #include "llagent.h"
 #include "llcallingcard.h"			// for LLAvatarTracker
@@ -58,7 +60,7 @@ void log_facebook_connect_error(const std::string& request, U32 status, const st
     }
 }
 
-void toast_user_for_success()
+void toast_user_for_facebook_success()
 {
 	LLSD args;
     args["MESSAGE"] = LLTrans::getString("facebook_post_success");
@@ -74,23 +76,58 @@ class LLFacebookConnectHandler : public LLCommandHandler
     
 	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
 	{
-		if (tokens.size() > 0)
+		if (tokens.size() >= 1)
 		{
 			if (tokens[0].asString() == "connect")
 			{
-				// this command probably came from the fbc_web browser, so close it
-				LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web");
-				if (fbc_web)
+				if (tokens.size() >= 2 && tokens[1].asString() == "flickr")
 				{
-					fbc_web->closeFloater();
+					// this command probably came from the flickr_web browser, so close it
+					LLFloater* flickr_web = LLFloaterReg::getInstance("flickr_web");
+					if (flickr_web)
+					{
+						flickr_web->closeFloater();
+					}
+
+					// connect to flickr
+					if (query_map.has("oauth_token"))
+					{
+						LLFlickrConnect::instance().connectToFlickr(query_map["oauth_token"], query_map.get("oauth_verifier"));
+					}
+					return true;
 				}
-
-				// connect to facebook
-				if (query_map.has("code"))
+				else if (tokens.size() >= 2 && tokens[1].asString() == "twitter")
+				{
+					// this command probably came from the twitter_web browser, so close it
+					LLFloater* twitter_web = LLFloaterReg::getInstance("twitter_web");
+					if (twitter_web)
+					{
+						twitter_web->closeFloater();
+					}
+
+					// connect to twitter
+					if (query_map.has("oauth_token"))
+					{
+						LLTwitterConnect::instance().connectToTwitter(query_map["oauth_token"], query_map.get("oauth_verifier"));
+					}
+					return true;
+				}
+				else //if (tokens.size() >= 2 && tokens[1].asString() == "facebook")
 				{
-                    LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state"));
+					// this command probably came from the fbc_web browser, so close it
+					LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web");
+					if (fbc_web)
+					{
+						fbc_web->closeFloater();
+					}
+
+					// connect to facebook
+					if (query_map.has("code"))
+					{
+						LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state"));
+					}
+					return true;
 				}
-				return true;
 			}
 		}
 		return false;
@@ -150,7 +187,7 @@ class LLFacebookShareResponder : public LLHTTPClient::Responder
 	{
 		if (isGoodStatus(status))
 		{
-            toast_user_for_success();
+            toast_user_for_facebook_success();
 			LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL;
 			
 			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED);
@@ -371,40 +408,6 @@ std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, b
 	return url;
 }
 
-std::string LLFacebookConnect::getFlickrConnectURL(const std::string& route, bool include_read_from_master)
-{
-    std::string url("");
-    LLViewerRegion *regionp = gAgent.getRegion();
-    if (regionp)
-    {
-        url = regionp->getCapability("FlickrConnect");
-        url += route;
-    
-        if (include_read_from_master && mReadFromMaster)
-        {
-            url += "?read_from_master=true";
-        }
-    }
-	return url;
-}
-
-std::string LLFacebookConnect::getTwitterConnectURL(const std::string& route, bool include_read_from_master)
-{
-    std::string url("");
-    LLViewerRegion *regionp = gAgent.getRegion();
-    if (regionp)
-    {
-        url = regionp->getCapability("TwitterConnect");
-        url += route;
-    
-        if (include_read_from_master && mReadFromMaster)
-        {
-            url += "?read_from_master=true";
-        }
-    }
-	return url;
-}
-
 void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const std::string& auth_state)
 {
 	LLSD body;
@@ -431,11 +434,6 @@ void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect)
 	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
 	LLHTTPClient::get(getFacebookConnectURL("/connection", true), new LLFacebookConnectedResponder(auto_connect),
 						LLSD(), timeout, follow_redirects);
-	
-	// TEMPORARY FOR TESTING - CHO
-	llinfos << "FlickrConnect URL: " << getFlickrConnectURL() << LL_ENDL;
-	llinfos << "TwitterConnect URL: " << getTwitterConnectURL() << LL_ENDL;
-
 }
 
 void LLFacebookConnect::loadFacebookInfo()
diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h
index c4117174c111a2f4e4813c0d36ffb21ca0edf43a..c157db21781b7ff101297656f62dd5e4b0e128c2 100644
--- a/indra/newview/llfacebookconnect.h
+++ b/indra/newview/llfacebookconnect.h
@@ -90,10 +90,6 @@ class LLFacebookConnect : public LLSingleton<LLFacebookConnect>
 	~LLFacebookConnect() {};
  	std::string getFacebookConnectURL(const std::string& route = "", bool include_read_from_master = false);
 
-	// TEMPORARY FOR TESTING - CHO
- 	std::string getFlickrConnectURL(const std::string& route = "", bool include_read_from_master = false);
- 	std::string getTwitterConnectURL(const std::string& route = "", bool include_read_from_master = false);
-   
     EConnectionState mConnectionState;
 	BOOL mConnected;
 	LLSD mInfo;
diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a21933b6359d48e25df71ca7fc45bf01130221b
--- /dev/null
+++ b/indra/newview/llflickrconnect.cpp
@@ -0,0 +1,477 @@
+/** 
+ * @file llflickrconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Flickr Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llflickrconnect.h"
+
+#include "llagent.h"
+#include "llcallingcard.h"			// for LLAvatarTracker
+#include "llcommandhandler.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
+#include "llurlaction.h"
+#include "llimagepng.h"
+#include "llimagejpeg.h"
+#include "lltrans.h"
+#include "llevents.h"
+#include "llviewerregion.h"
+
+#include "llfloaterwebcontent.h"
+#include "llfloaterreg.h"
+
+boost::scoped_ptr<LLEventPump> LLFlickrConnect::sStateWatcher(new LLEventStream("FlickrConnectState"));
+boost::scoped_ptr<LLEventPump> LLFlickrConnect::sInfoWatcher(new LLEventStream("FlickrConnectInfo"));
+boost::scoped_ptr<LLEventPump> LLFlickrConnect::sContentWatcher(new LLEventStream("FlickrConnectContent"));
+
+// Local functions
+void log_flickr_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
+{
+    // Note: 302 (redirect) is *not* an error that warrants logging
+    if (status != 302)
+    {
+		LL_WARNS("FlickrConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL;
+    }
+}
+
+void toast_user_for_flickr_success()
+{
+	LLSD args;
+    args["MESSAGE"] = LLTrans::getString("flickr_post_success");
+    LLNotificationsUtil::add("FlickrConnect", args);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrConnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrConnectResponder);
+public:
+	
+    LLFlickrConnectResponder()
+    {
+        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+    }
+    
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status))
+		{
+			LL_DEBUGS("FlickrConnect") << "Connect successful. content: " << content << LL_ENDL;
+			
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
+		}
+		else if (status != 302)
+		{
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+            log_flickr_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description"));
+		}
+	}
+    
+    void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+    {
+        if (status == 302)
+        {
+            LLFlickrConnect::instance().openFlickrWeb(content["location"]);
+        }
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrShareResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrShareResponder);
+public:
+    
+	LLFlickrShareResponder()
+	{
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTING);
+	}
+	
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status))
+		{
+            toast_user_for_flickr_success();
+			LL_DEBUGS("FlickrConnect") << "Post successful. content: " << content << LL_ENDL;
+			
+			LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTED);
+		}
+		else if (status == 404)
+		{
+			LLFlickrConnect::instance().connectToFlickr();
+		}
+		else
+		{
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED);
+            log_flickr_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description"));
+		}
+	}
+    
+    void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+    {
+        if (status == 302)
+        {
+            LLFlickrConnect::instance().openFlickrWeb(content["location"]);
+        }
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrDisconnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrDisconnectResponder);
+public:
+ 
+	LLFlickrDisconnectResponder()
+	{
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING);
+	}
+
+	void setUserDisconnected()
+	{
+		// Clear data
+		LLFlickrConnect::instance().clearInfo();
+
+		//Notify state change
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
+	}
+
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status)) 
+		{
+			LL_DEBUGS("FlickrConnect") << "Disconnect successful. content: " << content << LL_ENDL;
+			setUserDisconnected();
+
+		}
+		//User not found so already disconnected
+		else if(status == 404)
+		{
+			LL_DEBUGS("FlickrConnect") << "Already disconnected. content: " << content << LL_ENDL;
+			setUserDisconnected();
+		}
+		else
+		{
+			LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED);
+            log_flickr_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrConnectedResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrConnectedResponder);
+public:
+    
+	LLFlickrConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
+    {
+		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+    }
+    
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status))
+		{
+			LL_DEBUGS("FlickrConnect") << "Connect successful. content: " << content << LL_ENDL;
+            
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
+		}
+		else
+		{
+			// show the flickr login page if not connected yet
+			if (status == 404)
+			{
+				if (mAutoConnect)
+				{
+					LLFlickrConnect::instance().connectToFlickr();
+				}
+				else
+				{
+					LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
+				}
+			}
+            else
+            {
+                LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+				log_flickr_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description"));
+            }
+		}
+	}
+    
+private:
+	bool mAutoConnect;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFlickrInfoResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLFlickrInfoResponder);
+public:
+
+	virtual void completed(U32 status, const std::string& reason, const LLSD& info)
+	{
+		if (isGoodStatus(status))
+		{
+			llinfos << "Flickr: Info received" << llendl;
+			LL_DEBUGS("FlickrConnect") << "Getting Flickr info successful. info: " << info << LL_ENDL;
+			LLFlickrConnect::instance().storeInfo(info);
+		}
+		else
+		{
+			log_flickr_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description"));
+		}
+	}
+
+	void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (status == 302)
+		{
+			LLFlickrConnect::instance().openFlickrWeb(content["location"]);
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+LLFlickrConnect::LLFlickrConnect()
+:	mConnectionState(FLICKR_NOT_CONNECTED),
+	mConnected(false),
+	mInfo(),
+	mRefreshInfo(false),
+	mReadFromMaster(false)
+{
+}
+
+void LLFlickrConnect::openFlickrWeb(std::string url)
+{
+	// Open the URL in an internal browser window without navigation UI
+	LLFloaterWebContent::Params p;
+    p.url(url).show_chrome(true);
+    p.url(url).allow_address_entry(false);
+    p.url(url).allow_back_forward_navigation(false);
+    p.url(url).trusted_content(true);
+	LLFloater *floater = LLFloaterReg::showInstance("flickr_web", p);
+	//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems).
+	//So when showing the internal web browser, set focus to it's containing floater "flickr_web". When a mouse event 
+	//occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus.
+	//flickr_web floater contains the "webbrowser" panel.    JIRA: ACME-744
+	gFocusMgr.setKeyboardFocus( floater );
+
+	//LLUrlAction::openURLExternal(url);
+}
+
+std::string LLFlickrConnect::getFlickrConnectURL(const std::string& route, bool include_read_from_master)
+{
+    std::string url("");
+    LLViewerRegion *regionp = gAgent.getRegion();
+    if (regionp)
+    {
+		//url = "http://pdp15.lindenlab.com/flickr/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO
+        url = regionp->getCapability("FlickrConnect");
+        url += route;
+    
+        if (include_read_from_master && mReadFromMaster)
+        {
+            url += "?read_from_master=true";
+        }
+    }
+	return url;
+}
+
+void LLFlickrConnect::connectToFlickr(const std::string& request_token, const std::string& oauth_verifier)
+{
+	LLSD body;
+	if (!request_token.empty())
+		body["request_token"] = request_token;
+	if (!oauth_verifier.empty())
+		body["oauth_verifier"] = oauth_verifier;
+    
+	LLHTTPClient::put(getFlickrConnectURL("/connection"), body, new LLFlickrConnectResponder());
+}
+
+void LLFlickrConnect::disconnectFromFlickr()
+{
+	LLHTTPClient::del(getFlickrConnectURL("/connection"), new LLFlickrDisconnectResponder());
+}
+
+void LLFlickrConnect::checkConnectionToFlickr(bool auto_connect)
+{
+	const bool follow_redirects = false;
+	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	LLHTTPClient::get(getFlickrConnectURL("/connection", true), new LLFlickrConnectedResponder(auto_connect),
+						LLSD(), timeout, follow_redirects);
+}
+
+void LLFlickrConnect::loadFlickrInfo()
+{
+	if(mRefreshInfo)
+	{
+		const bool follow_redirects = false;
+		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+		LLHTTPClient::get(getFlickrConnectURL("/info", true), new LLFlickrInfoResponder(),
+			LLSD(), timeout, follow_redirects);
+	}
+}
+
+void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level)
+{
+	LLSD body;
+	body["image"] = image_url;
+	body["title"] = title;
+	body["description"] = description;
+	body["tags"] = tags;
+	body["safety_level"] = safety_level;
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::post(getFlickrConnectURL("/share/photo", true), body, new LLFlickrShareResponder());
+}
+
+void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level)
+{
+	std::string imageFormat;
+	if (dynamic_cast<LLImagePNG*>(image.get()))
+	{
+		imageFormat = "png";
+	}
+	else if (dynamic_cast<LLImageJPEG*>(image.get()))
+	{
+		imageFormat = "jpg";
+	}
+	else
+	{
+		llwarns << "Image to upload is not a PNG or JPEG" << llendl;
+		return;
+	}
+	
+	// All this code is mostly copied from LLWebProfile::post()
+	const std::string boundary = "----------------------------0123abcdefab";
+
+	LLSD headers;
+	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
+
+	std::ostringstream body;
+
+	// *NOTE: The order seems to matter.
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"title\"\r\n\r\n"
+			<< title << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"description\"\r\n\r\n"
+			<< description << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"tags\"\r\n\r\n"
+			<< tags << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n"
+			<< safety_level << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << imageFormat << "\"\r\n"
+			<< "Content-Type: image/" << imageFormat << "\r\n\r\n";
+
+	// Insert the image data.
+	// *FIX: Treating this as a string will probably screw it up ...
+	U8* image_data = image->getData();
+	for (S32 i = 0; i < image->getDataSize(); ++i)
+	{
+		body << image_data[i];
+	}
+
+	body <<	"\r\n--" << boundary << "--\r\n";
+
+	// postRaw() takes ownership of the buffer and releases it later.
+	size_t size = body.str().size();
+	U8 *data = new U8[size];
+	memcpy(data, body.str().data(), size);
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::postRaw(getFlickrConnectURL("/share/photo", true), data, size, new LLFlickrShareResponder(), headers);
+}
+
+void LLFlickrConnect::storeInfo(const LLSD& info)
+{
+	mInfo = info;
+	mRefreshInfo = false;
+
+	sInfoWatcher->post(info);
+}
+
+const LLSD& LLFlickrConnect::getInfo() const
+{
+	return mInfo;
+}
+
+void LLFlickrConnect::clearInfo()
+{
+	mInfo = LLSD();
+}
+
+void LLFlickrConnect::setDataDirty()
+{
+	mRefreshInfo = true;
+}
+
+void LLFlickrConnect::setConnectionState(LLFlickrConnect::EConnectionState connection_state)
+{
+	if(connection_state == FLICKR_CONNECTED)
+	{
+		mReadFromMaster = true;
+		setConnected(true);
+		setDataDirty();
+	}
+	else if(connection_state == FLICKR_NOT_CONNECTED)
+	{
+		setConnected(false);
+	}
+	else if(connection_state == FLICKR_POSTED)
+	{
+		mReadFromMaster = false;
+	}
+
+	if (mConnectionState != connection_state)
+	{
+		LLSD state_info;
+		state_info["enum"] = connection_state;
+		sStateWatcher->post(state_info);
+	}
+	
+	mConnectionState = connection_state;
+}
+
+void LLFlickrConnect::setConnected(bool connected)
+{
+	mConnected = connected;
+}
diff --git a/indra/newview/llflickrconnect.h b/indra/newview/llflickrconnect.h
new file mode 100644
index 0000000000000000000000000000000000000000..b127e6e10405deb936e49b310b555fe1bd29d5da
--- /dev/null
+++ b/indra/newview/llflickrconnect.h
@@ -0,0 +1,98 @@
+/** 
+ * @file llflickrconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Flickr Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLICKRCONNECT_H
+#define LL_LLFLICKRCONNECT_H
+
+#include "llsingleton.h"
+#include "llimage.h"
+
+class LLEventPump;
+
+/**
+ * @class LLFlickrConnect
+ *
+ * Manages authentication to, and interaction with, a web service allowing the
+ * the viewer to upload photos to Flickr.
+ */
+class LLFlickrConnect : public LLSingleton<LLFlickrConnect>
+{
+	LOG_CLASS(LLFlickrConnect);
+public:
+    enum EConnectionState
+	{
+		FLICKR_NOT_CONNECTED = 0,
+		FLICKR_CONNECTION_IN_PROGRESS = 1,
+		FLICKR_CONNECTED = 2,
+		FLICKR_CONNECTION_FAILED = 3,
+		FLICKR_POSTING = 4,
+		FLICKR_POSTED = 5,
+		FLICKR_POST_FAILED = 6,
+		FLICKR_DISCONNECTING = 7,
+		FLICKR_DISCONNECT_FAILED = 8
+	};
+	
+	void connectToFlickr(const std::string& request_token = "", const std::string& oauth_verifier = "");	// Initiate the complete Flickr connection. Please use checkConnectionToFlickr() in normal use.
+	void disconnectFromFlickr();																			// Disconnect from the Flickr service.
+    void checkConnectionToFlickr(bool auto_connect = false);												// Check if an access token is available on the Flickr service. If not, call connectToFlickr().
+    
+	void loadFlickrInfo();
+	void uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level);
+	void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level);
+	
+	void storeInfo(const LLSD& info);
+	const LLSD& getInfo() const;
+	void clearInfo();
+	void setDataDirty();
+    
+    void setConnectionState(EConnectionState connection_state);
+	void setConnected(bool connected);
+	bool isConnected() { return mConnected; }
+	bool isTransactionOngoing() { return ((mConnectionState == FLICKR_CONNECTION_IN_PROGRESS) || (mConnectionState == FLICKR_POSTING) || (mConnectionState == FLICKR_DISCONNECTING)); }
+    EConnectionState getConnectionState() { return mConnectionState; }
+    
+    void openFlickrWeb(std::string url);
+
+private:
+	friend class LLSingleton<LLFlickrConnect>;
+
+	LLFlickrConnect();
+	~LLFlickrConnect() {};
+ 	std::string getFlickrConnectURL(const std::string& route = "", bool include_read_from_master = false);
+
+    EConnectionState mConnectionState;
+	BOOL mConnected;
+	LLSD mInfo;
+	bool mRefreshInfo;
+	bool mReadFromMaster;
+	
+	static boost::scoped_ptr<LLEventPump> sStateWatcher;
+	static boost::scoped_ptr<LLEventPump> sInfoWatcher;
+	static boost::scoped_ptr<LLEventPump> sContentWatcher;
+};
+
+#endif // LL_LLFLICKRCONNECT_H
diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..61ebe563a31df427e6586f3c3a839ebbf87a67e5
--- /dev/null
+++ b/indra/newview/llfloaterflickr.cpp
@@ -0,0 +1,703 @@
+/** 
+* @file llfloaterflickr.cpp
+* @brief Implementation of llfloaterflickr
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterflickr.h"
+
+#include "llagent.h"
+#include "llagentui.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "llflickrconnect.h"
+#include "llfloaterreg.h"
+#include "lliconctrl.h"
+#include "llresmgr.h"		// LLLocale
+#include "llsdserialize.h"
+#include "llloadingindicator.h"
+#include "llplugincookiestore.h"
+#include "llslurl.h"
+#include "lltrans.h"
+#include "llsnapshotlivepreview.h"
+#include "llviewerregion.h"
+#include "llviewercontrol.h"
+#include "llviewermedia.h"
+#include "lltabcontainer.h"
+
+static LLRegisterPanelClassWrapper<LLFlickrPhotoPanel> t_panel_photo("llflickrphotopanel");
+static LLRegisterPanelClassWrapper<LLFlickrAccountPanel> t_panel_account("llflickraccountpanel");
+
+const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
+const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=flickr&utm_medium=photo&utm_campaign=slshare";
+const std::string DEFAULT_PHOTO_LINK_TEXT = "Visit this location now";
+const std::string DEFAULT_TAG_TEXT = "secondlife ";
+
+///////////////////////////
+//LLFlickrPhotoPanel///////
+///////////////////////////
+
+LLFlickrPhotoPanel::LLFlickrPhotoPanel() :
+mSnapshotPanel(NULL),
+mResolutionComboBox(NULL),
+mRefreshBtn(NULL),
+mWorkingLabel(NULL),
+mThumbnailPlaceholder(NULL),
+mTitleTextBox(NULL),
+mDescriptionTextBox(NULL),
+mLocationCheckbox(NULL),
+mTagsTextBox(NULL),
+mRatingComboBox(NULL),
+mPostButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLFlickrPhotoPanel::onSend, this));
+	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLFlickrPhotoPanel::onClickNewSnapshot, this));
+}
+
+LLFlickrPhotoPanel::~LLFlickrPhotoPanel()
+{
+	if(mPreviewHandle.get())
+	{
+		mPreviewHandle.get()->die();
+	}
+}
+
+BOOL LLFlickrPhotoPanel::postBuild()
+{
+	setVisibleCallback(boost::bind(&LLFlickrPhotoPanel::onVisibilityChange, this, _2));
+	
+	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
+	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
+	mResolutionComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE));
+	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
+    mWorkingLabel = getChild<LLUICtrl>("working_lbl");
+	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
+	mTitleTextBox = getChild<LLUICtrl>("photo_title");
+	mDescriptionTextBox = getChild<LLUICtrl>("photo_description");
+	mLocationCheckbox = getChild<LLUICtrl>("add_location_cb");
+	mTagsTextBox = getChild<LLUICtrl>("photo_tags");
+	mTagsTextBox->setValue(DEFAULT_TAG_TEXT);
+	mRatingComboBox = getChild<LLUICtrl>("rating_combobox");
+	mPostButton = getChild<LLUICtrl>("post_photo_btn");
+	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn");
+
+	return LLPanel::postBuild();
+}
+
+void LLFlickrPhotoPanel::draw()
+{ 
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+
+    // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts)
+    bool no_ongoing_connection = !(LLFlickrConnect::instance().isTransactionOngoing());
+    mCancelButton->setEnabled(no_ongoing_connection);
+    mTitleTextBox->setEnabled(no_ongoing_connection);
+    mDescriptionTextBox->setEnabled(no_ongoing_connection);
+    mTagsTextBox->setEnabled(no_ongoing_connection);
+    mRatingComboBox->setEnabled(no_ongoing_connection);
+    mResolutionComboBox->setEnabled(no_ongoing_connection);
+    mRefreshBtn->setEnabled(no_ongoing_connection);
+    mLocationCheckbox->setEnabled(no_ongoing_connection);
+    
+    // Display the preview if one is available
+	if (previewp && previewp->getThumbnailImage())
+	{
+		const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect();
+		const S32 thumbnail_w = previewp->getThumbnailWidth();
+		const S32 thumbnail_h = previewp->getThumbnailHeight();
+
+		// calc preview offset within the preview rect
+		const S32 local_offset_x = (thumbnail_rect.getWidth()  - thumbnail_w) / 2 ;
+		const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ;
+
+		// calc preview offset within the floater rect
+        // Hack : To get the full offset, we need to take into account each and every offset of each widgets up to the floater.
+        // This is almost as arbitrary as using a fixed offset so that's what we do here for the sake of simplicity.
+        // *TODO : Get the offset looking through the hierarchy of widgets, should be done in postBuild() so to avoid traversing the hierarchy each time.
+		S32 offset_x = thumbnail_rect.mLeft + local_offset_x - 1;
+		S32 offset_y = thumbnail_rect.mBottom + local_offset_y - 39;
+        
+		mSnapshotPanel->localPointToOtherView(offset_x, offset_y, &offset_x, &offset_y, getParentByType<LLFloater>());
+        
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		// Apply floater transparency to the texture unless the floater is focused.
+		F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+		LLColor4 color = LLColor4::white;
+		gl_draw_scaled_image(offset_x, offset_y, 
+			thumbnail_w, thumbnail_h,
+			previewp->getThumbnailImage(), color % alpha);
+
+		previewp->drawPreviewRect(offset_x, offset_y) ;
+	}
+
+    // Update the visibility of the working (computing preview) label
+    mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate()));
+    
+    // Enable Post if we have a preview to send and no on going connection being processed
+    mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate()) && (mRatingComboBox && mRatingComboBox->getValue().isDefined()));
+    
+    // Draw the rest of the panel on top of it
+	LLPanel::draw();
+}
+
+LLSnapshotLivePreview* LLFlickrPhotoPanel::getPreviewView()
+{
+	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get();
+	return previewp;
+}
+
+void LLFlickrPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
+{
+	bool visible = new_visibility.asBoolean();
+	if (visible)
+	{
+		if (mPreviewHandle.get())
+		{
+			LLSnapshotLivePreview* preview = getPreviewView();
+			if(preview)
+			{
+				lldebugs << "opened, updating snapshot" << llendl;
+				preview->updateSnapshot(TRUE);
+			}
+		}
+		else
+		{
+			LLRect full_screen_rect = getRootView()->getRect();
+			LLSnapshotLivePreview::Params p;
+			p.rect(full_screen_rect);
+			LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
+			mPreviewHandle = previewp->getHandle();	
+
+			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
+			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
+			//previewp->setSnapshotQuality(98);
+			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
+
+			updateControls();
+		}
+	}
+}
+
+void LLFlickrPhotoPanel::onClickNewSnapshot()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	if (previewp)
+	{
+		//setStatus(Impl::STATUS_READY);
+		lldebugs << "updating snapshot" << llendl;
+		previewp->updateSnapshot(TRUE);
+	}
+}
+
+void LLFlickrPhotoPanel::onSend()
+{
+	LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel"); // just in case it is already listening
+	LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrPhotoPanel", boost::bind(&LLFlickrPhotoPanel::onFlickrConnectStateChange, this, _1));
+	
+	// Connect to Flickr if necessary and then post
+	if (LLFlickrConnect::instance().isConnected())
+	{
+		sendPhoto();
+	}
+	else
+	{
+		LLFlickrConnect::instance().checkConnectionToFlickr(true);
+	}
+}
+
+bool LLFlickrPhotoPanel::onFlickrConnectStateChange(const LLSD& data)
+{
+	switch (data.get("enum").asInteger())
+	{
+		case LLFlickrConnect::FLICKR_CONNECTED:
+			sendPhoto();
+			break;
+
+		case LLFlickrConnect::FLICKR_POSTED:
+			LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel");
+			clearAndClose();
+			break;
+	}
+
+	return false;
+}
+
+void LLFlickrPhotoPanel::sendPhoto()
+{
+	// Get the title, description, and tags
+	std::string title = mTitleTextBox->getValue().asString();
+	std::string description = mDescriptionTextBox->getValue().asString();
+	std::string tags = mTagsTextBox->getValue().asString();
+
+	// Add the location if required
+	bool add_location = mLocationCheckbox->getValue().asBoolean();
+	if (add_location)
+	{
+		// Get the SLURL for the location
+		LLSLURL slurl;
+		LLAgentUI::buildSLURL(slurl);
+		std::string slurl_string = slurl.getSLURLString();
+
+		// Add query parameters so Google Analytics can track incoming clicks!
+		slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS;
+
+		slurl_string = "<a href=\"" + slurl_string + "\">" + DEFAULT_PHOTO_LINK_TEXT + "</a>";
+
+		// Add it to the description (pretty crude, but we don't have a better option with photos)
+		if (description.empty())
+			description = slurl_string;
+		else
+			description = description + "\n\n" + slurl_string;
+	}
+
+	// Get the content rating
+	int content_rating = mRatingComboBox->getValue().asInteger();
+
+	// Get the image
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	
+	// Post to Flickr
+	LLFlickrConnect::instance().uploadPhoto(previewp->getFormattedImage(), title, description, tags, content_rating);
+
+	updateControls();
+}
+
+void LLFlickrPhotoPanel::clearAndClose()
+{
+	mTitleTextBox->setValue("");
+	mDescriptionTextBox->setValue("");
+	mTagsTextBox->setValue(DEFAULT_TAG_TEXT);
+
+	LLFloater* floater = getParentByType<LLFloater>();
+	if (floater)
+	{
+		floater->closeFloater();
+	}
+}
+
+void LLFlickrPhotoPanel::updateControls()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	BOOL got_bytes = previewp && previewp->getDataSize() > 0;
+	BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
+	LLSnapshotLivePreview::ESnapshotType shot_type = (previewp ? previewp->getSnapshotType() : LLSnapshotLivePreview::SNAPSHOT_POSTCARD);
+
+	// *TODO: Separate maximum size for Web images from postcards
+	lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
+
+	LLLocale locale(LLLocale::USER_LOCALE);
+	std::string bytes_string;
+	if (got_snap)
+	{
+		LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 );
+	}
+
+	//getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : getString("unknown")); <---uses localized string
+	getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : "unknown");
+	getChild<LLUICtrl>("file_size_label")->setColor(
+		shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD 
+		&& got_bytes
+		&& previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" ));
+
+	updateResolution(FALSE);
+}
+
+void LLFlickrPhotoPanel::updateResolution(BOOL do_update)
+{
+	LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
+
+	std::string sdstring = combobox->getSelectedValue();
+	LLSD sdres;
+	std::stringstream sstream(sdstring);
+	LLSDSerialize::fromNotation(sdres, sstream, sdstring.size());
+
+	S32 width = sdres[0];
+	S32 height = sdres[1];
+
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+	if (previewp && combobox->getCurrentIndex() >= 0)
+	{
+		S32 original_width = 0 , original_height = 0 ;
+		previewp->getSize(original_width, original_height) ;
+
+		if (width == 0 || height == 0)
+		{
+			// take resolution from current window size
+			lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl;
+			previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
+		}
+		else
+		{
+			// use the resolution from the selected pre-canned drop-down choice
+			lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl;
+			previewp->setSize(width, height);
+		}
+
+		checkAspectRatio(width);
+
+		previewp->getSize(width, height);
+		
+		if(original_width != width || original_height != height)
+		{
+			previewp->setSize(width, height);
+
+			// hide old preview as the aspect ratio could be wrong
+			lldebugs << "updating thumbnail" << llendl;
+			
+			previewp->updateSnapshot(FALSE, TRUE);
+			if(do_update)
+			{
+				lldebugs << "Will update controls" << llendl;
+				updateControls();
+                LLFlickrPhotoPanel::onClickNewSnapshot();
+			}
+		}
+		
+	}
+}
+
+void LLFlickrPhotoPanel::checkAspectRatio(S32 index)
+{
+	LLSnapshotLivePreview *previewp = getPreviewView() ;
+
+	BOOL keep_aspect = FALSE;
+
+	if (0 == index) // current window size
+	{
+		keep_aspect = TRUE;
+	}
+	else // predefined resolution
+	{
+		keep_aspect = FALSE;
+	}
+
+	if (previewp)
+	{
+		previewp->mKeepAspectRatio = keep_aspect;
+	}
+}
+
+LLUICtrl* LLFlickrPhotoPanel::getRefreshBtn()
+{
+	return mRefreshBtn;
+}
+
+///////////////////////////
+//LLFlickrAccountPanel//////
+///////////////////////////
+
+LLFlickrAccountPanel::LLFlickrAccountPanel() : 
+mAccountCaptionLabel(NULL),
+mAccountNameLabel(NULL),
+mPanelButtons(NULL),
+mConnectButton(NULL),
+mDisconnectButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLFlickrAccountPanel::onConnect, this));
+	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLFlickrAccountPanel::onDisconnect, this));
+
+	setVisibleCallback(boost::bind(&LLFlickrAccountPanel::onVisibilityChange, this, _2));
+}
+
+BOOL LLFlickrAccountPanel::postBuild()
+{
+	mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
+	mAccountNameLabel = getChild<LLTextBox>("account_name_label");
+	mPanelButtons = getChild<LLUICtrl>("panel_buttons");
+	mConnectButton = getChild<LLUICtrl>("connect_btn");
+	mDisconnectButton = getChild<LLUICtrl>("disconnect_btn");
+
+	return LLPanel::postBuild();
+}
+
+void LLFlickrAccountPanel::draw()
+{
+	LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState();
+
+	//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress
+	bool disconnecting = connection_state == LLFlickrConnect::FLICKR_DISCONNECTING;
+	mDisconnectButton->setEnabled(!disconnecting);
+
+	//Disable the 'connect' button when a connection is in progress
+	bool connecting = connection_state == LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS;
+	mConnectButton->setEnabled(!connecting);
+
+	LLPanel::draw();
+}
+
+void LLFlickrAccountPanel::onVisibilityChange(const LLSD& new_visibility)
+{
+	bool visible = new_visibility.asBoolean();
+
+	if(visible)
+	{
+		LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel");
+		LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectStateChange, this, _1));
+
+		LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel");
+		LLEventPumps::instance().obtain("FlickrConnectInfo").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectInfoChange, this));
+
+		//Connected
+		if(LLFlickrConnect::instance().isConnected())
+		{
+			showConnectedLayout();
+		}
+		//Check if connected (show disconnected layout in meantime)
+		else
+		{
+			showDisconnectedLayout();
+		}
+        if ((LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_NOT_CONNECTED) ||
+            (LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_CONNECTION_FAILED))
+        {
+            LLFlickrConnect::instance().checkConnectionToFlickr();
+        }
+	}
+	else
+	{
+		LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel");
+		LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel");
+	}
+}
+
+bool LLFlickrAccountPanel::onFlickrConnectStateChange(const LLSD& data)
+{
+	if(LLFlickrConnect::instance().isConnected())
+	{
+		//In process of disconnecting so leave the layout as is
+		if(data.get("enum").asInteger() != LLFlickrConnect::FLICKR_DISCONNECTING)
+		{
+			showConnectedLayout();
+		}
+	}
+	else
+	{
+		showDisconnectedLayout();
+	}
+
+	return false;
+}
+
+bool LLFlickrAccountPanel::onFlickrConnectInfoChange()
+{
+	LLSD info = LLFlickrConnect::instance().getInfo();
+	std::string clickable_name;
+
+	//Strings of format [http://www.somewebsite.com Click Me] become clickable text
+	if(info.has("link") && info.has("name"))
+	{
+		clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]";
+	}
+
+	mAccountNameLabel->setText(clickable_name);
+
+	return false;
+}
+
+void LLFlickrAccountPanel::showConnectButton()
+{
+	if(!mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(TRUE);
+		mDisconnectButton->setVisible(FALSE);
+	}
+}
+
+void LLFlickrAccountPanel::hideConnectButton()
+{
+	if(mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(FALSE);
+		mDisconnectButton->setVisible(TRUE);
+	}
+}
+
+void LLFlickrAccountPanel::showDisconnectedLayout()
+{
+	mAccountCaptionLabel->setText(getString("flickr_disconnected"));
+	mAccountNameLabel->setText(std::string(""));
+	showConnectButton();
+}
+
+void LLFlickrAccountPanel::showConnectedLayout()
+{
+	LLFlickrConnect::instance().loadFlickrInfo();
+
+	mAccountCaptionLabel->setText(getString("flickr_connected"));
+	hideConnectButton();
+}
+
+void LLFlickrAccountPanel::onConnect()
+{
+	LLFlickrConnect::instance().checkConnectionToFlickr(true);
+
+	//Clear only the flickr browser cookies so that the flickr login screen appears
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com"); 
+}
+
+void LLFlickrAccountPanel::onDisconnect()
+{
+	LLFlickrConnect::instance().disconnectFromFlickr();
+
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com"); 
+}
+
+////////////////////////
+//LLFloaterFlickr///////
+////////////////////////
+
+LLFloaterFlickr::LLFloaterFlickr(const LLSD& key) : LLFloater(key),
+    mSocialPhotoPanel(NULL),
+    mStatusErrorText(NULL),
+    mStatusLoadingText(NULL),
+    mStatusLoadingIndicator(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterFlickr::onCancel, this));
+}
+
+void LLFloaterFlickr::onCancel()
+{
+    closeFloater();
+}
+
+BOOL LLFloaterFlickr::postBuild()
+{
+    // Keep tab of the Photo Panel
+	mSocialPhotoPanel = static_cast<LLFlickrPhotoPanel*>(getChild<LLUICtrl>("panel_flickr_photo"));
+    // Connection status widgets
+    mStatusErrorText = getChild<LLTextBox>("connection_error_text");
+    mStatusLoadingText = getChild<LLTextBox>("connection_loading_text");
+    mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator");
+	return LLFloater::postBuild();
+}
+
+void LLFloaterFlickr::showPhotoPanel()
+{
+	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mSocialPhotoPanel->getParent());
+	if (!parent)
+	{
+		llwarns << "Cannot find panel container" << llendl;
+		return;
+	}
+
+	parent->selectTabPanel(mSocialPhotoPanel);
+}
+
+// static
+void LLFloaterFlickr::preUpdate()
+{
+	LLFloaterFlickr* instance = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr");
+	if (instance)
+	{
+		//Will set file size text to 'unknown'
+		instance->mSocialPhotoPanel->updateControls();
+	}
+}
+
+// static
+void LLFloaterFlickr::postUpdate()
+{
+	LLFloaterFlickr* instance = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr");
+	if (instance)
+	{
+		//Will set the file size text
+		instance->mSocialPhotoPanel->updateControls();
+
+		// The refresh button is initially hidden. We show it after the first update,
+		// i.e. after snapshot is taken
+		LLUICtrl * refresh_button = instance->mSocialPhotoPanel->getRefreshBtn();
+
+		if (!refresh_button->getVisible())
+		{
+			refresh_button->setVisible(true);
+		}
+		
+	}
+}
+
+void LLFloaterFlickr::draw()
+{
+    if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator)
+    {
+        mStatusErrorText->setVisible(false);
+        mStatusLoadingText->setVisible(false);
+        mStatusLoadingIndicator->setVisible(false);
+        LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState();
+        std::string status_text;
+        
+        switch (connection_state)
+        {
+        case LLFlickrConnect::FLICKR_NOT_CONNECTED:
+            // No status displayed when first opening the panel and no connection done
+        case LLFlickrConnect::FLICKR_CONNECTED:
+            // When successfully connected, no message is displayed
+        case LLFlickrConnect::FLICKR_POSTED:
+            // No success message to show since we actually close the floater after successful posting completion
+            break;
+        case LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS:
+            // Connection loading indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrConnecting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+            break;
+        case LLFlickrConnect::FLICKR_POSTING:
+            // Posting indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrPosting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+			break;
+        case LLFlickrConnect::FLICKR_CONNECTION_FAILED:
+            // Error connecting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrErrorConnecting");
+            mStatusErrorText->setValue(status_text);
+            break;
+        case LLFlickrConnect::FLICKR_POST_FAILED:
+            // Error posting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialFlickrErrorPosting");
+            mStatusErrorText->setValue(status_text);
+            break;
+		case LLFlickrConnect::FLICKR_DISCONNECTING:
+			// Disconnecting loading indicator
+			mStatusLoadingText->setVisible(true);
+			status_text = LLTrans::getString("SocialFlickrDisconnecting");
+			mStatusLoadingText->setValue(status_text);
+			mStatusLoadingIndicator->setVisible(true);
+			break;
+		case LLFlickrConnect::FLICKR_DISCONNECT_FAILED:
+			// Error disconnecting from the service
+			mStatusErrorText->setVisible(true);
+			status_text = LLTrans::getString("SocialFlickrErrorDisconnecting");
+			mStatusErrorText->setValue(status_text);
+			break;
+        }
+    }
+	LLFloater::draw();
+}
+
diff --git a/indra/newview/llfloaterflickr.h b/indra/newview/llfloaterflickr.h
new file mode 100644
index 0000000000000000000000000000000000000000..e9005444d8dfc1dd38a91d75c66e093a7b957bdb
--- /dev/null
+++ b/indra/newview/llfloaterflickr.h
@@ -0,0 +1,127 @@
+/** 
+* @file   llfloaterflickr.h
+* @brief  Header file for llfloaterflickr
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLFLOATERFLICKR_H
+#define LL_LLFLOATERFLICKR_H
+
+#include "llfloater.h"
+#include "lltextbox.h"
+#include "llviewertexture.h"
+
+class LLIconCtrl;
+class LLCheckBoxCtrl;
+class LLSnapshotLivePreview;
+
+class LLFlickrPhotoPanel : public LLPanel
+{
+public:
+	LLFlickrPhotoPanel();
+	~LLFlickrPhotoPanel();
+
+	BOOL postBuild();
+	void draw();
+
+	LLSnapshotLivePreview* getPreviewView();
+	void onVisibilityChange(const LLSD& new_visibility);
+	void onClickNewSnapshot();
+	void onSend();
+	bool onFlickrConnectStateChange(const LLSD& data);
+
+	void sendPhoto();
+	void clearAndClose();
+
+	void updateControls();
+	void updateResolution(BOOL do_update);
+	void checkAspectRatio(S32 index);
+	LLUICtrl* getRefreshBtn();
+
+private:
+	LLHandle<LLView> mPreviewHandle;
+
+	LLUICtrl * mSnapshotPanel;
+	LLUICtrl * mResolutionComboBox;
+	LLUICtrl * mRefreshBtn;
+	LLUICtrl * mWorkingLabel;
+	LLUICtrl * mThumbnailPlaceholder;
+	LLUICtrl * mTitleTextBox;
+	LLUICtrl * mDescriptionTextBox;
+	LLUICtrl * mLocationCheckbox;
+	LLUICtrl * mTagsTextBox;
+	LLUICtrl * mRatingComboBox;
+	LLUICtrl * mPostButton;
+	LLUICtrl* mCancelButton;
+};
+
+class LLFlickrAccountPanel : public LLPanel
+{
+public:
+	LLFlickrAccountPanel();
+	BOOL postBuild();
+	void draw();
+
+private:
+	void onVisibilityChange(const LLSD& new_visibility);
+	bool onFlickrConnectStateChange(const LLSD& data);
+	bool onFlickrConnectInfoChange();
+	void onConnect();
+	void onUseAnotherAccount();
+	void onDisconnect();
+
+	void showConnectButton();
+	void hideConnectButton();
+	void showDisconnectedLayout();
+	void showConnectedLayout();
+
+	LLTextBox * mAccountCaptionLabel;
+	LLTextBox * mAccountNameLabel;
+	LLUICtrl * mPanelButtons;
+	LLUICtrl * mConnectButton;
+	LLUICtrl * mDisconnectButton;
+};
+
+
+class LLFloaterFlickr : public LLFloater
+{
+public:
+	LLFloaterFlickr(const LLSD& key);
+	BOOL postBuild();
+	void draw();
+	void onCancel();
+	
+	void showPhotoPanel();
+
+	static void preUpdate();
+	static void postUpdate();
+
+private:
+	LLFlickrPhotoPanel* mSocialPhotoPanel;
+    LLTextBox* mStatusErrorText;
+    LLTextBox* mStatusLoadingText;
+    LLUICtrl*  mStatusLoadingIndicator;
+};
+
+#endif // LL_LLFLOATERFLICKR_H
+
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index ea385d7baf1b89297f9ec3cea51a76b0b13f7a7e..4701e128d348f1dd2eb22b1d5f8f988aec1ba635 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -32,6 +32,8 @@
 #include "llfacebookconnect.h"
 #include "llfloaterreg.h"
 #include "llfloatersocial.h"
+#include "llfloaterflickr.h"
+#include "llfloatertwitter.h"
 #include "llcheckboxctrl.h"
 #include "llcombobox.h"
 #include "llpostcard.h"
@@ -1264,9 +1266,11 @@ S32 LLFloaterSnapshot::notify(const LLSD& info)
 void LLFloaterSnapshot::update()
 {
 	LLFloaterSnapshot* inst = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot");
-	LLFloaterSocial* floater_social  = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); 
+	LLFloaterSocial* floater_social = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); 
+	LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr"); 
+	LLFloaterTwitter* floater_twitter = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); 
 
-	if (!inst && !floater_social)
+	if (!inst && !floater_social && !floater_flickr && !floater_twitter)
 		return;
 	
 	BOOL changed = FALSE;
diff --git a/indra/newview/llfloatersocial.cpp b/indra/newview/llfloatersocial.cpp
index 2a74c8e3eac8f145a9de54d7fe8d5183041ae6ab..31404da7d31a058c676f4a312bf830400ad03c26 100644
--- a/indra/newview/llfloatersocial.cpp
+++ b/indra/newview/llfloatersocial.cpp
@@ -46,6 +46,7 @@
 #include "llviewerregion.h"
 #include "llviewercontrol.h"
 #include "llviewermedia.h"
+#include "lltabcontainer.h"
 
 static LLRegisterPanelClassWrapper<LLSocialStatusPanel> t_panel_status("llsocialstatuspanel");
 static LLRegisterPanelClassWrapper<LLSocialPhotoPanel> t_panel_photo("llsocialphotopanel");
@@ -823,6 +824,18 @@ BOOL LLFloaterSocial::postBuild()
 	return LLFloater::postBuild();
 }
 
+void LLFloaterSocial::showPhotoPanel()
+{
+	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mSocialPhotoPanel->getParent());
+	if (!parent)
+	{
+		llwarns << "Cannot find panel container" << llendl;
+		return;
+	}
+
+	parent->selectTabPanel(mSocialPhotoPanel);
+}
+
 // static
 void LLFloaterSocial::preUpdate()
 {
diff --git a/indra/newview/llfloatersocial.h b/indra/newview/llfloatersocial.h
index bbe07c970406ec6b4daa1689ad9ed6dcd6e7beef..041ae8a2682ec185953fb309bbe611f568092831 100644
--- a/indra/newview/llfloatersocial.h
+++ b/indra/newview/llfloatersocial.h
@@ -150,6 +150,8 @@ class LLFloaterSocial : public LLFloater
 	BOOL postBuild();
 	void draw();
 	void onCancel();
+	
+	void showPhotoPanel();
 
 	static void preUpdate();
 	static void postUpdate();
diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..06d0fb5542ae0ecab4308ac5586f51214dbee0ef
--- /dev/null
+++ b/indra/newview/llfloatertwitter.cpp
@@ -0,0 +1,697 @@
+/** 
+* @file llfloatertwitter.cpp
+* @brief Implementation of llfloatertwitter
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatertwitter.h"
+
+#include "llagent.h"
+#include "llagentui.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "lltwitterconnect.h"
+#include "llfloaterreg.h"
+#include "lliconctrl.h"
+#include "llresmgr.h"		// LLLocale
+#include "llsdserialize.h"
+#include "llloadingindicator.h"
+#include "llplugincookiestore.h"
+#include "llslurl.h"
+#include "lltrans.h"
+#include "llsnapshotlivepreview.h"
+#include "llviewerregion.h"
+#include "llviewercontrol.h"
+#include "llviewermedia.h"
+#include "lltabcontainer.h"
+#include "lltexteditor.h"
+
+static LLRegisterPanelClassWrapper<LLTwitterPhotoPanel> t_panel_photo("lltwitterphotopanel");
+static LLRegisterPanelClassWrapper<LLTwitterAccountPanel> t_panel_account("lltwitteraccountpanel");
+
+const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
+const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=twitter&utm_medium=photo&utm_campaign=slshare";
+
+///////////////////////////
+//LLTwitterPhotoPanel///////
+///////////////////////////
+
+LLTwitterPhotoPanel::LLTwitterPhotoPanel() :
+mSnapshotPanel(NULL),
+mResolutionComboBox(NULL),
+mRefreshBtn(NULL),
+mWorkingLabel(NULL),
+mThumbnailPlaceholder(NULL),
+mStatusTextBox(NULL),
+mPhotoCheckbox(NULL),
+mPostButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLTwitterPhotoPanel::onSend, this));
+	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLTwitterPhotoPanel::onClickNewSnapshot, this));
+}
+
+LLTwitterPhotoPanel::~LLTwitterPhotoPanel()
+{
+	if(mPreviewHandle.get())
+	{
+		mPreviewHandle.get()->die();
+	}
+}
+
+BOOL LLTwitterPhotoPanel::postBuild()
+{
+	setVisibleCallback(boost::bind(&LLTwitterPhotoPanel::onVisibilityChange, this, _2));
+	
+	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
+	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
+	mResolutionComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE));
+	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
+    mWorkingLabel = getChild<LLUICtrl>("working_lbl");
+	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
+	mStatusTextBox = getChild<LLUICtrl>("photo_status");
+	mPhotoCheckbox = getChild<LLUICtrl>("add_photo_cb");
+	mPostButton = getChild<LLUICtrl>("post_photo_btn");
+	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn");
+
+	return LLPanel::postBuild();
+}
+
+void LLTwitterPhotoPanel::draw()
+{ 
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+
+    // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts)
+    bool no_ongoing_connection = !(LLTwitterConnect::instance().isTransactionOngoing());
+    mCancelButton->setEnabled(no_ongoing_connection);
+    mStatusTextBox->setEnabled(no_ongoing_connection);
+    mResolutionComboBox->setEnabled(no_ongoing_connection && mPhotoCheckbox->getValue().asBoolean());
+    mRefreshBtn->setEnabled(no_ongoing_connection && mPhotoCheckbox->getValue().asBoolean());
+    mPhotoCheckbox->setEnabled(no_ongoing_connection);
+
+	bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+
+	// Restrict the status text length to Twitter's character limit
+	LLTextEditor* status_text_box = dynamic_cast<LLTextEditor*>(mStatusTextBox);
+	if (status_text_box)
+	{
+		int max_status_length = add_photo ? 100 : 140;
+		status_text_box->setMaxTextLength(max_status_length);
+		if (!add_photo)
+		{
+			if (mOldStatusText.length() > status_text_box->getText().length() && status_text_box->getText() == mOldStatusText.substr(0, status_text_box->getText().length()))
+			{
+				status_text_box->setText(mOldStatusText);
+			}
+			mOldStatusText = "";
+		}
+		if (status_text_box->getText().length() > max_status_length)
+		{
+			mOldStatusText = status_text_box->getText();
+			status_text_box->setText(mOldStatusText.substr(0, max_status_length));
+		}
+	}
+
+    // Display the preview if one is available
+	if (previewp && previewp->getThumbnailImage())
+	{
+		const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect();
+		const S32 thumbnail_w = previewp->getThumbnailWidth();
+		const S32 thumbnail_h = previewp->getThumbnailHeight();
+
+		// calc preview offset within the preview rect
+		const S32 local_offset_x = (thumbnail_rect.getWidth()  - thumbnail_w) / 2 ;
+		const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ;
+
+		// calc preview offset within the floater rect
+        // Hack : To get the full offset, we need to take into account each and every offset of each widgets up to the floater.
+        // This is almost as arbitrary as using a fixed offset so that's what we do here for the sake of simplicity.
+        // *TODO : Get the offset looking through the hierarchy of widgets, should be done in postBuild() so to avoid traversing the hierarchy each time.
+		S32 offset_x = thumbnail_rect.mLeft + local_offset_x - 1;
+		S32 offset_y = thumbnail_rect.mBottom + local_offset_y - 39;
+        
+		mSnapshotPanel->localPointToOtherView(offset_x, offset_y, &offset_x, &offset_y, getParentByType<LLFloater>());
+        
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		// Apply floater transparency to the texture unless the floater is focused.
+		F32 alpha = (add_photo ? (getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency()) : 0.5f);
+		LLColor4 color = LLColor4::white;
+		gl_draw_scaled_image(offset_x, offset_y, 
+			thumbnail_w, thumbnail_h,
+			previewp->getThumbnailImage(), color % alpha);
+
+		previewp->drawPreviewRect(offset_x, offset_y) ;
+	}
+
+    // Update the visibility of the working (computing preview) label
+    mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate()));
+    
+    // Enable Post if we have a preview to send and no on going connection being processed
+    mPostButton->setEnabled(no_ongoing_connection && ((add_photo && previewp && previewp->getSnapshotUpToDate()) || !mStatusTextBox->getValue().asString().empty()));
+    
+    // Draw the rest of the panel on top of it
+	LLPanel::draw();
+}
+
+LLSnapshotLivePreview* LLTwitterPhotoPanel::getPreviewView()
+{
+	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get();
+	return previewp;
+}
+
+void LLTwitterPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
+{
+	bool visible = new_visibility.asBoolean();
+	if (visible)
+	{
+		if (mPreviewHandle.get())
+		{
+			LLSnapshotLivePreview* preview = getPreviewView();
+			if(preview)
+			{
+				lldebugs << "opened, updating snapshot" << llendl;
+				preview->updateSnapshot(TRUE);
+			}
+		}
+		else
+		{
+			LLRect full_screen_rect = getRootView()->getRect();
+			LLSnapshotLivePreview::Params p;
+			p.rect(full_screen_rect);
+			LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
+			mPreviewHandle = previewp->getHandle();	
+
+			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
+			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
+			//previewp->setSnapshotQuality(98);
+			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
+
+			updateControls();
+		}
+	}
+}
+
+void LLTwitterPhotoPanel::onClickNewSnapshot()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	if (previewp)
+	{
+		//setStatus(Impl::STATUS_READY);
+		lldebugs << "updating snapshot" << llendl;
+		previewp->updateSnapshot(TRUE);
+	}
+}
+
+void LLTwitterPhotoPanel::onSend()
+{
+	LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); // just in case it is already listening
+	LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterPhotoPanel", boost::bind(&LLTwitterPhotoPanel::onTwitterConnectStateChange, this, _1));
+	
+	// Connect to Twitter if necessary and then post
+	if (LLTwitterConnect::instance().isConnected())
+	{
+		sendPhoto();
+	}
+	else
+	{
+		LLTwitterConnect::instance().checkConnectionToTwitter(true);
+	}
+}
+
+bool LLTwitterPhotoPanel::onTwitterConnectStateChange(const LLSD& data)
+{
+	switch (data.get("enum").asInteger())
+	{
+		case LLTwitterConnect::TWITTER_CONNECTED:
+			sendPhoto();
+			break;
+
+		case LLTwitterConnect::TWITTER_POSTED:
+			LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel");
+			clearAndClose();
+			break;
+	}
+
+	return false;
+}
+
+void LLTwitterPhotoPanel::sendPhoto()
+{
+	// Get the status text
+	std::string status = mStatusTextBox->getValue().asString();
+
+	// Add the photo if required
+	bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+	if (add_photo)
+	{
+		// Get the image
+		LLSnapshotLivePreview* previewp = getPreviewView();
+	
+		// Post to Twitter
+		LLTwitterConnect::instance().uploadPhoto(previewp->getFormattedImage(), status);
+	}
+	else
+	{
+		// Just post the status to Twitter
+		LLTwitterConnect::instance().updateStatus(status);
+	}
+
+	updateControls();
+}
+
+void LLTwitterPhotoPanel::clearAndClose()
+{
+	mStatusTextBox->setValue("");
+
+	LLFloater* floater = getParentByType<LLFloater>();
+	if (floater)
+	{
+		floater->closeFloater();
+	}
+}
+
+void LLTwitterPhotoPanel::updateControls()
+{
+	LLSnapshotLivePreview* previewp = getPreviewView();
+	BOOL got_bytes = previewp && previewp->getDataSize() > 0;
+	BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
+	LLSnapshotLivePreview::ESnapshotType shot_type = (previewp ? previewp->getSnapshotType() : LLSnapshotLivePreview::SNAPSHOT_POSTCARD);
+
+	// *TODO: Separate maximum size for Web images from postcards
+	lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
+
+	LLLocale locale(LLLocale::USER_LOCALE);
+	std::string bytes_string;
+	if (got_snap)
+	{
+		LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 );
+	}
+
+	//getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : getString("unknown")); <---uses localized string
+	getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : "unknown");
+	getChild<LLUICtrl>("file_size_label")->setColor(
+		shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD 
+		&& got_bytes
+		&& previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" ));
+
+	updateResolution(FALSE);
+}
+
+void LLTwitterPhotoPanel::updateResolution(BOOL do_update)
+{
+	LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
+
+	std::string sdstring = combobox->getSelectedValue();
+	LLSD sdres;
+	std::stringstream sstream(sdstring);
+	LLSDSerialize::fromNotation(sdres, sstream, sdstring.size());
+
+	S32 width = sdres[0];
+	S32 height = sdres[1];
+
+	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
+	if (previewp && combobox->getCurrentIndex() >= 0)
+	{
+		S32 original_width = 0 , original_height = 0 ;
+		previewp->getSize(original_width, original_height) ;
+
+		if (width == 0 || height == 0)
+		{
+			// take resolution from current window size
+			lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl;
+			previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
+		}
+		else
+		{
+			// use the resolution from the selected pre-canned drop-down choice
+			lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl;
+			previewp->setSize(width, height);
+		}
+
+		checkAspectRatio(width);
+
+		previewp->getSize(width, height);
+		
+		if(original_width != width || original_height != height)
+		{
+			previewp->setSize(width, height);
+
+			// hide old preview as the aspect ratio could be wrong
+			lldebugs << "updating thumbnail" << llendl;
+			
+			previewp->updateSnapshot(FALSE, TRUE);
+			if(do_update)
+			{
+				lldebugs << "Will update controls" << llendl;
+				updateControls();
+                LLTwitterPhotoPanel::onClickNewSnapshot();
+			}
+		}
+		
+	}
+}
+
+void LLTwitterPhotoPanel::checkAspectRatio(S32 index)
+{
+	LLSnapshotLivePreview *previewp = getPreviewView() ;
+
+	BOOL keep_aspect = FALSE;
+
+	if (0 == index) // current window size
+	{
+		keep_aspect = TRUE;
+	}
+	else // predefined resolution
+	{
+		keep_aspect = FALSE;
+	}
+
+	if (previewp)
+	{
+		previewp->mKeepAspectRatio = keep_aspect;
+	}
+}
+
+LLUICtrl* LLTwitterPhotoPanel::getRefreshBtn()
+{
+	return mRefreshBtn;
+}
+
+///////////////////////////
+//LLTwitterAccountPanel//////
+///////////////////////////
+
+LLTwitterAccountPanel::LLTwitterAccountPanel() : 
+mAccountCaptionLabel(NULL),
+mAccountNameLabel(NULL),
+mPanelButtons(NULL),
+mConnectButton(NULL),
+mDisconnectButton(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLTwitterAccountPanel::onConnect, this));
+	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLTwitterAccountPanel::onDisconnect, this));
+
+	setVisibleCallback(boost::bind(&LLTwitterAccountPanel::onVisibilityChange, this, _2));
+}
+
+BOOL LLTwitterAccountPanel::postBuild()
+{
+	mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
+	mAccountNameLabel = getChild<LLTextBox>("account_name_label");
+	mPanelButtons = getChild<LLUICtrl>("panel_buttons");
+	mConnectButton = getChild<LLUICtrl>("connect_btn");
+	mDisconnectButton = getChild<LLUICtrl>("disconnect_btn");
+
+	return LLPanel::postBuild();
+}
+
+void LLTwitterAccountPanel::draw()
+{
+	LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState();
+
+	//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress
+	bool disconnecting = connection_state == LLTwitterConnect::TWITTER_DISCONNECTING;
+	mDisconnectButton->setEnabled(!disconnecting);
+
+	//Disable the 'connect' button when a connection is in progress
+	bool connecting = connection_state == LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS;
+	mConnectButton->setEnabled(!connecting);
+
+	LLPanel::draw();
+}
+
+void LLTwitterAccountPanel::onVisibilityChange(const LLSD& new_visibility)
+{
+	bool visible = new_visibility.asBoolean();
+
+	if(visible)
+	{
+		LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel");
+		LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectStateChange, this, _1));
+
+		LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel");
+		LLEventPumps::instance().obtain("TwitterConnectInfo").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectInfoChange, this));
+
+		//Connected
+		if(LLTwitterConnect::instance().isConnected())
+		{
+			showConnectedLayout();
+		}
+		//Check if connected (show disconnected layout in meantime)
+		else
+		{
+			showDisconnectedLayout();
+		}
+        if ((LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_NOT_CONNECTED) ||
+            (LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_CONNECTION_FAILED))
+        {
+            LLTwitterConnect::instance().checkConnectionToTwitter();
+        }
+	}
+	else
+	{
+		LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel");
+		LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel");
+	}
+}
+
+bool LLTwitterAccountPanel::onTwitterConnectStateChange(const LLSD& data)
+{
+	if(LLTwitterConnect::instance().isConnected())
+	{
+		//In process of disconnecting so leave the layout as is
+		if(data.get("enum").asInteger() != LLTwitterConnect::TWITTER_DISCONNECTING)
+		{
+			showConnectedLayout();
+		}
+	}
+	else
+	{
+		showDisconnectedLayout();
+	}
+
+	return false;
+}
+
+bool LLTwitterAccountPanel::onTwitterConnectInfoChange()
+{
+	LLSD info = LLTwitterConnect::instance().getInfo();
+	std::string clickable_name;
+
+	//Strings of format [http://www.somewebsite.com Click Me] become clickable text
+	if(info.has("link") && info.has("name"))
+	{
+		clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]";
+	}
+
+	mAccountNameLabel->setText(clickable_name);
+
+	return false;
+}
+
+void LLTwitterAccountPanel::showConnectButton()
+{
+	if(!mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(TRUE);
+		mDisconnectButton->setVisible(FALSE);
+	}
+}
+
+void LLTwitterAccountPanel::hideConnectButton()
+{
+	if(mConnectButton->getVisible())
+	{
+		mConnectButton->setVisible(FALSE);
+		mDisconnectButton->setVisible(TRUE);
+	}
+}
+
+void LLTwitterAccountPanel::showDisconnectedLayout()
+{
+	mAccountCaptionLabel->setText(getString("twitter_disconnected"));
+	mAccountNameLabel->setText(std::string(""));
+	showConnectButton();
+}
+
+void LLTwitterAccountPanel::showConnectedLayout()
+{
+	LLTwitterConnect::instance().loadTwitterInfo();
+
+	mAccountCaptionLabel->setText(getString("twitter_connected"));
+	hideConnectButton();
+}
+
+void LLTwitterAccountPanel::onConnect()
+{
+	LLTwitterConnect::instance().checkConnectionToTwitter(true);
+
+	//Clear only the twitter browser cookies so that the twitter login screen appears
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com"); 
+}
+
+void LLTwitterAccountPanel::onDisconnect()
+{
+	LLTwitterConnect::instance().disconnectFromTwitter();
+
+	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com"); 
+}
+
+////////////////////////
+//LLFloaterTwitter///////
+////////////////////////
+
+LLFloaterTwitter::LLFloaterTwitter(const LLSD& key) : LLFloater(key),
+    mSocialPhotoPanel(NULL),
+    mStatusErrorText(NULL),
+    mStatusLoadingText(NULL),
+    mStatusLoadingIndicator(NULL)
+{
+	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterTwitter::onCancel, this));
+}
+
+void LLFloaterTwitter::onCancel()
+{
+    closeFloater();
+}
+
+BOOL LLFloaterTwitter::postBuild()
+{
+    // Keep tab of the Photo Panel
+	mSocialPhotoPanel = static_cast<LLTwitterPhotoPanel*>(getChild<LLUICtrl>("panel_twitter_photo"));
+    // Connection status widgets
+    mStatusErrorText = getChild<LLTextBox>("connection_error_text");
+    mStatusLoadingText = getChild<LLTextBox>("connection_loading_text");
+    mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator");
+	return LLFloater::postBuild();
+}
+
+void LLFloaterTwitter::showPhotoPanel()
+{
+	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mSocialPhotoPanel->getParent());
+	if (!parent)
+	{
+		llwarns << "Cannot find panel container" << llendl;
+		return;
+	}
+
+	parent->selectTabPanel(mSocialPhotoPanel);
+}
+
+// static
+void LLFloaterTwitter::preUpdate()
+{
+	LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter");
+	if (instance)
+	{
+		//Will set file size text to 'unknown'
+		instance->mSocialPhotoPanel->updateControls();
+	}
+}
+
+// static
+void LLFloaterTwitter::postUpdate()
+{
+	LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter");
+	if (instance)
+	{
+		//Will set the file size text
+		instance->mSocialPhotoPanel->updateControls();
+
+		// The refresh button is initially hidden. We show it after the first update,
+		// i.e. after snapshot is taken
+		LLUICtrl * refresh_button = instance->mSocialPhotoPanel->getRefreshBtn();
+
+		if (!refresh_button->getVisible())
+		{
+			refresh_button->setVisible(true);
+		}
+		
+	}
+}
+
+void LLFloaterTwitter::draw()
+{
+    if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator)
+    {
+        mStatusErrorText->setVisible(false);
+        mStatusLoadingText->setVisible(false);
+        mStatusLoadingIndicator->setVisible(false);
+        LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState();
+        std::string status_text;
+        
+        switch (connection_state)
+        {
+        case LLTwitterConnect::TWITTER_NOT_CONNECTED:
+            // No status displayed when first opening the panel and no connection done
+        case LLTwitterConnect::TWITTER_CONNECTED:
+            // When successfully connected, no message is displayed
+        case LLTwitterConnect::TWITTER_POSTED:
+            // No success message to show since we actually close the floater after successful posting completion
+            break;
+        case LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS:
+            // Connection loading indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterConnecting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+            break;
+        case LLTwitterConnect::TWITTER_POSTING:
+            // Posting indicator
+            mStatusLoadingText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterPosting");
+            mStatusLoadingText->setValue(status_text);
+            mStatusLoadingIndicator->setVisible(true);
+			break;
+        case LLTwitterConnect::TWITTER_CONNECTION_FAILED:
+            // Error connecting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterErrorConnecting");
+            mStatusErrorText->setValue(status_text);
+            break;
+        case LLTwitterConnect::TWITTER_POST_FAILED:
+            // Error posting to the service
+            mStatusErrorText->setVisible(true);
+            status_text = LLTrans::getString("SocialTwitterErrorPosting");
+            mStatusErrorText->setValue(status_text);
+            break;
+		case LLTwitterConnect::TWITTER_DISCONNECTING:
+			// Disconnecting loading indicator
+			mStatusLoadingText->setVisible(true);
+			status_text = LLTrans::getString("SocialTwitterDisconnecting");
+			mStatusLoadingText->setValue(status_text);
+			mStatusLoadingIndicator->setVisible(true);
+			break;
+		case LLTwitterConnect::TWITTER_DISCONNECT_FAILED:
+			// Error disconnecting from the service
+			mStatusErrorText->setVisible(true);
+			status_text = LLTrans::getString("SocialTwitterErrorDisconnecting");
+			mStatusErrorText->setValue(status_text);
+			break;
+        }
+    }
+	LLFloater::draw();
+}
+
diff --git a/indra/newview/llfloatertwitter.h b/indra/newview/llfloatertwitter.h
new file mode 100644
index 0000000000000000000000000000000000000000..686e167b1fd4e0ca4c6cf675dac05cf47b03aa7a
--- /dev/null
+++ b/indra/newview/llfloatertwitter.h
@@ -0,0 +1,126 @@
+/** 
+* @file   llfloatertwitter.h
+* @brief  Header file for llfloatertwitter
+* @author cho@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLFLOATERTWITTER_H
+#define LL_LLFLOATERTWITTER_H
+
+#include "llfloater.h"
+#include "lltextbox.h"
+#include "llviewertexture.h"
+
+class LLIconCtrl;
+class LLCheckBoxCtrl;
+class LLSnapshotLivePreview;
+
+class LLTwitterPhotoPanel : public LLPanel
+{
+public:
+	LLTwitterPhotoPanel();
+	~LLTwitterPhotoPanel();
+
+	BOOL postBuild();
+	void draw();
+
+	LLSnapshotLivePreview* getPreviewView();
+	void onVisibilityChange(const LLSD& new_visibility);
+	void onClickNewSnapshot();
+	void onSend();
+	bool onTwitterConnectStateChange(const LLSD& data);
+
+	void sendPhoto();
+	void clearAndClose();
+
+	void updateControls();
+	void updateResolution(BOOL do_update);
+	void checkAspectRatio(S32 index);
+	LLUICtrl* getRefreshBtn();
+
+private:
+	LLHandle<LLView> mPreviewHandle;
+
+	LLUICtrl * mSnapshotPanel;
+	LLUICtrl * mResolutionComboBox;
+	LLUICtrl * mRefreshBtn;
+	LLUICtrl * mWorkingLabel;
+	LLUICtrl * mThumbnailPlaceholder;
+	LLUICtrl * mStatusTextBox;
+	LLUICtrl * mPhotoCheckbox;
+	LLUICtrl * mPostButton;
+	LLUICtrl* mCancelButton;
+
+	std::string mOldStatusText;
+};
+
+class LLTwitterAccountPanel : public LLPanel
+{
+public:
+	LLTwitterAccountPanel();
+	BOOL postBuild();
+	void draw();
+
+private:
+	void onVisibilityChange(const LLSD& new_visibility);
+	bool onTwitterConnectStateChange(const LLSD& data);
+	bool onTwitterConnectInfoChange();
+	void onConnect();
+	void onUseAnotherAccount();
+	void onDisconnect();
+
+	void showConnectButton();
+	void hideConnectButton();
+	void showDisconnectedLayout();
+	void showConnectedLayout();
+
+	LLTextBox * mAccountCaptionLabel;
+	LLTextBox * mAccountNameLabel;
+	LLUICtrl * mPanelButtons;
+	LLUICtrl * mConnectButton;
+	LLUICtrl * mDisconnectButton;
+};
+
+
+class LLFloaterTwitter : public LLFloater
+{
+public:
+	LLFloaterTwitter(const LLSD& key);
+	BOOL postBuild();
+	void draw();
+	void onCancel();
+
+	void showPhotoPanel();
+
+	static void preUpdate();
+	static void postUpdate();
+
+private:
+	LLTwitterPhotoPanel* mSocialPhotoPanel;
+    LLTextBox* mStatusErrorText;
+    LLTextBox* mStatusLoadingText;
+    LLUICtrl*  mStatusLoadingIndicator;
+};
+
+#endif // LL_LLFLOATERTWITTER_H
+
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 5c569b9bf0ffd5a024217374593cc84b23c9e1c7..814c91ef6c63dbce39cf4456ddfef72485267f79 100755
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -30,6 +30,8 @@
 #include "lliconctrl.h"
 #include "llfloaterreg.h"
 #include "llfacebookconnect.h"
+#include "llflickrconnect.h"
+#include "lltwitterconnect.h"
 #include "lllayoutstack.h"
 #include "llpluginclassmedia.h"
 #include "llprogressbar.h"
@@ -298,7 +300,24 @@ void LLFloaterWebContent::onClose(bool app_quitting)
             LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
         }
     }
-    
+	// Same with Flickr
+	LLFloater* flickr_web = LLFloaterReg::getInstance("flickr_web");
+    if (flickr_web == this)
+    {
+        if (!LLFlickrConnect::instance().isConnected())
+        {
+            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+        }
+    }
+	// And Twitter
+	LLFloater* twitter_web = LLFloaterReg::getInstance("twitter_web");
+    if (twitter_web == this)
+    {
+        if (!LLTwitterConnect::instance().isConnected())
+        {
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+        }
+    }
 	LLViewerMedia::proxyWindowClosed(mUUID);
 	destroy();
 }
diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp
index 554fabe5b3d38f0cd9dded22f1b071b327c9e7cb..4cadd837d132887027748bd36386d71401bd06b1 100755
--- a/indra/newview/llpanelsnapshotoptions.cpp
+++ b/indra/newview/llpanelsnapshotoptions.cpp
@@ -31,6 +31,10 @@
 #include "llsidetraypanelcontainer.h"
 
 #include "llfloatersnapshot.h" // FIXME: create a snapshot model
+#include "llfloaterreg.h"
+#include "llfloatersocial.h"
+#include "llfloaterflickr.h"
+#include "llfloatertwitter.h"
 
 /**
  * Provides several ways to save a snapshot.
@@ -44,6 +48,7 @@ class LLPanelSnapshotOptions
 public:
 	LLPanelSnapshotOptions();
 	~LLPanelSnapshotOptions();
+	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void onOpen(const LLSD& key);
 	/*virtual*/ void onEconomyDataChange() { updateUploadCost(); }
 
@@ -54,6 +59,9 @@ class LLPanelSnapshotOptions
 	void onSaveToEmail();
 	void onSaveToInventory();
 	void onSaveToComputer();
+	void onSendToFacebook();
+	void onSendToTwitter();
+	void onSendToFlickr();
 };
 
 static LLRegisterPanelClassWrapper<LLPanelSnapshotOptions> panel_class("llpanelsnapshotoptions");
@@ -73,6 +81,19 @@ LLPanelSnapshotOptions::~LLPanelSnapshotOptions()
 	LLGlobalEconomy::Singleton::getInstance()->removeObserver(this);
 }
 
+// virtual
+BOOL LLPanelSnapshotOptions::postBuild()
+{
+    LLTextBox* sendToFacebookTextBox = getChild<LLTextBox>("send_to_facebook_textbox");
+    sendToFacebookTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToFacebook, this));
+    LLTextBox* sendToTwitterTextBox = getChild<LLTextBox>("send_to_twitter_textbox");
+    sendToTwitterTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToTwitter, this));
+    LLTextBox* sendToFlickrTextBox = getChild<LLTextBox>("send_to_flickr_textbox");
+    sendToFlickrTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToFlickr, this));
+
+	return LLPanel::postBuild();
+}
+
 // virtual
 void LLPanelSnapshotOptions::onOpen(const LLSD& key)
 {
@@ -118,3 +139,39 @@ void LLPanelSnapshotOptions::onSaveToComputer()
 {
 	openPanel("panel_snapshot_local");
 }
+
+void LLPanelSnapshotOptions::onSendToFacebook()
+{
+	LLFloaterReg::hideInstance("snapshot");
+
+	LLFloaterSocial* social_floater = dynamic_cast<LLFloaterSocial*>(LLFloaterReg::getInstance("social"));
+	if (social_floater)
+	{
+		social_floater->showPhotoPanel();
+	}
+	LLFloaterReg::showInstance("social");
+}
+
+void LLPanelSnapshotOptions::onSendToTwitter()
+{
+	LLFloaterReg::hideInstance("snapshot");
+
+	LLFloaterTwitter* twitter_floater = dynamic_cast<LLFloaterTwitter*>(LLFloaterReg::getInstance("twitter"));
+	if (twitter_floater)
+	{
+		twitter_floater->showPhotoPanel();
+	}
+	LLFloaterReg::showInstance("twitter");
+}
+
+void LLPanelSnapshotOptions::onSendToFlickr()
+{
+	LLFloaterReg::hideInstance("snapshot");
+
+	LLFloaterFlickr* flickr_floater = dynamic_cast<LLFloaterFlickr*>(LLFloaterReg::getInstance("flickr"));
+	if (flickr_floater)
+	{
+		flickr_floater->showPhotoPanel();
+	}
+	LLFloaterReg::showInstance("flickr");
+}
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 7532ebfc5784d78ce688bb1af5face1e84d073db..67952f83c75735289c0fc362868c7009156844df 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -35,6 +35,8 @@
 #include "llfloaterperms.h"
 #include "llfloaterreg.h"
 #include "llfloatersocial.h"
+#include "llfloaterflickr.h"
+#include "llfloatertwitter.h"
 #include "llimagebmp.h"
 #include "llimagej2c.h"
 #include "llimagejpeg.h"
@@ -209,6 +211,8 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail
 		mSnapshotDelayTimer.setTimerExpirySec(delay);
 		LLFloaterSnapshot::preUpdate();
 		LLFloaterSocial::preUpdate();
+		LLFloaterFlickr::preUpdate();
+		LLFloaterTwitter::preUpdate();
 	}
 
 	// Update thumbnail if requested.
@@ -766,6 +770,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 	lldebugs << "done creating snapshot" << llendl;
 	LLFloaterSnapshot::postUpdate();
 	LLFloaterSocial::postUpdate();
+	LLFloaterFlickr::postUpdate();
+	LLFloaterTwitter::postUpdate();
 
 	return TRUE;
 }
diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e015867df2b2ca1e2add87428b83cbbb8e24b86d
--- /dev/null
+++ b/indra/newview/lltwitterconnect.cpp
@@ -0,0 +1,471 @@
+/** 
+ * @file lltwitterconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Twitter Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltwitterconnect.h"
+
+#include "llagent.h"
+#include "llcallingcard.h"			// for LLAvatarTracker
+#include "llcommandhandler.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
+#include "llurlaction.h"
+#include "llimagepng.h"
+#include "llimagejpeg.h"
+#include "lltrans.h"
+#include "llevents.h"
+#include "llviewerregion.h"
+
+#include "llfloaterwebcontent.h"
+#include "llfloaterreg.h"
+
+boost::scoped_ptr<LLEventPump> LLTwitterConnect::sStateWatcher(new LLEventStream("TwitterConnectState"));
+boost::scoped_ptr<LLEventPump> LLTwitterConnect::sInfoWatcher(new LLEventStream("TwitterConnectInfo"));
+boost::scoped_ptr<LLEventPump> LLTwitterConnect::sContentWatcher(new LLEventStream("TwitterConnectContent"));
+
+// Local functions
+void log_twitter_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
+{
+    // Note: 302 (redirect) is *not* an error that warrants logging
+    if (status != 302)
+    {
+		LL_WARNS("TwitterConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL;
+    }
+}
+
+void toast_user_for_twitter_success()
+{
+	LLSD args;
+    args["MESSAGE"] = LLTrans::getString("twitter_post_success");
+    LLNotificationsUtil::add("TwitterConnect", args);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterConnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterConnectResponder);
+public:
+	
+    LLTwitterConnectResponder()
+    {
+        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+    }
+    
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status))
+		{
+			LL_DEBUGS("TwitterConnect") << "Connect successful. content: " << content << LL_ENDL;
+			
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
+		}
+		else if (status != 302)
+		{
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+            log_twitter_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description"));
+		}
+	}
+    
+    void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+    {
+        if (status == 302)
+        {
+            LLTwitterConnect::instance().openTwitterWeb(content["location"]);
+        }
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterShareResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterShareResponder);
+public:
+    
+	LLTwitterShareResponder()
+	{
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTING);
+	}
+	
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status))
+		{
+            toast_user_for_twitter_success();
+			LL_DEBUGS("TwitterConnect") << "Post successful. content: " << content << LL_ENDL;
+			
+			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTED);
+		}
+		else if (status == 404)
+		{
+			LLTwitterConnect::instance().connectToTwitter();
+		}
+		else
+		{
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED);
+            log_twitter_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description"));
+		}
+	}
+    
+    void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+    {
+        if (status == 302)
+        {
+            LLTwitterConnect::instance().openTwitterWeb(content["location"]);
+        }
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterDisconnectResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterDisconnectResponder);
+public:
+ 
+	LLTwitterDisconnectResponder()
+	{
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING);
+	}
+
+	void setUserDisconnected()
+	{
+		// Clear data
+		LLTwitterConnect::instance().clearInfo();
+
+		//Notify state change
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
+	}
+
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status)) 
+		{
+			LL_DEBUGS("TwitterConnect") << "Disconnect successful. content: " << content << LL_ENDL;
+			setUserDisconnected();
+
+		}
+		//User not found so already disconnected
+		else if(status == 404)
+		{
+			LL_DEBUGS("TwitterConnect") << "Already disconnected. content: " << content << LL_ENDL;
+			setUserDisconnected();
+		}
+		else
+		{
+			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED);
+            log_twitter_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description"));
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterConnectedResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterConnectedResponder);
+public:
+    
+	LLTwitterConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
+    {
+		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+    }
+    
+	virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (isGoodStatus(status))
+		{
+			LL_DEBUGS("TwitterConnect") << "Connect successful. content: " << content << LL_ENDL;
+            
+            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
+		}
+		else
+		{
+			// show the twitter login page if not connected yet
+			if (status == 404)
+			{
+				if (mAutoConnect)
+				{
+					LLTwitterConnect::instance().connectToTwitter();
+				}
+				else
+				{
+					LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
+				}
+			}
+            else
+            {
+                LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+				log_twitter_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description"));
+            }
+		}
+	}
+    
+private:
+	bool mAutoConnect;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLTwitterInfoResponder : public LLHTTPClient::Responder
+{
+	LOG_CLASS(LLTwitterInfoResponder);
+public:
+
+	virtual void completed(U32 status, const std::string& reason, const LLSD& info)
+	{
+		if (isGoodStatus(status))
+		{
+			llinfos << "Twitter: Info received" << llendl;
+			LL_DEBUGS("TwitterConnect") << "Getting Twitter info successful. info: " << info << LL_ENDL;
+			LLTwitterConnect::instance().storeInfo(info);
+		}
+		else
+		{
+			log_twitter_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description"));
+		}
+	}
+
+	void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+	{
+		if (status == 302)
+		{
+			LLTwitterConnect::instance().openTwitterWeb(content["location"]);
+		}
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+LLTwitterConnect::LLTwitterConnect()
+:	mConnectionState(TWITTER_NOT_CONNECTED),
+	mConnected(false),
+	mInfo(),
+	mRefreshInfo(false),
+	mReadFromMaster(false)
+{
+}
+
+void LLTwitterConnect::openTwitterWeb(std::string url)
+{
+	// Open the URL in an internal browser window without navigation UI
+	LLFloaterWebContent::Params p;
+    p.url(url).show_chrome(true);
+    p.url(url).allow_address_entry(false);
+    p.url(url).allow_back_forward_navigation(false);
+    p.url(url).trusted_content(true);
+	LLFloater *floater = LLFloaterReg::showInstance("twitter_web", p);
+	//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems).
+	//So when showing the internal web browser, set focus to it's containing floater "twitter_web". When a mouse event 
+	//occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus.
+	//twitter_web floater contains the "webbrowser" panel.    JIRA: ACME-744
+	gFocusMgr.setKeyboardFocus( floater );
+
+	//LLUrlAction::openURLExternal(url);
+}
+
+std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, bool include_read_from_master)
+{
+    std::string url("");
+    LLViewerRegion *regionp = gAgent.getRegion();
+    if (regionp)
+    {
+		//url = "http://pdp15.lindenlab.com/twitter/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO
+        url = regionp->getCapability("TwitterConnect");
+        url += route;
+    
+        if (include_read_from_master && mReadFromMaster)
+        {
+            url += "?read_from_master=true";
+        }
+    }
+	return url;
+}
+
+void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier)
+{
+	LLSD body;
+	if (!request_token.empty())
+		body["request_token"] = request_token;
+	if (!oauth_verifier.empty())
+		body["oauth_verifier"] = oauth_verifier;
+    
+	LLHTTPClient::put(getTwitterConnectURL("/connection"), body, new LLTwitterConnectResponder());
+}
+
+void LLTwitterConnect::disconnectFromTwitter()
+{
+	LLHTTPClient::del(getTwitterConnectURL("/connection"), new LLTwitterDisconnectResponder());
+}
+
+void LLTwitterConnect::checkConnectionToTwitter(bool auto_connect)
+{
+	const bool follow_redirects = false;
+	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	LLHTTPClient::get(getTwitterConnectURL("/connection", true), new LLTwitterConnectedResponder(auto_connect),
+						LLSD(), timeout, follow_redirects);
+}
+
+void LLTwitterConnect::loadTwitterInfo()
+{
+	if(mRefreshInfo)
+	{
+		const bool follow_redirects = false;
+		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+		LLHTTPClient::get(getTwitterConnectURL("/info", true), new LLTwitterInfoResponder(),
+			LLSD(), timeout, follow_redirects);
+	}
+}
+
+void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::string& status)
+{
+	LLSD body;
+	body["image"] = image_url;
+	body["status"] = status;
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::post(getTwitterConnectURL("/share/photo", true), body, new LLTwitterShareResponder());
+}
+
+void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status)
+{
+	std::string imageFormat;
+	if (dynamic_cast<LLImagePNG*>(image.get()))
+	{
+		imageFormat = "png";
+	}
+	else if (dynamic_cast<LLImageJPEG*>(image.get()))
+	{
+		imageFormat = "jpg";
+	}
+	else
+	{
+		llwarns << "Image to upload is not a PNG or JPEG" << llendl;
+		return;
+	}
+	
+	// All this code is mostly copied from LLWebProfile::post()
+	const std::string boundary = "----------------------------0123abcdefab";
+
+	LLSD headers;
+	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
+
+	std::ostringstream body;
+
+	// *NOTE: The order seems to matter.
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"status\"\r\n\r\n"
+			<< status << "\r\n";
+
+	body	<< "--" << boundary << "\r\n"
+			<< "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << imageFormat << "\"\r\n"
+			<< "Content-Type: image/" << imageFormat << "\r\n\r\n";
+
+	// Insert the image data.
+	// *FIX: Treating this as a string will probably screw it up ...
+	U8* image_data = image->getData();
+	for (S32 i = 0; i < image->getDataSize(); ++i)
+	{
+		body << image_data[i];
+	}
+
+	body <<	"\r\n--" << boundary << "--\r\n";
+
+	// postRaw() takes ownership of the buffer and releases it later.
+	size_t size = body.str().size();
+	U8 *data = new U8[size];
+	memcpy(data, body.str().data(), size);
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::postRaw(getTwitterConnectURL("/share/photo", true), data, size, new LLTwitterShareResponder(), headers);
+}
+
+void LLTwitterConnect::updateStatus(const std::string& status)
+{
+	LLSD body;
+	body["status"] = status;
+	
+    // Note: we can use that route for different publish action. We should be able to use the same responder.
+	LLHTTPClient::post(getTwitterConnectURL("/share/status", true), body, new LLTwitterShareResponder());
+}
+
+void LLTwitterConnect::storeInfo(const LLSD& info)
+{
+	mInfo = info;
+	mRefreshInfo = false;
+
+	sInfoWatcher->post(info);
+}
+
+const LLSD& LLTwitterConnect::getInfo() const
+{
+	return mInfo;
+}
+
+void LLTwitterConnect::clearInfo()
+{
+	mInfo = LLSD();
+}
+
+void LLTwitterConnect::setDataDirty()
+{
+	mRefreshInfo = true;
+}
+
+void LLTwitterConnect::setConnectionState(LLTwitterConnect::EConnectionState connection_state)
+{
+	if(connection_state == TWITTER_CONNECTED)
+	{
+		mReadFromMaster = true;
+		setConnected(true);
+		setDataDirty();
+	}
+	else if(connection_state == TWITTER_NOT_CONNECTED)
+	{
+		setConnected(false);
+	}
+	else if(connection_state == TWITTER_POSTED)
+	{
+		mReadFromMaster = false;
+	}
+
+	if (mConnectionState != connection_state)
+	{
+		LLSD state_info;
+		state_info["enum"] = connection_state;
+		sStateWatcher->post(state_info);
+	}
+	
+	mConnectionState = connection_state;
+}
+
+void LLTwitterConnect::setConnected(bool connected)
+{
+	mConnected = connected;
+}
diff --git a/indra/newview/lltwitterconnect.h b/indra/newview/lltwitterconnect.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1df13f18cf558ea934ebe35983c770a6f84bc2e
--- /dev/null
+++ b/indra/newview/lltwitterconnect.h
@@ -0,0 +1,99 @@
+/** 
+ * @file lltwitterconnect.h
+ * @author Merov, Cho
+ * @brief Connection to Twitter Service
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTWITTERCONNECT_H
+#define LL_LLTWITTERCONNECT_H
+
+#include "llsingleton.h"
+#include "llimage.h"
+
+class LLEventPump;
+
+/**
+ * @class LLTwitterConnect
+ *
+ * Manages authentication to, and interaction with, a web service allowing the
+ * the viewer to post status updates and upload photos to Twitter.
+ */
+class LLTwitterConnect : public LLSingleton<LLTwitterConnect>
+{
+	LOG_CLASS(LLTwitterConnect);
+public:
+    enum EConnectionState
+	{
+		TWITTER_NOT_CONNECTED = 0,
+		TWITTER_CONNECTION_IN_PROGRESS = 1,
+		TWITTER_CONNECTED = 2,
+		TWITTER_CONNECTION_FAILED = 3,
+		TWITTER_POSTING = 4,
+		TWITTER_POSTED = 5,
+		TWITTER_POST_FAILED = 6,
+		TWITTER_DISCONNECTING = 7,
+		TWITTER_DISCONNECT_FAILED = 8
+	};
+	
+	void connectToTwitter(const std::string& request_token = "", const std::string& oauth_verifier = "");	// Initiate the complete Twitter connection. Please use checkConnectionToTwitter() in normal use.
+	void disconnectFromTwitter();																			// Disconnect from the Twitter service.
+    void checkConnectionToTwitter(bool auto_connect = false);												// Check if an access token is available on the Twitter service. If not, call connectToTwitter().
+    
+	void loadTwitterInfo();
+	void uploadPhoto(const std::string& image_url, const std::string& status);
+	void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status);
+	void updateStatus(const std::string& status);
+	
+	void storeInfo(const LLSD& info);
+	const LLSD& getInfo() const;
+	void clearInfo();
+	void setDataDirty();
+    
+    void setConnectionState(EConnectionState connection_state);
+	void setConnected(bool connected);
+	bool isConnected() { return mConnected; }
+	bool isTransactionOngoing() { return ((mConnectionState == TWITTER_CONNECTION_IN_PROGRESS) || (mConnectionState == TWITTER_POSTING) || (mConnectionState == TWITTER_DISCONNECTING)); }
+    EConnectionState getConnectionState() { return mConnectionState; }
+    
+    void openTwitterWeb(std::string url);
+
+private:
+	friend class LLSingleton<LLTwitterConnect>;
+
+	LLTwitterConnect();
+	~LLTwitterConnect() {};
+ 	std::string getTwitterConnectURL(const std::string& route = "", bool include_read_from_master = false);
+
+    EConnectionState mConnectionState;
+	BOOL mConnected;
+	LLSD mInfo;
+	bool mRefreshInfo;
+	bool mReadFromMaster;
+	
+	static boost::scoped_ptr<LLEventPump> sStateWatcher;
+	static boost::scoped_ptr<LLEventPump> sInfoWatcher;
+	static boost::scoped_ptr<LLEventPump> sContentWatcher;
+};
+
+#endif // LL_LLTWITTERCONNECT_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 4ce049df03ffa1b6b62896aa456f351ab0224993..1e07aaf5ec27aef8885049bc97bfefeec612b023 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -53,13 +53,14 @@
 #include "llfloaterconversationlog.h"
 #include "llfloaterconversationpreview.h"
 #include "llfloaterdeleteenvpreset.h"
+#include "llfloaterdestinations.h"
 #include "llfloaterdisplayname.h"
 #include "llfloatereditdaycycle.h"
 #include "llfloatereditsky.h"
 #include "llfloatereditwater.h"
 #include "llfloaterenvironmentsettings.h"
 #include "llfloaterevent.h"
-#include "llfloaterdestinations.h"
+#include "llfloaterflickr.h"
 #include "llfloaterfonttest.h"
 #include "llfloatergesture.h"
 #include "llfloatergodtools.h"
@@ -115,6 +116,7 @@
 #include "llfloatertopobjects.h"
 #include "llfloatertoybox.h"
 #include "llfloatertranslationsettings.h"
+#include "llfloatertwitter.h"
 #include "llfloateruipreview.h"
 #include "llfloatervoiceeffect.h"
 #include "llfloatervoicevolume.h"
@@ -305,6 +307,8 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);
 	LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>);
 	LLFloaterReg::add("social", "floater_social.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSocial>);
+	LLFloaterReg::add("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFlickr>);
+	LLFloaterReg::add("twitter", "floater_twitter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTwitter>);
 	LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);
 	LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);
 	LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);
@@ -312,8 +316,10 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>);
 	LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
 	LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
-	LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);	
+	LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
 	LLFloaterReg::add("fbc_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
+	LLFloaterReg::add("flickr_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
+	LLFloaterReg::add("twitter_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
 	
 	LLFloaterUIPreviewUtil::registerFloater();
 	LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload");
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 94c187e21a78b3f306e29e3f413c2824b20a8eac..e42743824e5e7fd41264163bf174635f4afbe162 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -149,6 +149,8 @@ with the same filename but different name
   <texture name="Command_Profile_Icon"      file_name="toolbar_icons/profile.png"      preload="true" />
   <texture name="Command_Search_Icon"       file_name="toolbar_icons/search.png"       preload="true" />
   <texture name="Command_Social_Icon"       file_name="toolbar_icons/facebook.png"     preload="true" />
+  <texture name="Command_Flickr_Icon"       file_name="toolbar_icons/flickr.png"     preload="true" />
+  <texture name="Command_Twitter_Icon"      file_name="toolbar_icons/twitter.png"     preload="true" />
   <texture name="Command_Snapshot_Icon"     file_name="toolbar_icons/snapshot.png"     preload="true" />
   <texture name="Command_Speak_Icon"        file_name="toolbar_icons/speak.png"        preload="true" />
   <texture name="Command_View_Icon"         file_name="toolbar_icons/view.png"         preload="true" />
diff --git a/indra/newview/skins/default/textures/toolbar_icons/flickr.png b/indra/newview/skins/default/textures/toolbar_icons/flickr.png
new file mode 100644
index 0000000000000000000000000000000000000000..7fce9f0df24675f2af445689467a21ec14796a54
Binary files /dev/null and b/indra/newview/skins/default/textures/toolbar_icons/flickr.png differ
diff --git a/indra/newview/skins/default/textures/toolbar_icons/twitter.png b/indra/newview/skins/default/textures/toolbar_icons/twitter.png
new file mode 100644
index 0000000000000000000000000000000000000000..a99c490887eafde50d0b4295d3bd93efafab3dda
Binary files /dev/null and b/indra/newview/skins/default/textures/toolbar_icons/twitter.png differ
diff --git a/indra/newview/skins/default/xui/en/floater_flickr.xml b/indra/newview/skins/default/xui/en/floater_flickr.xml
new file mode 100644
index 0000000000000000000000000000000000000000..57014f8427ba88dbd0e9d2d9548e084755952a10
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_flickr.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<floater
+  positioning="cascading"
+  can_close="true"
+  can_resize="false"
+  help_topic="floater_flickr"
+  layout="topleft"
+  name="floater_flickr"
+  save_rect="true"
+  single_instance="true"
+  reuse_instance="true"
+  title="UPLOAD TO FLICKR"
+  height="622"
+  width="304">
+  <panel
+   height="622"
+   width="304"
+   visible="true"
+   name="background"
+   follows="all"
+   top="0"
+   left="0">
+   <tab_container
+     name="tabs"
+     tab_group="1"
+     tab_min_width="70"
+     tab_height="30"
+     tab_position="top"
+     top="7"
+     height="577"
+     halign="center">
+     <panel
+       filename="panel_flickr_photo.xml"
+       class="llflickrphotopanel"
+       follows="all"
+       label="PHOTO"
+       name="panel_flickr_photo"/>
+     <panel
+       filename="panel_flickr_account.xml"
+       class="llflickraccountpanel"
+       follows="all"
+       label="ACCOUNT"
+       name="panel_flickr_account"/>     
+    </tab_container>
+    <panel
+     name="connection_status_panel"
+     follows="left|bottom|right"
+     height="24">
+     <text
+      name="connection_error_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left="9"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="DrYellow"
+      font="SansSerif">
+      Error
+     </text>
+     <loading_indicator
+      follows="left|bottom|right"
+      height="24"
+      width="24"
+      name="connection_loading_indicator"
+      top="2"
+      left="9"
+      visible="true"/>
+     <text
+      name="connection_loading_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left_pad="5"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="EmphasisColor"
+      font="SansSerif">
+      Loading...
+    </text>
+  </panel>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml
index 853c209bcac0e4395a287dcef2142e6a187ec5fa..019ddad33cf50f5ed2fac26f83120ae579f7c668 100755
--- a/indra/newview/skins/default/xui/en/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml
@@ -10,7 +10,7 @@
  help_topic="snapshot"
  save_rect="true"
  save_visibility="false"
- title="SNAPSHOT PREVIEW"
+ title="SNAPSHOT"
  width="470">
     <floater.string
      name="unknown">
diff --git a/indra/newview/skins/default/xui/en/floater_twitter.xml b/indra/newview/skins/default/xui/en/floater_twitter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7007a14cdb067e0224aca0517dde2261887e7ce9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_twitter.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<floater
+  positioning="cascading"
+  can_close="true"
+  can_resize="false"
+  help_topic="floater_twitter"
+  layout="topleft"
+  name="floater_twitter"
+  save_rect="true"
+  single_instance="true"
+  reuse_instance="true"
+  title="TWITTER"
+  height="482"
+  width="304">
+  <panel
+   height="482"
+   width="304"
+   visible="true"
+   name="background"
+   follows="all"
+   top="0"
+   left="0">
+   <tab_container
+     name="tabs"
+     tab_group="1"
+     tab_min_width="70"
+     tab_height="30"
+     tab_position="top"
+     top="7"
+     height="437"
+     halign="center">
+     <panel
+       filename="panel_twitter_photo.xml"
+       class="lltwitterphotopanel"
+       follows="all"
+       label="COMPOSE"
+       name="panel_twitter_photo"/>
+     <panel
+       filename="panel_twitter_account.xml"
+       class="lltwitteraccountpanel"
+       follows="all"
+       label="ACCOUNT"
+       name="panel_twitter_account"/>     
+    </tab_container>
+    <panel
+     name="connection_status_panel"
+     follows="left|bottom|right"
+     height="24">
+     <text
+      name="connection_error_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left="9"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="DrYellow"
+      font="SansSerif">
+      Error
+     </text>
+     <loading_indicator
+      follows="left|bottom|right"
+      height="24"
+      width="24"
+      name="connection_loading_indicator"
+      top="2"
+      left="9"
+      visible="true"/>
+     <text
+      name="connection_loading_text"
+      type="string"
+      follows="left|bottom|right"
+      top="5"
+      left_pad="5"
+      width="250"
+      height="20"
+      wrap="true"
+      halign="left"
+      valign="center"
+      text_color="EmphasisColor"
+      font="SansSerif">
+      Loading...
+    </text>
+  </panel>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index d635b8ee93e3c39c02e9e5440ff3f61493d6c939..79adb4e8bb8def093606bc1cc3bbcece5e2060e8 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -15,14 +15,6 @@
          function="ShowAgentProfile"
          parameter="agent" />
       </menu_item_call>
-      <menu_item_call
-        label="Post to Facebook..."
-        name="PostToFacebook">
-        <menu_item_call.on_click
-          function="Floater.Toggle"
-          parameter="social"/>
-      </menu_item_call>      
-      <menu_item_separator/>
       <menu_item_call
        label="Appearance..."
        name="ChangeOutfit">
@@ -288,6 +280,28 @@
              parameter="conversation" />
         </menu_item_check>
         <menu_item_separator/>
+      <menu_item_call
+        label="Facebook..."
+        name="Facebook">
+        <menu_item_call.on_click
+          function="Floater.Toggle"
+          parameter="social"/>
+      </menu_item_call>
+      <menu_item_call
+        label="Twitter..."
+        name="Twitter">
+        <menu_item_call.on_click
+          function="Floater.Toggle"
+          parameter="twitter"/>
+      </menu_item_call>
+      <menu_item_call
+        label="Flickr..."
+        name="Flickr">
+        <menu_item_call.on_click
+          function="Floater.Toggle"
+          parameter="flickr"/>
+      </menu_item_call>
+        <menu_item_separator/>
         <menu
          label="Voice morphing"
          name="VoiceMorphing"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index e7c89db06907e31966b1eab3297c69c85208a2bc..a3c0682aea8c47286d4347f514920ea3ab2a382b 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6044,7 +6044,21 @@ Please select at least one type of content to search (General, Moderate, or Adul
   type="notifytip">
 [MESSAGE]
  </notification>
-    
+
+  <notification
+   icon="notify.tga"
+   name="FlickrConnect"
+   type="notifytip">
+    [MESSAGE]
+  </notification>
+
+  <notification
+   icon="notify.tga"
+   name="TwitterConnect"
+   type="notifytip">
+    [MESSAGE]
+  </notification>
+
   <notification
    icon="notify.tga"
    name="PaymentReceived"
diff --git a/indra/newview/skins/default/xui/en/panel_flickr_account.xml b/indra/newview/skins/default/xui/en/panel_flickr_account.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3a388520490d854a3b93d87f2fdc024906f96465
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_flickr_account.xml
@@ -0,0 +1,75 @@
+<panel
+	 height="540"
+	 width="304"
+	 layout="topleft"
+   name="panel_flickr_account">
+  <string
+      name="flickr_connected"
+      value="You are connected to Flickr as:" />
+  <string
+      name="flickr_disconnected"
+      value="Not connected to Flickr" />
+  <text
+   layout="topleft"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_caption_label"
+   top="21"
+   type="string">
+    Not connected to Flickr.
+  </text>
+  <text
+   layout="topleft"
+   top_pad="2"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_name_label"
+   parse_urls="true"
+   type="string"/>
+  <panel
+    layout="topleft"
+    name="panel_buttons"
+    height="345"
+    left="9">
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_pad="9"
+     visible="true"
+     height="23"
+     label="Connect..."
+     name="connect_btn"
+     width="210">
+      <commit_callback function="SocialSharing.Connect"/>
+    </button>
+
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_delta="0"
+     height="23"
+     label="Disconnect"
+     name="disconnect_btn"
+     width="210"
+     visible="false">
+      <commit_callback function="SocialSharing.Disconnect"/>
+    </button>
+    <text
+      layout="topleft"
+      length="1"
+      follows="top|left"
+      height="16"
+      left="0"
+      name="account_learn_more_label"
+      top_pad="20"
+      type="string">
+      [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share/ta-p/2149711 Learn about posting to Flickr]
+    </text>
+  </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_flickr_photo.xml b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b3af271f34a17b24e91ffd609cf7577a71393865
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml
@@ -0,0 +1,231 @@
+    <panel
+      height="540"
+      width="304"
+      layout="topleft"
+      name="panel_flickr_photo">
+      <layout_stack
+	   layout="topleft"
+       border_size="0"
+       height="532"
+       follows="all"
+       orientation="vertical"
+       name="stack_photo"
+       top="8">
+        <layout_panel	
+         name="snapshot_panel"
+         height="507">
+            <combo_box
+             control_name="SocialPhotoResolution"
+             follows="left|top"
+             top="6"
+             left="9"
+             name="resolution_combobox"
+             tool_tip="Image resolution"
+             height="21"
+             width="135">
+              <combo_box.item
+               label="Current Window"
+               name="CurrentWindow"
+               value="[i0,i0]" />
+              <combo_box.item
+               label="640x480"
+               name="640x480"
+               value="[i640,i480]" />
+              <combo_box.item
+               label="800x600"
+               name="800x600"
+               value="[i800,i600]" />
+              <combo_box.item
+               label="1024x768"
+               name="1024x768"
+               value="[i1024,i768]" />
+            </combo_box>
+            <text
+             follows="left|top"
+             font="SansSerifSmall"
+             height="14"
+             left="208"
+             length="1"
+             halign="right"
+             name="file_size_label"
+             top="9"
+             type="string"
+             width="50">
+              [SIZE] KB
+            </text>
+            <panel
+                height="150"
+                width="250"
+                visible="true"
+                name="thumbnail_placeholder"
+                top="33"
+                follows="left|top"
+                left="9">
+            </panel>
+            <button
+             follows="left|top"
+             height="23"
+             label="Refresh"
+             left="9"
+             top_pad="5"
+             name="new_snapshot_btn"
+             tool_tip="Click to refresh"
+             visible="true"
+             width="100" >
+             <button.commit_callback
+               function="SocialSharing.RefreshPhoto" />
+            </button>
+            <text
+                follows="left|top"
+                font="SansSerif"
+                text_color="EmphasisColor"
+                height="14"
+                top_pad="-19"
+                left_pad="-20"
+                length="1"
+                halign="center"
+                name="working_lbl"
+                translate="false"
+                type="string"
+                visible="true"
+                width="150">
+                Refreshing...
+            </text>
+            <text
+             length="1"
+             follows="top|left|right"
+             font="SansSerif"
+             height="16"
+             left="9"
+             name="title_label"
+             top_pad="20"
+             type="string">
+              Title:
+            </text>
+            <line_editor
+             follows="left|top"
+             height="20"
+             width="250"
+             left="9"
+             length="1"
+             max_length="256"
+             name="photo_title"
+             type="string">
+            </line_editor>
+            <text
+             length="1"
+             follows="top|left|right"
+             font="SansSerif"
+             height="16"
+             left="9"
+             name="description_label"
+             top_pad="10"
+             type="string">
+              Description:
+            </text>
+            <text_editor
+             follows="left|top"
+             height="50"
+             width="250"
+             left="9"
+             length="1"
+             max_length="700"
+             name="photo_description"
+             type="string"
+             word_wrap="true">
+            </text_editor>
+            <check_box
+             follows="left|top"
+             initial_value="true"
+             label="Include SL location at end of description"
+             name="add_location_cb"
+              left="9"
+              height="16"
+             top_pad="8"/>
+            <text
+             length="1"
+             follows="top|left|right"
+             font="SansSerif"
+             height="16"
+             left="9"
+             name="tags_label"
+             top_pad="10"
+             type="string">
+              Tags:
+            </text>
+            <text
+              length="1"
+              follows="top|left"
+              font="SansSerifSmall"
+              text_color="White_50"
+              height="30"
+              name="tags_help_label"
+              left="50"
+              top_pad="-16"
+              type="string">
+Separate tags with spaces
+Use "" for multi-word tags
+            </text>
+            <text_editor
+             follows="left|top"
+             height="50"
+             width="250"
+             left="9"
+             length="1"
+             max_length="700"
+             name="photo_tags"
+             type="string"
+             word_wrap="true">
+            </text_editor>
+            <combo_box
+             control_name="FlickrPhotoRating"
+             follows="left|top"
+             top_pad="16"
+             left="9"
+             label="Choose Flickr rating (required)..."
+             name="rating_combobox"
+             tool_tip="Flickr content rating"
+             height="21"
+             width="250">
+              <combo_box.item
+               label="Safe content rating"
+               name="SafeRating"
+               value="1" />
+              <combo_box.item
+               label="Moderate content rating"
+               name="ModerateRating"
+               value="2" />
+              <combo_box.item
+               label="Restricted content rating"
+               name="RestrictedRating"
+               value="3" />
+            </combo_box>
+        </layout_panel>
+        <layout_panel
+          name="photo_button_panel"
+          height="25">
+          <button
+           follows="left|top"
+           top="0"
+           left="9"
+           height="23"
+           label="Upload"
+           name="post_photo_btn"
+           width="100">
+            <button.commit_callback
+             function="SocialSharing.SendPhoto" />
+          </button>
+          <button
+               follows="left|top"
+               height="23"
+               label="Cancel"
+               name="cancel_photo_btn"
+               left_pad="15"
+               top_delta="0"
+               width="100">
+            <button.commit_callback
+             function="SocialSharing.Cancel" />
+          </button>          
+        </layout_panel>        
+      </layout_stack>
+    </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
index 61c8c971c28766cb8968175ba418f039f904acef..eff60f8228bcaaaa7026ead068999cddb0b1a7cd 100755
--- a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
@@ -81,4 +81,40 @@
     <button.commit_callback
      function="Snapshot.SaveToComputer" />
   </button>
+  <text
+    font="SansSerif"
+    layout="topleft"
+    length="1"
+    follows="top|left"
+    height="16"
+    left="10"
+    name="send_to_facebook_textbox"
+    top_pad="10"
+    type="string">
+    Send to:  [secondlife:/// Facebook]
+  </text>
+  <text
+    font="SansSerif"
+    layout="topleft"
+    length="1"
+    follows="top|left"
+    height="16"
+    left="140"
+    name="send_to_twitter_textbox"
+    top_pad="-16"
+    type="string">
+    [secondlife:/// Twitter]
+  </text>
+  <text
+    font="SansSerif"
+    layout="topleft"
+    length="1"
+    follows="top|left"
+    height="16"
+    left="190"
+    name="send_to_flickr_textbox"
+    top_pad="-16"
+    type="string">
+    [secondlife:/// Flickr]
+  </text>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_twitter_account.xml b/indra/newview/skins/default/xui/en/panel_twitter_account.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4a413bd711584f7d62d4afe0a3c5db94fedb11bc
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_twitter_account.xml
@@ -0,0 +1,75 @@
+<panel
+	 height="400"
+	 width="304"
+	 layout="topleft"
+   name="panel_twitter_account">
+  <string
+      name="twitter_connected"
+      value="You are connected to Twitter as:" />
+  <string
+      name="twitter_disconnected"
+      value="Not connected to Twitter" />
+  <text
+   layout="topleft"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_caption_label"
+   top="21"
+   type="string">
+    Not connected to Twitter.
+  </text>
+  <text
+   layout="topleft"
+   top_pad="2"
+   length="1"
+   follows="top|left"
+   font="SansSerif"
+   height="16"
+   left="9"
+   name="account_name_label"
+   parse_urls="true"
+   type="string"/>
+  <panel
+    layout="topleft"
+    name="panel_buttons"
+    height="345"
+    left="9">
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_pad="9"
+     visible="true"
+     height="23"
+     label="Connect..."
+     name="connect_btn"
+     width="210">
+      <commit_callback function="SocialSharing.Connect"/>
+    </button>
+
+    <button
+     layout="topleft"
+     follows="left|top"
+     top_delta="0"
+     height="23"
+     label="Disconnect"
+     name="disconnect_btn"
+     width="210"
+     visible="false">
+      <commit_callback function="SocialSharing.Disconnect"/>
+    </button>
+    <text
+      layout="topleft"
+      length="1"
+      follows="top|left"
+      height="16"
+      left="0"
+      name="account_learn_more_label"
+      top_pad="20"
+      type="string">
+      [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share/ta-p/2149711 Learn about posting to Twitter]
+    </text>
+  </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_twitter_photo.xml b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8e2412c84e5dc73b46d2fa91149187bbf612be94
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml
@@ -0,0 +1,156 @@
+    <panel
+      height="400"
+      width="304"
+      layout="topleft"
+      name="panel_twitter_photo">
+      <layout_stack
+	   layout="topleft"
+       border_size="0"
+       height="392"
+       follows="all"
+       orientation="vertical"
+       name="stack_photo"
+       top="8">
+        <layout_panel
+         name="text_panel"
+         height="140">
+          <text
+           length="1"
+           follows="top|left|right"
+           font="SansSerif"
+           height="16"
+           left="9"
+           name="status_label"
+           top="3"
+           type="string">
+            What's happening?
+          </text>
+          <text_editor
+           follows="left|top"
+           height="87"
+           width="250"
+           left="9"
+           length="1"
+           max_length="140"
+           name="photo_status"
+           type="string"
+           word_wrap="true">
+          </text_editor>
+          <check_box
+           follows="left|top"
+           initial_value="true"
+           label="Include a photo"
+           name="add_photo_cb"
+            left="9"
+            height="16"
+           top_pad="10"/>
+        </layout_panel>
+          <layout_panel
+           name="snapshot_panel"
+           height="227">
+            <combo_box
+             control_name="SocialPhotoResolution"
+             follows="left|top"
+             top="6"
+             left="9"
+             name="resolution_combobox"
+             tool_tip="Image resolution"
+             height="21"
+             width="135">
+              <combo_box.item
+               label="Current Window"
+               name="CurrentWindow"
+               value="[i0,i0]" />
+              <combo_box.item
+               label="640x480"
+               name="640x480"
+               value="[i640,i480]" />
+              <combo_box.item
+               label="800x600"
+               name="800x600"
+               value="[i800,i600]" />
+              <combo_box.item
+               label="1024x768"
+               name="1024x768"
+               value="[i1024,i768]" />
+            </combo_box>
+            <text
+             follows="left|top"
+             font="SansSerifSmall"
+             height="14"
+             left="208"
+             length="1"
+             halign="right"
+             name="file_size_label"
+             top="9"
+             type="string"
+             width="50">
+              [SIZE] KB
+            </text>
+            <panel
+                height="150"
+                width="250"
+                visible="true"
+                name="thumbnail_placeholder"
+                top="33"
+                follows="left|top"
+                left="9">
+            </panel>
+            <button
+             follows="left|top"
+             height="23"
+             label="Refresh"
+             left="9"
+             top_pad="5"
+             name="new_snapshot_btn"
+             tool_tip="Click to refresh"
+             visible="true"
+             width="100" >
+             <button.commit_callback
+               function="SocialSharing.RefreshPhoto" />
+            </button>
+            <text
+                follows="left|top"
+                font="SansSerif"
+                text_color="EmphasisColor"
+                height="14"
+                top_pad="-19"
+                left_pad="-20"
+                length="1"
+                halign="center"
+                name="working_lbl"
+                translate="false"
+                type="string"
+                visible="true"
+                width="150">
+                Refreshing...
+            </text>
+        </layout_panel>
+        <layout_panel
+          name="photo_button_panel"
+          height="25">
+          <button
+           follows="left|top"
+           top="0"
+           left="9"
+           height="23"
+           label="Tweet"
+           name="post_photo_btn"
+           width="100">
+            <button.commit_callback
+             function="SocialSharing.SendPhoto" />
+          </button>
+          <button
+               follows="left|top"
+               height="23"
+               label="Cancel"
+               name="cancel_photo_btn"
+               left_pad="15"
+               top_delta="0"
+               width="100">
+            <button.commit_callback
+             function="SocialSharing.Cancel" />
+          </button>          
+        </layout_panel>        
+      </layout_stack>
+    </panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 8ac95beddb329738c229bdfe0db4e27cd097f77e..b24cca588ea1c04277c2617d95bda84559590224 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -148,13 +148,25 @@ Please try logging in again in a minute.</string>
 	<string name="SentToInvalidRegion">You were sent to an invalid region.</string>
 	<string name="TestingDisconnect">Testing viewer disconnect</string>
 
-	<!-- Facebook Connect and, eventually, other Social Network -->
-	<string name="SocialFacebookConnecting">Connecting to Facebook...</string>
-	<string name="SocialFacebookPosting">Posting...</string>
-	<string name="SocialFacebookDisconnecting">Disconnecting from Facebook...</string>
-	<string name="SocialFacebookErrorConnecting">Problem connecting to Facebook</string>
-	<string name="SocialFacebookErrorPosting">Problem posting to Facebook</string>
-	<string name="SocialFacebookErrorDisconnecting">Problem disconnecting from Facebook</string>
+	<!-- SLShare: Facebook, Flickr, and Twitter -->
+  <string name="SocialFacebookConnecting">Connecting to Facebook...</string>
+  <string name="SocialFacebookPosting">Posting...</string>
+  <string name="SocialFacebookDisconnecting">Disconnecting from Facebook...</string>
+  <string name="SocialFacebookErrorConnecting">Problem connecting to Facebook</string>
+  <string name="SocialFacebookErrorPosting">Problem posting to Facebook</string>
+  <string name="SocialFacebookErrorDisconnecting">Problem disconnecting from Facebook</string>
+  <string name="SocialFlickrConnecting">Connecting to Flickr...</string>
+  <string name="SocialFlickrPosting">Posting...</string>
+  <string name="SocialFlickrDisconnecting">Disconnecting from Flickr...</string>
+  <string name="SocialFlickrErrorConnecting">Problem connecting to Flickr</string>
+  <string name="SocialFlickrErrorPosting">Problem posting to Flickr</string>
+  <string name="SocialFlickrErrorDisconnecting">Problem disconnecting from Flickr</string>
+  <string name="SocialTwitterConnecting">Connecting to Twitter...</string>
+  <string name="SocialTwitterPosting">Posting...</string>
+  <string name="SocialTwitterDisconnecting">Disconnecting from Twitter...</string>
+  <string name="SocialTwitterErrorConnecting">Problem connecting to Twitter</string>
+  <string name="SocialTwitterErrorPosting">Problem posting to Twitter</string>
+  <string name="SocialTwitterErrorDisconnecting">Problem disconnecting from Twitter</string>
     
 	<!-- Tooltip -->
 	<string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar -->
@@ -3442,6 +3454,12 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
   <string name="facebook_post_success">
     You posted to Facebook.
   </string>
+  <string name="flickr_post_success">
+    You posted to Flickr.
+  </string>
+  <string name="twitter_post_success">
+    You posted to Twitter.
+  </string>
 
   <string name="no_session_message">
     (IM Session Doesn't Exist)
@@ -3875,6 +3893,8 @@ Try enclosing path to the editor with double quotes.
   <string name="Command_Search_Label">Search</string>
   <string name="Command_Snapshot_Label">Snapshot</string>
   <string name="Command_Social_Label">Facebook</string>
+  <string name="Command_Flickr_Label">Flickr</string>
+  <string name="Command_Twitter_Label">Twitter</string>
   <string name="Command_Speak_Label">Speak</string>
   <string name="Command_View_Label">Camera controls</string>
   <string name="Command_Voice_Label">Voice settings</string>
@@ -3903,6 +3923,8 @@ Try enclosing path to the editor with double quotes.
   <string name="Command_Search_Tooltip">Find places, events, people</string>
   <string name="Command_Snapshot_Tooltip">Take a picture</string>
   <string name="Command_Social_Tooltip">Post to Facebook</string>
+  <string name="Command_Flickr_Tooltip">Upload to Flickr</string>
+  <string name="Command_Twitter_Tooltip">Twitter</string>
   <string name="Command_Speak_Tooltip">Speak with people nearby using your microphone</string>
   <string name="Command_View_Tooltip">Changing camera angle</string>
   <string name="Command_Voice_Tooltip">Volume controls for calls and people near you in world</string>