Fix extension

- Delete social network code
- Fix save functionality
- Fix "Port closed" error
diff --git a/src/js/account.js b/src/js/account.js
deleted file mode 100644
index d8ddd0d..0000000
--- a/src/js/account.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**

- * Create a user.

- * @param {Object} user

- *   properties: id, name, accessToken, expires, accessTokenSecret, albumId

- */

-var User = function(user) {

-  for (var prop in user) {

-    this[prop] = user[prop];

-  }

-};

-

-var Account = {

-

-  getUsers: function(siteId) {

-    var users = localStorage.getItem(siteId + '_userInfo');

-    if (users) {

-      users = JSON.parse(users);

-      for (var id in users) {

-        // Remove expired user.

-        if (Account.isExpires(users[id])) {

-          delete users[id];

-        }

-      }

-      localStorage.setItem(siteId + '_userInfo', JSON.stringify(users));

-      return users;

-    }

-    return {};

-  },

-

-  getUser: function(siteId, userId) {

-    var users = Account.getUsers(siteId);

-    var user = users[userId];

-    if (user && Account.isExpires(user)) {

-      Account.removeUser(siteId, userId);

-      return null;

-    } else {

-      return user;

-    }

-  },

-

-  addUser: function(siteId, user) {

-    var users = Account.getUsers(siteId);

-    var userId = user.id;

-    if (!users[userId]) {

-      users[userId] = user;

-      users = JSON.stringify(users);

-      localStorage.setItem(siteId + '_userInfo', users);

-    }

-  },

-

-  updateUser: function(siteId, user) {

-    var users = Account.getUsers(siteId);

-    var userId = user.id;

-    if (users && users[userId]) {

-      users[userId] = user;

-      users = JSON.stringify(users);

-      localStorage.setItem(siteId + '_userInfo', users);

-    }

-  },

-  

-  removeUser: function(siteId, userId) {

-    var users = Account.getUsers(siteId);

-    delete users[userId];

-    users = JSON.stringify(users);

-    localStorage.setItem(siteId + '_userInfo', users);

-  },

-

-  isExpires: function(user) {

-    var expires = user.expires;

-    if (expires) {

-      return new Date().getTime() >= expires;

-    }

-    return false;

-  }

-};
\ No newline at end of file
diff --git a/src/js/ajax.js b/src/js/ajax.js
deleted file mode 100644
index 2f3d4a5..0000000
--- a/src/js/ajax.js
+++ /dev/null
@@ -1,185 +0,0 @@
-(function(){

-  /**

-   * ajax is a encapsulated function that used to send data to server

-   * asynchronously. It uses XMLHttpRequest object to send textual or binary

-   * data through HTTP method GET, POST etc. It can custom request method,

-   * request header. Response can be parsed automatically by MIME type of

-   * response's Content-type, and it can handle success, error or progress event

-   * in course of sending request and retrieving response.

-   * @param {Object} option

-   */

-  function ajax(option) {

-    if (arguments.length < 1 || option.constructor != Object)

-      throw new Error('Bad parameter.');

-    var url = option.url;

-    var success = option.success;

-    var complete = option.complete;

-    if (!url || !(success || complete))

-      throw new Error('Parameter url and success or complete are required.');

-

-    var parameters = option.parameters || {};

-    var method = option.method || 'GET';

-    var status = option.status;

-    var headers = option.headers || {};

-    var data = option.data || null;

-    var multipartData = option.multipartData;

-    var queryString = constructQueryString(parameters);

-

-    if (multipartData) {

-      var boundary = multipartData.boundary || 'XMLHttpRequest2';

-      method = 'POST';

-      var multipartDataString;

-      var contentType = headers['Content-Type'] || 'multipart/form-data';

-      if (contentType.indexOf('multipart/form-data') == 0) {

-        headers['Content-Type'] = 'multipart/form-data; boundary=' + boundary;

-        multipartDataString = constructMultipartFormData(multipartData, boundary,

-          parameters);

-      } else if (contentType.indexOf('multipart/related') == 0) {

-        headers['Content-Type'] = 'multipart/related; boundary=' + boundary;

-        multipartDataString = constructMultipartRelatedData(boundary,

-          multipartData.dataList);

-      }

-

-      data = constructBufferData(multipartDataString);

-    } else {

-      if (queryString)

-        url += '?' + queryString;

-    }

-

-    var xhr = new XMLHttpRequest();

-    xhr.open(method, url, true);

-    xhr.onreadystatechange = function() {

-      if (xhr.readyState == 4) {

-        var statusCode = xhr.status;

-        var parsedResponse = parseResponse(xhr);

-        if (complete)

-          complete(statusCode, parsedResponse);

-        if (success && (statusCode == 200 || statusCode == 304)) {

-          success(parsedResponse);

-        } else if (status) {

-          if (status[statusCode]) {

-            // Call specified status code handler

-            status[statusCode](parsedResponse);

-          } else if (status['others']) {

-            // Call others status code handler

-            status['others'](parsedResponse, statusCode);

-          }

-        }

-      }

-    };

-

-    // Handle request progress

-    var progress = option.progress;

-    if (progress) {

-      xhr.upload.addEventListener('progress', function(e) {

-        // lengthComputable return true when the length of the progress is known

-        if (e.lengthComputable) {

-          progress(e.loaded, e.total);

-        }

-      }, false);

-    }

-    // Set request header

-    for (var headerKey in headers) {

-      xhr.setRequestHeader(headerKey, headers[headerKey]);

-    }

-

-    xhr.send(data);

-  }

-

-  function constructQueryString(parameters) {

-    var tmpParameter = [];

-    for(var name in parameters) {

-      var value = parameters[name];

-      if (value.constructor == Array) {

-        value.forEach(function(val) {

-          tmpParameter.push(name + '=' + val);

-        });

-      } else {

-        tmpParameter.push(name + '=' + value);

-      }

-    }

-    return tmpParameter.join('&');

-  }

-

-  // Parse response data according to content type of response

-  function parseResponse(xhr) {

-    var ct = xhr.getResponseHeader("content-type");

-    if (typeof ct == 'string') {

-      if (ct.indexOf('xml') >= 0)

-        return xhr.responseXML;

-      else if (ct.indexOf('json') >= 0)

-        return JSON.parse(xhr.responseText);

-    }

-    return xhr.responseText;

-  }

-

-  /**

-   * Construct multipart/form-data formatted data string.

-   * @param {Object} binaryData binary data

-   * @param {String} boundary boundary of parts

-   * @param {Object} otherParameters other text parameters

-   */

-  function constructMultipartFormData(binaryData, boundary, otherParameters) {

-    var commonHeader = 'Content-Disposition: form-data; ';

-    var data = [];

-    for (var key in otherParameters) {

-

-      // Add boundary of one header part

-      data.push('--' + boundary + '\r\n');

-

-      // Add same Content-Disposition information

-      data.push(commonHeader);

-      data.push('name="' + key + '"\r\n\r\n' + otherParameters[key] + '\r\n');

-    }

-

-    // Construct file data header

-    data.push('--' + boundary + '\r\n');

-    data.push(commonHeader);

-

-    data.push('name="' + (binaryData.name || 'binaryfilename') + '"; ');

-    data.push('filename=\"' + binaryData.value + '\"\r\n');

-    data.push('Content-type: ' + binaryData.type + '\r\n\r\n');

-    data.push(binaryData.data + '\r\n');

-

-    data.push('--' + boundary + '--\r\n');

-    return data.join('');

-  }

-

-  function constructBufferData(dataString, contentType) {

-      var len = dataString.length;

-

-      // Create a 8-bit unsigned integer ArrayBuffer view

-      var data = new Uint8Array(len);

-      for (var i = 0; i < len; i++) {

-        data[i] = dataString.charCodeAt(i);

-      }

-

-      return data.buffer

-  }

-

-  function constructMultipartRelatedData(boundary, dataList) {

-    var result = [];

-    dataList.forEach(function(data) {

-      result.push('--' + boundary + '\r\n');

-      result.push('Content-Type: ' + data.contentType + '\r\n\r\n');

-      result.push(data.data + '\r\n');

-    });

-    result.push('--' + boundary + '--\r\n');

-    return result.join('');

-  }

-

-  ajax.encodeForBinary = function(string) {

-    string = encodeURI(string).replace(/%([A-Z0-9]{2})/g, '%u00$1');

-    return unescape(string);

-  };

-

-  ajax.convertEntityString = function(string) {

-    var entitychars = ['<', '>', '&', '"', '\''];

-    var entities = ['&lt;', '&gt;', '&amp;', '&quot;', '&apos;'];

-    entitychars.forEach(function(character, index) {

-      string = string.replace(character, entities[index]);

-    });

-    return string;

-  };

-  window.ajax = ajax;

-})();
\ No newline at end of file
diff --git a/src/js/background.js b/src/js/background.js
index e3c030e..021bed3 100644
--- a/src/js/background.js
+++ b/src/js/background.js
@@ -20,53 +20,25 @@
   captureStatus: true,
   screenshotName: null,
 
-  handleHotKey: function(keyCode) {
-    if (HotKey.isEnabled()) {
-      switch (keyCode) {
-        case HotKey.getCharCode('area'):
-          screenshot.showSelectionArea();
-          break;
-        case HotKey.getCharCode('viewport'):
-          screenshot.captureWindow();
-          break;
-        case HotKey.getCharCode('fullpage'):
-          screenshot.captureWebpage();
-          break;
-        case HotKey.getCharCode('screen'):
-          screenshot.captureScreen();
-          break;
-      }
-    }
-  },
-
   /**
   * Receive messages from content_script, and then decide what to do next
   */
   addMessageListener: function() {
     chrome.extension.onMessage.addListener(function(request, sender, response) {
+      console.log(request);
       var obj = request;
-      var hotKeyEnabled = HotKey.isEnabled();
       switch (obj.msg) {
-        case 'capture_hot_key':
-          screenshot.handleHotKey(obj.keyCode);
-          break;
         case 'capture_selected':
           screenshot.captureSelected();
           break;
         case 'capture_window':
-          if (hotKeyEnabled) {
-            screenshot.captureWindow();
-          }
+          screenshot.captureWindow();
           break;
         case 'capture_area':
-          if (hotKeyEnabled) {
-            screenshot.showSelectionArea();
-          }
+          screenshot.showSelectionArea();
           break;
         case 'capture_webpage':
-          if (hotKeyEnabled) {
-            screenshot.captureWebpage();
-          }
+          screenshot.captureWebpage();
           break;
       }
     });
@@ -305,7 +277,6 @@
           for (var i = 0; i < tabs.length; ++i) {
             if (tabs[i].url.indexOf("chrome://") != 0) {
               chrome.tabs.executeScript(tabs[i].id, { file: 'js/page.js' });
-              chrome.tabs.executeScript(tabs[i].id, { file: 'js/shortcut.js' });
             }
           }
         });
diff --git a/src/js/facebook.js b/src/js/facebook.js
deleted file mode 100644
index 68cb091..0000000
--- a/src/js/facebook.js
+++ /dev/null
@@ -1,139 +0,0 @@
-const FB_APP_ID = CURRENT_LOCALE == 'zh_CN' ? 170328509685996 : 118170701590738;

-const FB_REDIRECT_URI = 'http://www.facebook.com/connect/login_success.html';

-const FB_PERMISSION = 'offline_access,user_photos,publish_stream';

-const FB_ACCESS_TOKEN_URL = 'https://www.facebook.com/dialog/oauth';

-const FB_PHOTO_UPLOAD_URL = 'https://graph.facebook.com/me/photos';

-const FB_USER_INFO_URL = 'https://graph.facebook.com/me';

-const FB_LOGOUT_URL = 'http://m.facebook.com/logout.php?confirm=1';

-

-var Facebook = {

-  siteId: 'facebook',

-  redirectUrl: FB_REDIRECT_URI,

-  currentUserId: null,

-  accessTokenCallback: null,

-

-  isRedirectUrl: function(url) {

-    return url.indexOf(FB_REDIRECT_URI) == 0;

-  },

-  

-  getAccessToken: function(callback) {

-    Facebook.accessTokenCallback = callback;

-    var url = FB_ACCESS_TOKEN_URL + '?client_id=' + FB_APP_ID +

-      '&redirect_uri=' + FB_REDIRECT_URI + '&scope=' + FB_PERMISSION +

-      '&response_type=token';

-    chrome.tabs.create({url: url});

-  },

-

-  parseAccessToken: function(url) {

-    var queryString = url.split('#')[1] || url.split('?')[1];

-    var queries = queryString.split('&');

-    var queryMap = {};

-    queries.forEach(function(pair) {

-      queryMap[pair.split('=')[0]] = pair.split('=')[1];

-    });

-    var accessToken = queryMap['access_token'];

-    if (accessToken) {

-      var user = new User({

-        accessToken: accessToken

-      });

-      Facebook.accessTokenCallback('success', user);

-    } else if (queryMap['error']) {

-      Facebook.accessTokenCallback('failure', 'user_denied');

-    }

-    Facebook.accessTokenCallback = null;

-  },

-

-  getUserInfo: function(user, callback) {

-    ajax({

-      url: FB_USER_INFO_URL,

-      parameters: {

-        'access_token': user.accessToken

-      },

-      success: function(userInfo) {

-        userInfo = JSON.parse(userInfo);

-        if (callback) {

-          user.id = userInfo.id;

-          user.name = userInfo.name;

-          callback('success', user);

-        }

-      },

-      status: {

-        others: function() {

-          if (callback)

-            callback('failure', 'failed_to_get_user_info');

-        }

-      }

-    });

-  },

-  

-  upload: function(user, caption, imageData, callback) {

-    caption = ajax.encodeForBinary(caption);

-    var params = {

-      'access_token': user.accessToken,

-      message: caption

-    };

-    

-    var binaryData = {

-      boundary: MULTIPART_FORMDATA_BOUNDARY,

-      data: imageData,

-      value: 'test.png',

-      type: 'image/png'

-    };

-    

-    ajax({

-      url: FB_PHOTO_UPLOAD_URL,

-      parameters: params,

-      multipartData: binaryData,

-      success: function(data) {

-        callback('success', JSON.parse(data).id);

-      },

-      status: {

-        others: function(data) {

-          var message;

-          if (data) {

-            data = JSON.parse(data);

-            if (data.error.message.indexOf('access token') >= 0) {

-              // User removed application permission

-              // {"error":{"type":"OAuthException",

-              // "message":"Error validating access token."}}

-              message = 'bad_access_token';

-            } else {

-              // {"error":{"type":"OAuthException",

-              // "message":"(#1) An unknown error occurred"}}

-              message = 'unknown_error';

-            }

-          } else {

-            message = 'failed_to_connect_to_server';

-          }

-          callback('failure', message);

-        }

-      }

-    });

-  },

-

-  getPhotoLink: function(user, photoId, callback) {

-    ajax({

-      url: 'https://graph.facebook.com/' + photoId,

-      parameters: {

-        'access_token': user.accessToken

-      },

-      complete: function(statusCode, data) {

-        if (statusCode == 200) {

-          callback('success', JSON.parse(data).link);

-        } else {

-          callback('failure', 'failed_to_get_photo_link');

-        }

-      }

-    });

-  },

-

-  logout: function(callback) {

-    ajax({

-      url: FB_LOGOUT_URL,

-      success: function(data) {

-        if (callback)

-          callback(data);

-      }

-    });

-  }

-};
\ No newline at end of file
diff --git a/src/js/hotkey_storage.js b/src/js/hotkey_storage.js
deleted file mode 100644
index 9cea0aa..0000000
--- a/src/js/hotkey_storage.js
+++ /dev/null
@@ -1,54 +0,0 @@
-var HotKey = (function() {

-  return {

-    setup: function() {

-      // Default enable hot key for capture.

-      if (!localStorage.getItem('hot_key_enabled'))

-        localStorage.setItem('hot_key_enabled', true);

-

-      // Set default hot key of capture, R V H P.

-      if (!this.get('area'))

-        this.set('area', 'R');

-      if (!this.get('viewport'))

-        this.set('viewport', 'V');

-      if (!this.get('fullpage'))

-        this.set('fullpage', 'H');

-      if (!this.get('screen'))

-        this.set('screen', 'P');

-

-      var screenCaptureHotKey = this.get('screen');

-      if (this.isEnabled()) {

-        this.set('screen', '@'); // Disable hot key for screen capture.

-      }

-    },

-

-    /**

-     * Set hot key by type.

-     * @param {String} type Hot key type, must be area/viewport/fullpage/screen.

-     * @param {String} value

-     */

-    set: function(type, value) {

-      var key = type + '_capture_hot_key';

-      localStorage.setItem(key, value);

-    },

-

-    get: function(type) {

-      return localStorage.getItem(type + '_capture_hot_key');

-    },

-

-    getCharCode: function(type) {

-      return this.get(type).charCodeAt(0);

-    },

-

-    enable: function() {

-      localStorage.setItem('hot_key_enabled', true);

-    },

-

-    disable: function(bg) {

-      localStorage.setItem('hot_key_enabled', false);

-    },

-

-    isEnabled: function() {

-      return localStorage.getItem('hot_key_enabled') == 'true';

-    }

-  }

-})();

diff --git a/src/js/imgur.js b/src/js/imgur.js
deleted file mode 100644
index cfc399f..0000000
--- a/src/js/imgur.js
+++ /dev/null
@@ -1,241 +0,0 @@
-(function() {

-  const IMGUR_APP_KEY = '90922ae86b91b09541d74134a5bb0f6404e0c378f';

-  const IMGUR_APP_SECRET = 'b100656ebf595b7464e428615b9bc703';

-  const IMGUR_REQUEST_TOKEN_URL = 'https://api.imgur.com/oauth/request_token';

-  const IMGUR_USER_AUTHENTICATION_URL = 'https://api.imgur.com/oauth/authorize';

-  const IMGUR_ACCESS_TOKEN_URL = 'https://api.imgur.com/oauth/access_token';

-  const IMGUR_USER_INFO_URL = 'http://api.imgur.com/2/account.json';

-  const IMGUR_PHOTO_UPLOAD_URL = 'http://api.imgur.com/2/account/images.json';

-  const IMGUR_LOGOUT_URL = 'http://imgur.com/logout';

-  const OAUTH_SIGNATURE_METHOD = 'HMAC-SHA1';

-  const OAUTH_VERSION = '1.0';

-

-  var Imgur = window.Imgur = {

-    siteId: 'imgur',

-    currentUserId: null,

-    currentUserOauthToken: '',

-    currentUserOauthTokenSecret: '',

-    accessTokenCallback: null,

-

-    isRedirectUrl: function() {},

-

-    getAuthorizationHeader: function(message, accessor) {

-      OAuth.setTimestampAndNonce(message);

-      OAuth.SignatureMethod.sign(message, accessor);

-      return OAuth.getAuthorizationHeader("", message.parameters);

-    },

-

-    getRequestToken: function(callback) {

-      Imgur.accessTokenCallback = callback;

-      var message = {

-        action: IMGUR_REQUEST_TOKEN_URL,

-        method: 'POST',

-        parameters: {

-          'oauth_consumer_key': IMGUR_APP_KEY,

-          'oauth_signature_method': OAUTH_SIGNATURE_METHOD,

-          'oauth_version': OAUTH_VERSION

-        }

-      };

-      var accessor = {

-        consumerKey: IMGUR_APP_KEY,

-        consumerSecret: IMGUR_APP_SECRET

-      };

-

-      // Get oauth signature header

-      var header = Imgur.getAuthorizationHeader(message, accessor);

-

-      ajax({

-        url: IMGUR_REQUEST_TOKEN_URL,

-        method: 'POST',

-        headers: {

-          'Authorization': header

-        },

-        success: function(response) {

-          parameters = OAuth.getParameterMap(response);

-          var oauth_token = parameters['oauth_token'];

-          var oauth_token_secret = parameters['oauth_token_secret'];

-          Imgur.currentUserOauthToken = oauth_token;

-          Imgur.currentUserOauthTokenSecret = oauth_token_secret;

-          Imgur.getUserAuthentication(oauth_token);

-        },

-        status: {

-          others: function() {

-            callback('failure', 'imgur_failed_to_get_request_token');

-          }

-        }

-      });

-    },

-

-    getUserAuthentication: function(oauth_token) {

-      var url = IMGUR_USER_AUTHENTICATION_URL + '?oauth_token=' + oauth_token +

-        '&oauth_callback=ready';

-      chrome.tabs.create({url: url}, function(tab) {

-          chrome.tabs.onUpdated.addListener(

-            function(tabId, changeInfo, _tab) {

-              if (tabId == tab.id && changeInfo.url

-                  && changeInfo.url.indexOf('oauth_verifier=') > 0) {

-                chrome.tabs.remove(tabId);

-                Imgur.parseAccessToken(changeInfo.url);

-              }

-            });

-        });

-    },

-

-    parseAccessToken: function(url) {

-      var oauth_verifier = OAuth.getParameter(url, 'oauth_verifier');

-      Imgur.getAccessToken(Imgur.accessTokenCallback, oauth_verifier);

-      Imgur.accessTokenCallback = null;

-    },

-

-    getAccessToken: function(callback, oauth_verifier) {

-      if (!oauth_verifier) {

-        Imgur.getRequestToken(callback);

-        return;

-      }

-      var message = {

-        action: IMGUR_ACCESS_TOKEN_URL,

-        method: 'POST',

-        parameters: {

-          'oauth_consumer_key': IMGUR_APP_KEY,

-          'oauth_token': Imgur.currentUserOauthToken,

-          'oauth_token_secret': Imgur.currentUserOauthTokenSecret,

-          'oauth_signature_method': OAUTH_SIGNATURE_METHOD,

-          'oauth_verifier': oauth_verifier,

-          'oauth_version': OAUTH_VERSION

-        }

-      };

-      var accessor = {

-        consumerKey: IMGUR_APP_KEY,

-        consumerSecret: IMGUR_APP_SECRET,

-        tokenSecret: Imgur.currentUserOauthTokenSecret

-      };

-      var header = Imgur.getAuthorizationHeader(message, accessor);

-

-      ajax({

-        url: IMGUR_ACCESS_TOKEN_URL,

-        method: 'POST',

-        headers: {

-          'Authorization': header

-        },

-        success: function(response) {

-          responseMap = OAuth.getParameterMap(response);

-          var accessToken = responseMap.oauth_token;

-          var accessTokenSecret = responseMap.oauth_token_secret;

-          var user = new User({

-            id: null,

-            accessToken: accessToken,

-            accessTokenSecret: accessTokenSecret

-          });

-

-          callback('success', user);

-        },

-        status: {

-          others: function(data) {

-            callback('failure', 'imgur_failed_to_get_access_token');

-          }

-        }

-      });

-    },

-

-    getUserInfo: function(user, callback) {

-      var url = IMGUR_USER_INFO_URL;

-      var message = {

-        action: url,

-        method: 'GET',

-        parameters: {

-          'oauth_consumer_key': IMGUR_APP_KEY,

-          'oauth_token': user.accessToken,

-          'oauth_signature_method': OAUTH_SIGNATURE_METHOD,

-          'oauth_version': OAUTH_VERSION

-        }

-      };

-

-      var accessor = {

-        consumerSecret: IMGUR_APP_SECRET,

-        tokenSecret: user.accessTokenSecret

-      };

-

-      var header = Imgur.getAuthorizationHeader(message, accessor);

-      ajax({

-        url: url,

-        method: 'GET',

-        headers: {

-          'Authorization': header

-        },

-        success: function(data) {

-          if (callback) {

-            user.id = data.account.url;

-            user.name = data.account.url;

-            callback('success', user);

-          }

-        },

-        status: {

-          others: function(data) {

-            callback('failure', 'failed_to_get_user_info');

-          }

-        }

-      });

-    },

-

-    upload: function(user, caption, imageData, callback) {

-      caption = encodeURIComponent(caption);

-      var message = {

-        action: IMGUR_PHOTO_UPLOAD_URL,

-        method: 'POST',

-        parameters: {

-          'oauth_consumer_key': IMGUR_APP_KEY,

-          'oauth_token': user.accessToken,

-          'oauth_signature_method': OAUTH_SIGNATURE_METHOD,

-          'oauth_version': OAUTH_VERSION

-        }

-      };

-      var accessor = {

-        consumerSecret: IMGUR_APP_SECRET,

-        tokenSecret: user.accessTokenSecret

-      };

-      var header = Imgur.getAuthorizationHeader(message, accessor);

-

-      var binaryData = {

-        boundary: MULTIPART_FORMDATA_BOUNDARY,

-        name: 'image',

-        value: 'screencapture.png',

-        data: imageData,

-        type: 'image/png'

-      };

-

-      ajax({

-        url: IMGUR_PHOTO_UPLOAD_URL,

-        method: 'POST',

-        multipartData: binaryData,

-        headers: {

-          'Authorization': header

-        },

-        success: function(response) {

-          callback('success', response.images.links.original);

-        },

-        status: {

-          others: function(err, statusCode) {

-            if (statusCode == 401) {

-              callback('failure', 'bad_access_token');

-            } else {

-              callback('failure', 'failed_to_upload_image');

-            };

-          }

-        }

-      });

-    },

-

-    getPhotoLink: function(user, photoLink, callback) {

-      callback('success', photoLink);

-    },

-

-    logout: function(callback) {

-      ajax({

-        url: IMGUR_LOGOUT_URL,

-        success: function() {

-          callback();

-        }

-      });

-    }

-  };

-})();
\ No newline at end of file
diff --git a/src/js/oauth.js b/src/js/oauth.js
deleted file mode 100644
index 85b2785..0000000
--- a/src/js/oauth.js
+++ /dev/null
@@ -1,551 +0,0 @@
-/*

- * Copyright 2008 Netflix, Inc.

- *

- * Licensed under the Apache License, Version 2.0 (the "License");

- * you may not use this file except in compliance with the License.

- * You may obtain a copy of the License at

- *

- *     http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS,

- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

- * See the License for the specific language governing permissions and

- * limitations under the License.

- */

-

-/* Here's some JavaScript software for implementing OAuth.

-

-   This isn't as useful as you might hope.  OAuth is based around

-   allowing tools and websites to talk to each other.  However,

-   JavaScript running in web browsers is hampered by security

-   restrictions that prevent code running on one website from

-   accessing data stored or served on another.

-

-   Before you start hacking, make sure you understand the limitations

-   posed by cross-domain XMLHttpRequest.

-

-   On the bright side, some platforms use JavaScript as their

-   language, but enable the programmer to access other web sites.

-   Examples include Google Gadgets, and Microsoft Vista Sidebar.

-   For those platforms, this library should come in handy.

-*/

-

-// The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by

-// http://pajhome.org.uk/crypt/md5/sha1.js

-

-/* An OAuth message is represented as an object like this:

-   {method: "GET", action: "http://server.com/path", parameters: ...}

-

-   The parameters may be either a map {name: value, name2: value2}

-   or an Array of name-value pairs [[name, value], [name2, value2]].

-   The latter representation is more powerful: it supports parameters

-   in a specific sequence, or several parameters with the same name;

-   for example [["a", 1], ["b", 2], ["a", 3]].

-

-   Parameter names and values are NOT percent-encoded in an object.

-   They must be encoded before transmission and decoded after reception.

-   For example, this message object:

-   {method: "GET", action: "http://server/path", parameters: {p: "x y"}}

-   ... can be transmitted as an HTTP request that begins:

-   GET /path?p=x%20y HTTP/1.0

-   (This isn't a valid OAuth request, since it lacks a signature etc.)

-   Note that the object "x y" is transmitted as x%20y.  To encode

-   parameters, you can call OAuth.addToURL, OAuth.formEncode or

-   OAuth.getAuthorization.

-

-   This message object model harmonizes with the browser object model for

-   input elements of an form, whose value property isn't percent encoded.

-   The browser encodes each value before transmitting it. For example,

-   see consumer.setInputs in example/consumer.js.

- */

-

-/* This script needs to know what time it is. By default, it uses the local

-   clock (new Date), which is apt to be inaccurate in browsers. To do

-   better, you can load this script from a URL whose query string contains

-   an oauth_timestamp parameter, whose value is a current Unix timestamp.

-   For example, when generating the enclosing document using PHP:

-

-   <script src="oauth.js?oauth_timestamp=<?=time()?>" ...

-

-   Another option is to call OAuth.correctTimestamp with a Unix timestamp.

- */

-

-var OAuth; if (OAuth == null) OAuth = {};

-

-OAuth.setProperties = function setProperties(into, from) {

-    if (into != null && from != null) {

-        for (var key in from) {

-            into[key] = from[key];

-        }

-    }

-    return into;

-}

-

-OAuth.setProperties(OAuth, // utility functions

-{

-    percentEncode: function percentEncode(s) {

-        if (s == null) {

-            return "";

-        }

-        if (s instanceof Array) {

-            var e = "";

-            for (var i = 0; i < s.length; ++s) {

-                if (e != "") e += '&';

-                e += OAuth.percentEncode(s[i]);

-            }

-            return e;

-        }

-        s = encodeURIComponent(s);

-        // Now replace the values which encodeURIComponent doesn't do

-        // encodeURIComponent ignores: - _ . ! ~ * ' ( )

-        // OAuth dictates the only ones you can ignore are: - _ . ~

-        // Source: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent

-        s = s.replace(/\!/g, "%21");

-        s = s.replace(/\*/g, "%2A");

-        s = s.replace(/\'/g, "%27");

-        s = s.replace(/\(/g, "%28");

-        s = s.replace(/\)/g, "%29");

-        return s;

-    }

-,

-    decodePercent: function decodePercent(s) {

-        if (s != null) {

-            // Handle application/x-www-form-urlencoded, which is defined by

-            // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1

-            s = s.replace(/\+/g, " ");

-        }

-        return decodeURIComponent(s);

-    }

-,

-    /** Convert the given parameters to an Array of name-value pairs. */

-    getParameterList: function getParameterList(parameters) {

-        if (parameters == null) {

-            return [];

-        }

-        if (typeof parameters != "object") {

-            return OAuth.decodeForm(parameters + "");

-        }

-        if (parameters instanceof Array) {

-            return parameters;

-        }

-        var list = [];

-        for (var p in parameters) {

-            list.push([p, parameters[p]]);

-        }

-        return list;

-    }

-,

-    /** Convert the given parameters to a map from name to value. */

-    getParameterMap: function getParameterMap(parameters) {

-        if (parameters == null) {

-            return {};

-        }

-        if (typeof parameters != "object") {

-            return OAuth.getParameterMap(OAuth.decodeForm(parameters + ""));

-        }

-        if (parameters instanceof Array) {

-            var map = {};

-            for (var p = 0; p < parameters.length; ++p) {

-                var key = parameters[p][0];

-                if (map[key] === undefined) { // first value wins

-                    map[key] = parameters[p][1];

-                }

-            }

-            return map;

-        }

-        return parameters;

-    }

-,

-    getParameter: function getParameter(parameters, name) {

-        if (parameters instanceof Array) {

-            for (var p = 0; p < parameters.length; ++p) {

-                if (parameters[p][0] == name) {

-                    return parameters[p][1]; // first value wins

-                }

-            }

-        } else {

-            return OAuth.getParameterMap(parameters)[name];

-        }

-        return null;

-    }

-,

-    formEncode: function formEncode(parameters) {

-        var form = "";

-        var list = OAuth.getParameterList(parameters);

-        for (var p = 0; p < list.length; ++p) {

-            var value = list[p][1];

-            if (value == null) value = "";

-            if (form != "") form += '&';

-            form += OAuth.percentEncode(list[p][0])

-              +'='+ OAuth.percentEncode(value);

-        }

-        return form;

-    }

-,

-    decodeForm: function decodeForm(form) {

-        var list = [];

-        var nvps = form.split('&');

-        for (var n = 0; n < nvps.length; ++n) {

-            var nvp = nvps[n];

-            if (nvp == "") {

-                continue;

-            }

-            var equals = nvp.indexOf('=');

-            var name;

-            var value;

-            if (equals < 0) {

-                name = OAuth.decodePercent(nvp);

-                value = null;

-            } else {

-                name = OAuth.decodePercent(nvp.substring(0, equals));

-                value = OAuth.decodePercent(nvp.substring(equals + 1));

-            }

-            list.push([name, value]);

-        }

-        return list;

-    }

-,

-    setParameter: function setParameter(message, name, value) {

-        var parameters = message.parameters;

-        if (parameters instanceof Array) {

-            for (var p = 0; p < parameters.length; ++p) {

-                if (parameters[p][0] == name) {

-                    if (value === undefined) {

-                        parameters.splice(p, 1);

-                    } else {

-                        parameters[p][1] = value;

-                        value = undefined;

-                    }

-                }

-            }

-            if (value !== undefined) {

-                parameters.push([name, value]);

-            }

-        } else {

-            parameters = OAuth.getParameterMap(parameters);

-            parameters[name] = value;

-            message.parameters = parameters;

-        }

-    }

-,

-    setParameters: function setParameters(message, parameters) {

-        var list = OAuth.getParameterList(parameters);

-        for (var i = 0; i < list.length; ++i) {

-            OAuth.setParameter(message, list[i][0], list[i][1]);

-        }

-    }

-,

-    /** Fill in parameters to help construct a request message.

-        This function doesn't fill in every parameter.

-        The accessor object should be like:

-        {consumerKey:'foo', consumerSecret:'bar', accessorSecret:'nurn', token:'krelm', tokenSecret:'blah'}

-        The accessorSecret property is optional.

-     */

-    completeRequest: function completeRequest(message, accessor) {

-        if (message.method == null) {

-            message.method = "GET";

-        }

-        var map = OAuth.getParameterMap(message.parameters);

-        if (map.oauth_consumer_key == null) {

-            OAuth.setParameter(message, "oauth_consumer_key", accessor.consumerKey || "");

-        }

-        if (map.oauth_token == null && accessor.token != null) {

-            OAuth.setParameter(message, "oauth_token", accessor.token);

-        }

-        if (map.oauth_version == null) {

-            OAuth.setParameter(message, "oauth_version", "1.0");

-        }

-        if (map.oauth_timestamp == null) {

-            OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());

-        }

-        if (map.oauth_nonce == null) {

-            OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));

-        }

-        OAuth.SignatureMethod.sign(message, accessor);

-    }

-,

-    setTimestampAndNonce: function setTimestampAndNonce(message) {

-        OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());

-        OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));

-    }

-,

-    addToURL: function addToURL(url, parameters) {

-        newURL = url;

-        if (parameters != null) {

-            var toAdd = OAuth.formEncode(parameters);

-            if (toAdd.length > 0) {

-                var q = url.indexOf('?');

-                if (q < 0) newURL += '?';

-                else       newURL += '&';

-                newURL += toAdd;

-            }

-        }

-        return newURL;

-    }

-,

-    /** Construct the value of the Authorization header for an HTTP request. */

-    getAuthorizationHeader: function getAuthorizationHeader(realm, parameters) {

-        var header = 'OAuth realm="' + OAuth.percentEncode(realm) + '"';

-        var list = OAuth.getParameterList(parameters);

-        for (var p = 0; p < list.length; ++p) {

-            var parameter = list[p];

-            var name = parameter[0];

-            if (name.indexOf("oauth_") == 0) {

-                header += ',' + OAuth.percentEncode(name) + '="' + OAuth.percentEncode(parameter[1]) + '"';

-            }

-        }

-        return header;

-    }

-,

-    /** Correct the time using a parameter from the URL from which the last script was loaded. */

-    correctTimestampFromSrc: function correctTimestampFromSrc(parameterName) {

-        parameterName = parameterName || "oauth_timestamp";

-        var scripts = document.getElementsByTagName('script');

-        if (scripts == null || !scripts.length) return;

-        var src = scripts[scripts.length-1].src;

-        if (!src) return;

-        var q = src.indexOf("?");

-        if (q < 0) return;

-        parameters = OAuth.getParameterMap(OAuth.decodeForm(src.substring(q+1)));

-        var t = parameters[parameterName];

-        if (t == null) return;

-        OAuth.correctTimestamp(t);

-    }

-,

-    /** Generate timestamps starting with the given value. */

-    correctTimestamp: function correctTimestamp(timestamp) {

-        OAuth.timeCorrectionMsec = (timestamp * 1000) - (new Date()).getTime();

-    }

-,

-    /** The difference between the correct time and my clock. */

-    timeCorrectionMsec: 0

-,

-    timestamp: function timestamp() {

-        var t = (new Date()).getTime() + OAuth.timeCorrectionMsec;

-        return Math.floor(t / 1000);

-    }

-,

-    nonce: function nonce(length) {

-        var chars = OAuth.nonce.CHARS;

-        var result = "";

-        for (var i = 0; i < length; ++i) {

-            var rnum = Math.floor(Math.random() * chars.length);

-            result += chars.substring(rnum, rnum+1);

-        }

-        return result;

-    }

-});

-

-OAuth.nonce.CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";

-

-/** Define a constructor function,

-    without causing trouble to anyone who was using it as a namespace.

-    That is, if parent[name] already existed and had properties,

-    copy those properties into the new constructor.

- */

-OAuth.declareClass = function declareClass(parent, name, newConstructor) {

-    var previous = parent[name];

-    parent[name] = newConstructor;

-    if (newConstructor != null && previous != null) {

-        for (var key in previous) {

-            if (key != "prototype") {

-                newConstructor[key] = previous[key];

-            }

-        }

-    }

-    return newConstructor;

-}

-

-/** An abstract algorithm for signing messages. */

-OAuth.declareClass(OAuth, "SignatureMethod", function OAuthSignatureMethod(){});

-

-OAuth.setProperties(OAuth.SignatureMethod.prototype, // instance members

-{

-    /** Add a signature to the message. */

-    sign: function sign(message) {

-        var baseString = OAuth.SignatureMethod.getBaseString(message);

-        var signature = this.getSignature(baseString);

-        OAuth.setParameter(message, "oauth_signature", signature);

-        return signature; // just in case someone's interested

-    }

-,

-    /** Set the key string for signing. */

-    initialize: function initialize(name, accessor) {

-        var consumerSecret;

-        if (accessor.accessorSecret != null

-            && name.length > 9

-            && name.substring(name.length-9) == "-Accessor")

-        {

-            consumerSecret = accessor.accessorSecret;

-        } else {

-            consumerSecret = accessor.consumerSecret;

-        }

-        this.key = OAuth.percentEncode(consumerSecret)

-             +"&"+ OAuth.percentEncode(accessor.tokenSecret);

-    }

-});

-

-/* SignatureMethod expects an accessor object to be like this:

-   {tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", accessorSecret: "xcmvzc..."}

-   The accessorSecret property is optional.

- */

-// Class members:

-OAuth.setProperties(OAuth.SignatureMethod, // class members

-{

-    sign: function sign(message, accessor) {

-        var name = OAuth.getParameterMap(message.parameters).oauth_signature_method;

-        if (name == null || name == "") {

-            name = "HMAC-SHA1";

-            OAuth.setParameter(message, "oauth_signature_method", name);

-        }

-        OAuth.SignatureMethod.newMethod(name, accessor).sign(message);

-    }

-,

-    /** Instantiate a SignatureMethod for the given method name. */

-    newMethod: function newMethod(name, accessor) {

-        var impl = OAuth.SignatureMethod.REGISTERED[name];

-        if (impl != null) {

-            var method = new impl();

-            method.initialize(name, accessor);

-            return method;

-        }

-        var err = new Error("signature_method_rejected");

-        var acceptable = "";

-        for (var r in OAuth.SignatureMethod.REGISTERED) {

-            if (acceptable != "") acceptable += '&';

-            acceptable += OAuth.percentEncode(r);

-        }

-        err.oauth_acceptable_signature_methods = acceptable;

-        throw err;

-    }

-,

-    /** A map from signature method name to constructor. */

-    REGISTERED : {}

-,

-    /** Subsequently, the given constructor will be used for the named methods.

-        The constructor will be called with no parameters.

-        The resulting object should usually implement getSignature(baseString).

-        You can easily define such a constructor by calling makeSubclass, below.

-     */

-    registerMethodClass: function registerMethodClass(names, classConstructor) {

-        for (var n = 0; n < names.length; ++n) {

-            OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor;

-        }

-    }

-,

-    /** Create a subclass of OAuth.SignatureMethod, with the given getSignature function. */

-    makeSubclass: function makeSubclass(getSignatureFunction) {

-        var superClass = OAuth.SignatureMethod;

-        var subClass = function() {

-            superClass.call(this);

-        };

-        subClass.prototype = new superClass();

-        // Delete instance variables from prototype:

-        // delete subclass.prototype... There aren't any.

-        subClass.prototype.getSignature = getSignatureFunction;

-        subClass.prototype.constructor = subClass;

-        return subClass;

-    }

-,

-    getBaseString: function getBaseString(message) {

-        var URL = message.action;

-        var q = URL.indexOf('?');

-        var parameters;

-        if (q < 0) {

-            parameters = message.parameters;

-        } else {

-            // Combine the URL query string with the other parameters:

-            parameters = OAuth.decodeForm(URL.substring(q + 1));

-            var toAdd = OAuth.getParameterList(message.parameters);

-            for (var a = 0; a < toAdd.length; ++a) {

-                parameters.push(toAdd[a]);

-            }

-        }

-        return OAuth.percentEncode(message.method.toUpperCase())

-         +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL))

-         +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters));

-    }

-,

-    normalizeUrl: function normalizeUrl(url) {

-        var uri = OAuth.SignatureMethod.parseUri(url);

-        var scheme = uri.protocol.toLowerCase();

-        var authority = uri.authority.toLowerCase();

-        var dropPort = (scheme == "http" && uri.port == 80)

-                    || (scheme == "https" && uri.port == 443);

-        if (dropPort) {

-            // find the last : in the authority

-            var index = authority.lastIndexOf(":");

-            if (index >= 0) {

-                authority = authority.substring(0, index);

-            }

-        }

-        var path = uri.path;

-        if (!path) {

-            path = "/"; // conforms to RFC 2616 section 3.2.2

-        }

-        // we know that there is no query and no fragment here.

-        return scheme + "://" + authority + path;

-    }

-,

-    parseUri: function parseUri (str) {

-        /* This function was adapted from parseUri 1.2.1

-           http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js

-         */

-        var o = {key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],

-                 parser: {strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ }};

-        var m = o.parser.strict.exec(str);

-        var uri = {};

-        var i = 14;

-        while (i--) uri[o.key[i]] = m[i] || "";

-        return uri;

-    }

-,

-    normalizeParameters: function normalizeParameters(parameters) {

-        if (parameters == null) {

-            return "";

-        }

-        var list = OAuth.getParameterList(parameters);

-        var sortable = [];

-        for (var p = 0; p < list.length; ++p) {

-            var nvp = list[p];

-            if (nvp[0] != "oauth_signature") {

-                sortable.push([ OAuth.percentEncode(nvp[0])

-                              + " " // because it comes before any character that can appear in a percentEncoded string.

-                              + OAuth.percentEncode(nvp[1])

-                              , nvp]);

-            }

-        }

-        sortable.sort(function(a,b) {

-                          if (a[0] < b[0]) return  -1;

-                          if (a[0] > b[0]) return 1;

-                          return 0;

-                      });

-        var sorted = [];

-        for (var s = 0; s < sortable.length; ++s) {

-            sorted.push(sortable[s][1]);

-        }

-        return OAuth.formEncode(sorted);

-    }

-});

-

-OAuth.SignatureMethod.registerMethodClass(["PLAINTEXT", "PLAINTEXT-Accessor"],

-    OAuth.SignatureMethod.makeSubclass(

-        function getSignature(baseString) {

-            return this.key;

-        }

-    ));

-

-OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"],

-    OAuth.SignatureMethod.makeSubclass(

-        function getSignature(baseString) {

-            b64pad = '=';

-            var signature = b64_hmac_sha1(this.key, baseString);

-            return signature;

-        }

-    ));

-

-try {

-    OAuth.correctTimestampFromSrc();

-} catch(e) {

-}

diff --git a/src/js/options.js b/src/js/options.js
index 9d61498..bbbce70 100644
--- a/src/js/options.js
+++ b/src/js/options.js
@@ -19,15 +19,12 @@
   i18nReplace('screenshootQualitySetting', 'quality_setting');

   i18nReplace('lossyScreenShot', 'lossy');

   i18nReplace('losslessScreenShot', 'lossless');

-  i18nReplace('shorcutSetting', 'shortcut_setting');

-  i18nReplace('settingShortcutText', 'shortcutsetting_text');

   if (isHighVersion()) {

     $('lossyScreenShot').innerText += ' (JPEG)';

     $('losslessScreenShot').innerText += ' (PNG)';

   }

   $('saveAndClose').addEventListener('click', saveAndClose);

   initScreenCaptureQuality();

-  HotKeySetting.setup();

 }

 

 function save() {

@@ -35,7 +32,7 @@
       $('lossy').checked ? 'jpeg' : '' ||

       $('lossless').checked ? 'png' : '';

 

-  return HotKeySetting.save();

+  return true;

 }

 

 function saveAndClose() {

@@ -59,107 +56,6 @@
   UI.addStyleSheet('./i18n_styles/en_options.css');

 }

 

-var HotKeySetting = (function() {

-  const CHAR_CODE_OF_AT = 64;

-  const CHAR_CODE_OF_A = 65;

-  const CHAR_CODE_OF_Z = 90;

-  var hotKeySelection = null;

-

-  var hotkey = {

-    setup: function() {

-      hotKeySelection = document.querySelectorAll('#hot-key-setting select');

-      // i18n.

-      $('area-capture-text').innerText =

-        chrome.i18n.getMessage('capture_area');

-      $('viewport-capture-text').innerText =

-        chrome.i18n.getMessage('capture_window');

-      $('full-page-capture-text').innerText =

-        chrome.i18n.getMessage('capture_webpage');

-      //$('screen-capture-text').innerText = chrome.i18n.getMessage('capture_screen');

-

-      for (var i = 0; i < hotKeySelection.length; i++) {

-        hotKeySelection[i].add(new Option('--', '@'));

-        for (var j = CHAR_CODE_OF_A; j <= CHAR_CODE_OF_Z; j++) {

-          var value = String.fromCharCode(j);

-          var option = new Option(value, value);

-          hotKeySelection[i].add(option);

-        }

-      }

-

-      $('area-capture-hot-key').selectedIndex =

-        HotKey.getCharCode('area') - CHAR_CODE_OF_AT;

-      $('viewport-capture-hot-key').selectedIndex =

-        HotKey.getCharCode('viewport') - CHAR_CODE_OF_AT;

-      $('full-page-capture-hot-key').selectedIndex =

-        HotKey.getCharCode('fullpage') - CHAR_CODE_OF_AT;

-      $('screen-capture-hot-key').selectedIndex =

-        HotKey.getCharCode('screen') - CHAR_CODE_OF_AT;

-

-      $('settingShortcut').addEventListener('click', function() {

-        hotkey.setState(this.checked);

-      }, false);

-

-      hotkey.setState(HotKey.isEnabled());

-    },

-

-    validate: function() {

-      var hotKeyLength =

-        Array.prototype.filter.call(hotKeySelection,

-            function (element) {

-              return element.value != '@'

-            }

-        ).length;

-      if (hotKeyLength != 0) {

-        var validateMap = {};

-        validateMap[hotKeySelection[0].value] = true;

-        validateMap[hotKeySelection[1].value] = true;

-        validateMap[hotKeySelection[2].value] = true;

-        if (hotKeyLength > 3 && hotKeySelection[3].value != '@') {

-          hotKeyLength -= 1;

-        }

-

-        if (Object.keys(validateMap).length < hotKeyLength) {

-          ErrorInfo.show('hot_key_conflict');

-          return false;

-        }

-      }

-      ErrorInfo.hide();

-      return true;

-    },

-

-    save: function() {

-      var result = true;

-      if ($('settingShortcut').checked) {

-        if (this.validate()) {

-          HotKey.enable();

-          HotKey.set('area', $('area-capture-hot-key').value);

-          HotKey.set('viewport', $('viewport-capture-hot-key').value);

-          HotKey.set('fullpage', $('full-page-capture-hot-key').value);

-        } else {

-          result = false;

-        }

-      } else {

-        HotKey.disable(bg);

-      }

-      return result;

-    },

-

-    setState: function(enabled) {

-      $('settingShortcut').checked = enabled;

-      UI.setStyle($('hot-key-setting'), 'color', enabled ? '' : '#6d6d6d');

-      for (var i = 0; i < hotKeySelection.length; i++) {

-        hotKeySelection[i].disabled = !enabled;

-      }

-      ErrorInfo.hide();

-    },

-

-    focusScreenCapture: function() {

-      $('screen-capture-hot-key').focus();

-    }

-  };

-  return hotkey;

-})();

-

 var ErrorInfo = (function() {

   return {

     show: function(msgKey) {

diff --git a/src/js/page.js b/src/js/page.js
index 2c5702d..9ca2463 100644
--- a/src/js/page.js
+++ b/src/js/page.js
@@ -241,15 +241,7 @@
   },

 

   getOriginalViewPortWidth: function() {

-    chrome.extension.sendMessage({ msg: 'original_view_port_width'},

-      function(originalViewPortWidth) {

-        if (originalViewPortWidth) {

-          page.originalViewPortWidth = page.hasScrollBar('y') ?

-            originalViewPortWidth - page.defaultScrollBarWidth : originalViewPortWidth;

-        } else {

-          page.originalViewPortWidth = document.documentElement.clientWidth;

-        }

-      });

+    page.originalViewPortWidth = document.documentElement.clientWidth;

   },

   

   calculateSizeAfterZooming: function(originalSize) {

@@ -895,13 +887,3 @@
   // Reget original width of view port if browser window resized or page zoomed.

   page.getOriginalViewPortWidth();

 }, false);

-

-// Send page url for retriving and parsing access token for facebook and picasa.

-var message = {

-  msg: 'url_for_access_token',

-  url: window.location.href

-}

-if (window.location.href.indexOf('https://api.weibo.com/oauth2/default.html') == 0) {

-  message.siteId = 'sina'

-}

-page.sendMessage(message);

diff --git a/src/js/picasa.js b/src/js/picasa.js
deleted file mode 100644
index e6343a8..0000000
--- a/src/js/picasa.js
+++ /dev/null
@@ -1,237 +0,0 @@
-(function() {

-  const ALBUM_NAME = 'Screen Capture';

-  const CLIENT_ID = '368358534491.apps.googleusercontent.com';

-  const AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';

-  const REDIRECT_URI = 'https://picasaweb.google.com';

-  const SCOPE = 'https://picasaweb.google.com/data/';

-  const RESPONSE_TYPE = 'token';

-  const ALBUM_URL = 'https://picasaweb.google.com/data/feed/api/user/' +

-    'default';

-  const CREATE_ALBUM_URL = 'https://picasaweb.google.com/data/feed/api/user/' +

-    'default';

-  const UPLOAD_BASE_URL = 'https://picasaweb.google.com/data/feed/api/user/' +

-    'default/albumid/';

-  const LOGOUT_URL = 'https://picasaweb.google.com/bye?continue=' +

-    'https://www.google.com/accounts/Logout?continue=' +

-    'https://picasaweb.google.com';

-

-  // var picasa = window.Picasa = new Site('picasa');

-  var picasa = window.Picasa = {

-    siteId: 'picasa',

-    currentUserId: null,

-    redirectUrl: REDIRECT_URI,

-    accessTokenCallback: null,

-    

-    getAccessToken: function(callback) {

-      picasa.accessTokenCallback = callback;

-      var url = AUTH_URL + '?client_id=' + CLIENT_ID + '&redirect_uri=' +

-        REDIRECT_URI + '&scope=' + SCOPE + '&response_type=' + RESPONSE_TYPE;

-      chrome.tabs.create({ url: url});

-    },

-

-    parseRedirectUrl: function(url) {

-      var result = false;

-      if (url.indexOf(REDIRECT_URI) == 0) {

-        var hash = url.split('#')[1];

-        if (hash) {

-          var params = hash.split('&');

-          var paramMap = {};

-          params.forEach(function(param) {

-            paramMap[param.split('=')[0]] = param.split('=')[1];

-          });

-

-          var accessToken = paramMap['access_token'];

-          var expires = paramMap['expires_in'];

-          if (accessToken && expires) {

-            result = {

-              accessToken: accessToken,

-              expires: expires

-            };

-          } else {

-            result = 'bad_redirect_url'; // Should never happened.

-          }

-        } else {

-          var search = url.split('?')[1];

-          if (search == 'error=access_denied')

-            result = 'access_denied';

-        }

-      }

-      return result;

-    },

-    

-    isRedirectUrl: function(url) {

-      return picasa.parseRedirectUrl(url) != false;

-    },

-    

-    parseAccessToken: function(redirectUrl) {

-      var parsedResult = picasa.parseRedirectUrl(redirectUrl);

-      if (parsedResult && typeof parsedResult == 'object') {

-        var user = new User({

-          accessToken: parsedResult.accessToken,

-          expires: new Date().getTime() + parsedResult.expires * 1000

-        });

-        picasa.accessTokenCallback('success', user);

-      } else {

-        picasa.accessTokenCallback('failure', 'user_denied');

-      }

-      picasa.accessTokenCallback = null;

-    },

-    

-    getUserInfo: function(user, callback) {

-      ajax({

-        url: ALBUM_URL,

-        parameters: {

-          fields: 'title,gphoto:nickname,entry/title,entry/gphoto:id',

-          alt: 'json',

-          access_token: user.accessToken

-        },

-        success: function(res) {

-          var userId = res.feed.title.$t;

-          var userName = res.feed.gphoto$nickname.$t;

-          user.id = userId;

-          user.name = userName;

-          

-          var albums = res.feed.entry;

-          if (albums) {

-            var length = albums.length;

-

-            // Check if user has created album "Screen Capture".

-            for (var i = 0; i < length; i++) {

-              var albumName = albums[i].title.$t;

-              if (albumName == ALBUM_NAME) {

-                user.albumId = albums[i].gphoto$id.$t;

-                break;

-              }

-            }

-          }

-

-          // Create album "Screen Capture" and retrieve album id.

-          if (!user.albumId) {

-            picasa.createAlbum(user.accessToken, function(result,

-                                                          albumIdOrMessage) {

-              if (result == 'success') {

-                user.albumId = albumIdOrMessage;

-                callback('success', user);

-              } else {

-                callback('failure', albumIdOrMessage);

-              }

-            });

-          } else {

-            callback('success', user);

-          }

-        },

-        status: {

-          404: function() {

-            callback('failure', 'failed_to_get_user_info');

-          }

-        }

-      });

-    },

-

-    createAlbum: function(accessToken, callback) {

-      var data = '<entry xmlns="http://www.w3.org/2005/Atom" ' +

-        'xmlns:media="http://search.yahoo.com/mrss/" ' +

-        'xmlns:gphoto="http://schemas.google.com/photos/2007">' +

-        '<title type="text">' + ALBUM_NAME +

-        '</title><category scheme="http://schemas.google.com/g/2005#kind" ' +

-        'term="http://schemas.google.com/photos/2007#album"></category>' +

-        '</entry>';

-

-      ajax({

-        method: 'POST',

-        url: CREATE_ALBUM_URL,

-        parameters: {

-          alt: 'json'

-        },

-        data: data,

-        headers: {

-          'GData-Version': 2,

-          'Content-Type': 'application/atom+xml',

-          'Authorization': 'OAuth ' + accessToken

-        },

-        complete: function(statusCode, album) {

-          if (statusCode == 201) {

-            var albumId = album.entry.gphoto$id.$t;

-            callback('success', albumId);

-          } else {

-            callback('failure', 'failure_to_create_album')

-          }

-        }

-      });

-    },

-

-    upload: function(user, caption, imageData, callback) {

-      caption = ajax.convertEntityString(caption);

-      caption = ajax.encodeForBinary(caption);

-

-      var imageFile = new Date().getTime() + '.png';

-      var headers = {

-        'GData-Version': 2,

-        'Content-Type': 'multipart/related; boundary=' +

-          MULTIPART_FORMDATA_BOUNDARY,

-        'Authorization': 'OAuth ' + user.accessToken

-      };

-

-      var captionData = '<entry xmlns="http://www.w3.org/2005/Atom">' +

-        '<title>' + imageFile + '</title>' +

-        '<summary>' + caption + '</summary>' +

-        '<category scheme="http://schemas.google.com/g/2005#kind" ' +

-        'term="http://schemas.google.com/photos/2007#photo"/></entry>';

-

-      var dataPart1 = {

-        contentType: 'application/atom+xml',

-        data: captionData

-      };

-      var dataPart2 = {

-        contentType: 'image/png',

-        data: imageData

-      };

-      var multipartData = {

-        boundary: MULTIPART_FORMDATA_BOUNDARY,

-        dataList: [dataPart1, dataPart2]

-      };

-

-      ajax({

-        url: UPLOAD_BASE_URL + user.albumId + '?alt=json',

-        headers: headers,

-        multipartData: multipartData,

-        complete: function(statusCode, res) {

-          if (statusCode == 201) {

-            var link = res.entry.link;

-            callback('success', link);

-          } else {

-            var message = 'failed_to_upload_image';

-            if (statusCode == 403) {

-              // bad access token

-              message = 'bad_access_token';

-            } else if (statusCode == 404 && res == 'No album found.') {

-              // Invalid album id.

-              message = 'invalid_album_id'

-            }

-            callback('failure', message);

-          }

-        }

-      });

-    },

-

-    getPhotoLink: function(user, photolinks, callback) {

-      for (var i = 0; i < photolinks.length; i++) {

-        var link = photolinks[i];

-        if (link.type == 'text/html' &&

-            link.rel == 'http://schemas.google.com/photos/2007#canonical') {

-          callback('success', link.href);

-          break;

-        }

-      }

-    },

-

-    logout: function(callback) {

-      ajax({

-        url: LOGOUT_URL,

-        success: function() {

-          callback();

-        }

-      });

-    }

-  };

-})();
\ No newline at end of file
diff --git a/src/js/popup.js b/src/js/popup.js
index 3f5690f..2319055 100644
--- a/src/js/popup.js
+++ b/src/js/popup.js
@@ -65,17 +65,12 @@
   $('option').addEventListener('click', function () {
     chrome.tabs.create({ url: 'options.html'});
   }, false);
-  if (HotKey.isEnabled()) {
-    $('captureWindowShortcut').style.display = 'inline';
-    $('captureAreaShortcut').style.display = 'inline';
-    $('captureWebpageShortcut').style.display = 'inline';
-    document.body.style.minWidth = "190px"
-  } else {
-    $('captureWindowShortcut').style.display = 'none';
-    $('captureAreaShortcut').style.display = 'none';
-    $('captureWebpageShortcut').style.display = 'none';
-    document.body.style.minWidth = "140px";
-  }
+
+  $('captureWindowShortcut').style.display = 'none';
+  $('captureAreaShortcut').style.display = 'none';
+  $('captureWebpageShortcut').style.display = 'none';
+  document.body.style.minWidth = "140px";
+
   var isScriptLoad = false;
   chrome.tabs.getSelected(null, function(tab) {
     if (tab.url.indexOf('chrome') == 0 || tab.url.indexOf('about') == 0) {
@@ -140,17 +135,6 @@
   setTimeout(insertScript, 500);
 
   // Update hot key.
-  if (HotKey.get('area') != '@')
-    $('captureAreaShortcut').innerText = 'Ctrl+Alt+' + HotKey.get('area');
-  if (HotKey.get('viewport') != '@') {
-    $('captureWindowShortcut').innerText = 'Ctrl+Alt+' +
-        HotKey.get('viewport');
-  }
-  if (HotKey.get('fullpage') != '@') {
-    $('captureWebpageShortcut').innerText ='Ctrl+Alt+' +
-        HotKey.get('fullpage');
-  }
-
   $('captureSpecialPageItem').addEventListener('click', function(e) {
     toDo('capture_special_page');
   });
diff --git a/src/js/sha1.js b/src/js/sha1.js
deleted file mode 100644
index 1b55982..0000000
--- a/src/js/sha1.js
+++ /dev/null
@@ -1,202 +0,0 @@
-/*

- * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined

- * in FIPS PUB 180-1

- * Version 2.1a Copyright Paul Johnston 2000 - 2002.

- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet

- * Distributed under the BSD License

- * See http://pajhome.org.uk/crypt/md5 for details.

- */

-

-/*

- * Configurable variables. You may need to tweak these to be compatible with

- * the server-side, but the defaults work in most cases.

- */

-var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */

-var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */

-var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

-

-/*

- * These are the functions you'll usually want to call

- * They take string arguments and return either hex or base-64 encoded strings

- */

-function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}

-function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}

-function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}

-function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}

-function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}

-function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}

-

-/*

- * Perform a simple self-test to see if the VM is working

- */

-function sha1_vm_test()

-{

-  return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";

-}

-

-/*

- * Calculate the SHA-1 of an array of big-endian words, and a bit length

- */

-function core_sha1(x, len)

-{

-  /* append padding */

-  x[len >> 5] |= 0x80 << (24 - len % 32);

-  x[((len + 64 >> 9) << 4) + 15] = len;

-

-  var w = Array(80);

-  var a =  1732584193;

-  var b = -271733879;

-  var c = -1732584194;

-  var d =  271733878;

-  var e = -1009589776;

-

-  for(var i = 0; i < x.length; i += 16)

-  {

-    var olda = a;

-    var oldb = b;

-    var oldc = c;

-    var oldd = d;

-    var olde = e;

-

-    for(var j = 0; j < 80; j++)

-    {

-      if(j < 16) w[j] = x[i + j];

-      else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);

-      var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),

-                       safe_add(safe_add(e, w[j]), sha1_kt(j)));

-      e = d;

-      d = c;

-      c = rol(b, 30);

-      b = a;

-      a = t;

-    }

-

-    a = safe_add(a, olda);

-    b = safe_add(b, oldb);

-    c = safe_add(c, oldc);

-    d = safe_add(d, oldd);

-    e = safe_add(e, olde);

-  }

-  return Array(a, b, c, d, e);

-

-}

-

-/*

- * Perform the appropriate triplet combination function for the current

- * iteration

- */

-function sha1_ft(t, b, c, d)

-{

-  if(t < 20) return (b & c) | ((~b) & d);

-  if(t < 40) return b ^ c ^ d;

-  if(t < 60) return (b & c) | (b & d) | (c & d);

-  return b ^ c ^ d;

-}

-

-/*

- * Determine the appropriate additive constant for the current iteration

- */

-function sha1_kt(t)

-{

-  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :

-         (t < 60) ? -1894007588 : -899497514;

-}

-

-/*

- * Calculate the HMAC-SHA1 of a key and some data

- */

-function core_hmac_sha1(key, data)

-{

-  var bkey = str2binb(key);

-  if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);

-

-  var ipad = Array(16), opad = Array(16);

-  for(var i = 0; i < 16; i++)

-  {

-    ipad[i] = bkey[i] ^ 0x36363636;

-    opad[i] = bkey[i] ^ 0x5C5C5C5C;

-  }

-

-  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);

-  return core_sha1(opad.concat(hash), 512 + 160);

-}

-

-/*

- * Add integers, wrapping at 2^32. This uses 16-bit operations internally

- * to work around bugs in some JS interpreters.

- */

-function safe_add(x, y)

-{

-  var lsw = (x & 0xFFFF) + (y & 0xFFFF);

-  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);

-  return (msw << 16) | (lsw & 0xFFFF);

-}

-

-/*

- * Bitwise rotate a 32-bit number to the left.

- */

-function rol(num, cnt)

-{

-  return (num << cnt) | (num >>> (32 - cnt));

-}

-

-/*

- * Convert an 8-bit or 16-bit string to an array of big-endian words

- * In 8-bit function, characters >255 have their hi-byte silently ignored.

- */

-function str2binb(str)

-{

-  var bin = Array();

-  var mask = (1 << chrsz) - 1;

-  for(var i = 0; i < str.length * chrsz; i += chrsz)

-    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);

-  return bin;

-}

-

-/*

- * Convert an array of big-endian words to a string

- */

-function binb2str(bin)

-{

-  var str = "";

-  var mask = (1 << chrsz) - 1;

-  for(var i = 0; i < bin.length * 32; i += chrsz)

-    str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);

-  return str;

-}

-

-/*

- * Convert an array of big-endian words to a hex string.

- */

-function binb2hex(binarray)

-{

-  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";

-  var str = "";

-  for(var i = 0; i < binarray.length * 4; i++)

-  {

-    str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +

-           hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);

-  }

-  return str;

-}

-

-/*

- * Convert an array of big-endian words to a base-64 string

- */

-function binb2b64(binarray)

-{

-  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

-  var str = "";

-  for(var i = 0; i < binarray.length * 4; i += 3)

-  {

-    var triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16)

-                | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )

-                |  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);

-    for(var j = 0; j < 4; j++)

-    {

-      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;

-      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);

-    }

-  }

-  return str;

-}

diff --git a/src/js/shortcut.js b/src/js/shortcut.js
deleted file mode 100644
index 7959178..0000000
--- a/src/js/shortcut.js
+++ /dev/null
@@ -1,35 +0,0 @@
-var shortcutKey = {

-

-  init: function() {

-    if (document.body.hasAttribute('screen_capture_injected')) {

-      return;

-    }

-    document.body.setAttribute('screen_capture_injected', true);

-    document.body.addEventListener('keydown', shortcutKey.handleShortcut,

-      false);

-  },

-

-  isThisPlatform: function(operationSystem) {

-    return navigator.userAgent.toLowerCase().indexOf(operationSystem) > -1;

-  },

-

-  handleShortcut: function (event) {

-    var isMac = shortcutKey.isThisPlatform('mac');

-    var keyCode = event.keyCode;

-    // Send compose key like Ctrl + Alt + alphabetical-key to background.

-    if ((event.ctrlKey && event.altKey && !isMac ||

-          event.metaKey && event.altKey && isMac) &&

-        keyCode > 64 && keyCode < 91) {

-      shortcutKey.sendMessage({

-        msg: 'capture_hot_key',

-        keyCode: keyCode

-      });

-    }

-  },

-

-  sendMessage: function(message) {

-    chrome.extension.sendMessage(message);

-  }

-};

-

-shortcutKey.init();

diff --git a/src/js/showimage.js b/src/js/showimage.js
index 294353d..b0d5f03 100644
--- a/src/js/showimage.js
+++ b/src/js/showimage.js
@@ -13,7 +13,6 @@
 function i18nReplace(id, messageKey) {
   return $(id).innerHTML = chrome.i18n.getMessage(messageKey);
 }
-UploadUI.init();
 
 var bg = chrome.extension.getBackgroundPage();
 var canvas = new Canvas();
@@ -503,6 +502,17 @@
     }
   },
 
+  save: function() {
+    photoshop.draw();
+    var formatParam  = localStorage.screenshootQuality || 'png';
+    var dataUrl;
+    var isJpeg = formatParam == 'jpeg';
+    $('canvas').toBlob(function(blob) {
+      saveAs(blob, chrome.extension.getBackgroundPage().screenshot.screenshotName+".png");
+    }, 'image/' + (isJpeg ? 'jpeg' : 'png'), (isJpeg ? 0.5 : null));
+    photoshop.finish();
+  },
+
   drawLineOnMaskCanvas: function(startX, startY, endX, endY, type, layerId) {
     var ctx = $('mask-canvas').getContext('2d');
     ctx.clearRect(0, 0, $('mask-canvas').width, $('mask-canvas').height);
@@ -809,16 +819,5 @@
     'selectstart', function f(e) { return false });
 $('mask-canvas').addEventListener(
     'selectstart', function f(e) { return false });
+$('btnSave').addEventListener('click', photoshop.save);
 $('btnClose').addEventListener('click', photoshop.closeCurrentTab);
-$('uploadAccountList').addEventListener('click', function(e) {
-  var target = e.target;
-  var classList = Array.prototype.slice.call(target.classList)
-  if (classList.indexOf('accountName') >= 0) {
-    var site = target.dataset.site;
-    var userId = target.dataset.userId;
-    UploadUI.upload(site, userId);
-  } else if (classList.indexOf('deleteBtn') >= 0) {
-    var accountId = target.dataset.accountId;
-    UploadUI.deleteAccountItem(accountId);
-  }
-});
diff --git a/src/js/sina_microblog.js b/src/js/sina_microblog.js
deleted file mode 100644
index 18b153b..0000000
--- a/src/js/sina_microblog.js
+++ /dev/null
@@ -1,122 +0,0 @@
-const APPKEY = '1350884563';

-const AUTHORIZE_URL = 'https://api.weibo.com/oauth2/authorize';

-const REDIRECT_URL = 'https://api.weibo.com/oauth2/default.html'

-const SINA_USER_INFO_URL = 'https://api.weibo.com/2/users/show.json';

-const SINA_PHOTO_UPLOAD_URL = 'https://upload.api.weibo.com/2/statuses/upload.json';

-const SINA_LOGOUT_URL = 'https://api.weibo.com/2/account/end_session.json';

-

-var SinaMicroblog = {

-  siteId: 'sina',

-  currentUserId: null,

-  accessTokenCallback: null,

-

-  isRedirectUrl: function() {},

-

-  getAccessToken: function(callback) {

-    SinaMicroblog.accessTokenCallback = callback;

-    var url = AUTHORIZE_URL + '?client_id=' + APPKEY +

-      '&redirect_uri=' + REDIRECT_URL + '&response_type=token';

-    chrome.tabs.create({url: url});

-  },

-  

-  parseAccessToken: function(url) {

-    var result = 'failure';

-    var msgOrUser = 'sina_failed_to_get_access_token';

-    var hash = url.split('#')[1];

-    if (hash && typeof hash == 'string') {

-      var keyValues = hash.split('&');

-      var response = {};

-

-      for (var keyValue, i = 0, l = keyValues.length; i < l; i++) {

-        keyValue = keyValues[i].split('=');

-        response[keyValue[0]] = keyValue[1];

-      }

-

-      if (!response.error && response.access_token && response.uid) {

-        result = 'success';

-        msgOrUser = new User({

-          id: response.uid,

-          accessToken: response.access_token

-        });

-      }

-    }

-

-    SinaMicroblog.accessTokenCallback(result, msgOrUser);

-    SinaMicroblog.accessTokenCallback = null;

-  },

-

-  getUserInfo: function(user, callback) {

-    ajax({

-      url: SINA_USER_INFO_URL,

-      parameters: {

-        access_token: user.accessToken,

-        uid: user.id

-      },

-      success: function(data) {

-        if (callback) {

-          user.name = data.screen_name;

-          callback('success', user);

-        }

-      },

-      status: {

-        others: function(data) {

-          callback('failure', 'failed_to_get_user_info');

-        }

-      }

-    });

-  },

-

-  upload: function(user, caption, imageData, callback) {

-    caption = encodeURIComponent(caption);

-    var params = {

-      access_token: user.accessToken,

-      status: caption

-    };

-    var binaryData = {

-      boundary: MULTIPART_FORMDATA_BOUNDARY,

-      name: 'pic',

-      value: 'test.png',

-      data: imageData,

-      type: 'image/png'

-    };

-    

-    ajax({

-      url: SINA_PHOTO_UPLOAD_URL,

-      parameters: params,

-      multipartData: binaryData,

-      success: function(microblog) {

-        callback('success', microblog.id);

-      },

-      status: {

-        others: function(res) {

-          var message = 'failed_to_upload_image';

-          var errorCode = res.error_code;

-          var invalidAccessTokenCodes = 

-            [21332, 21314, 21315, 21316, 21317, 21319, 21327];

-          if (invalidAccessTokenCodes.indexOf(errorCode) >= 0) {

-            message = 'bad_access_token';

-          }

-          callback('failure', message);

-        }

-      }

-    });

-  },

-

-  getPhotoLink: function(user, microblogId, callback) {

-    var photoLink = 'http://weibo.com/' + user.id + '/profile';

-    callback('success', photoLink);

-  },

-  

-  logout: function(callback) {

-    var params = {source: APPKEY};

-    ajax({

-      url: SINA_LOGOUT_URL,

-      parameters: params,

-      complete: function(statusCode, data) {

-        // Response status 403 means no user signed in

-        if ((statusCode == 200 || statusCode == 403) && callback)

-          callback(data);

-      }

-    });

-  }

-};
\ No newline at end of file
diff --git a/src/js/site.js b/src/js/site.js
deleted file mode 100644
index 6bb43f8..0000000
--- a/src/js/site.js
+++ /dev/null
@@ -1,63 +0,0 @@
-var Site = function(id) {

-  this.siteId = id;

-};

-

-Site.prototype = {

-  /**

-   * Get access token by user's authorization.

-   * @param {Function} callback call-back function, parameters:

-   *   {String} result, success or failure; {User|String} user with access

-   *   token, etc. or error message.

-   */

-  getAccessToken: function(callback) {},

-

-  /**

-   * Check if the url is redirect url for retrieving access token of current

-   * site.

-   * @param {String} url

-   * @return {Boolean} result

-   */

-  isRedirectUrl: function(url) {},

-

-  /**

-   * Parse and get access token from redirect url, then call call-back function

-   * of passed by calling getAccessToken method with access token.

-   * @param {String} url

-   */

-  parseAccessToken: function(url) {},

-

-  /**

-   * Get user information.

-   * @param {User} user

-   * @param {Function} callback call-back function, parameters:

-   *   {String} result, success or failure; {User|String} user with user id,

-   *   user name, etc. or error message.

-   */

-  getUserInfo: function(user, callback) {},

-

-  /**

-   * Upload image.

-   * @param {User} user user data with access token, etc.

-   * @param {String} caption image description

-   * @param {String} imageData binary image data

-   * @param callback  call-back function, parameters:

-   *   {String} result, success or failure; {String} photo id or error message.

-   */

-  upload: function(user, caption, imageData, callback) {},

-

-  /**

-   * Get photo link.

-   * @param {User} user user data with id, access token, etc.

-   * @param {String} photoId

-   * @param {Function} callback call-back function, parameters:

-   *   {String} result, success or failure; {String} photo link or error

-   *   message.

-   */

-  getPhotoLink: function(user, photoId, callback) {},

-

-  /**

-   * Log out current signed in user.

-   * @param callback

-   */

-  logout: function(callback) {}

-};
\ No newline at end of file
diff --git a/src/js/upload_ui.js b/src/js/upload_ui.js
deleted file mode 100644
index 5b073f5..0000000
--- a/src/js/upload_ui.js
+++ /dev/null
@@ -1,487 +0,0 @@
-const CURRENT_LOCALE = chrome.i18n.getMessage('@@ui_locale');

-const MULTIPART_FORMDATA_BOUNDARY = 'Google_Chrome_Screen_Capture';

-const HIDE_ERROR_INFO_DELAY_TIME = 5000;

-

-var UploadUI = {

-  currentSite: '',

-  uploading: false,

-  sites: {},

-

-  registerSite: function(id, siteObject) {

-    this.sites[id] = siteObject;

-  },

-

-  getSiteObject: function(id) {

-    return this.sites[id];

-  },

-

-  setUploading: function(state) {

-    UploadUI.uploading = state;

-  },

-

-  init: function() {

-    // Register supported site for image sharing.

-    UploadUI.registerSite(SinaMicroblog.siteId, SinaMicroblog);

-    UploadUI.registerSite(Facebook.siteId, Facebook);

-    UploadUI.registerSite(Picasa.siteId, Picasa);

-    UploadUI.registerSite(Imgur.siteId, Imgur);

-

-    // Import style sheet for current locale

-    if (CURRENT_LOCALE == 'zh_CN')

-      UI.addStyleSheet('./i18n_styles/zh_CN_upload_image.css');

-    else

-      UI.addStyleSheet('./i18n_styles/en_US_upload_image.css');

-

-    // Get i18n message

-    i18nReplace('shareToSinaMicroblogText', SinaMicroblog.siteId +

-      '_upload_header');

-    i18nReplace('shareToFacebookText', Facebook.siteId + '_upload_header');

-    i18nReplace('shareToPicasaText', Picasa.siteId + '_upload_header');

-    i18nReplace('lastStep', 'return_to_site_selection');

-    i18nReplace('closeUploadWrapper', 'close_upload_wrapper');

-    i18nReplace('imageCaptionText', 'image_caption');

-    i18nReplace('photoSizeTip', 'photo_size_tip');

-    i18nReplace('shareToImgurText', Imgur.siteId + '_upload_header');

-    $('requiredFlag').setAttribute('title',

-      chrome.i18n.getMessage('invalid_caption'));

-

-    // Add event listeners

-    //$('btnUpload').addEventListener('click', UploadUI.showUploadWrapper, false);

-    $('btnSave').addEventListener('click', UploadUI.saveImage, false);

-    $('closeUploadWrapper').addEventListener('click',

-      UploadUI.hideUploadWrapper, false);

-

-    $('picasaBtn').addEventListener('click', function() {

-      UploadUI.showUploadContentWrapper(Picasa.siteId);

-    });

-    $('facebookBtn').addEventListener('click', function() {

-      UploadUI.showUploadContentWrapper(Facebook.siteId);

-    }, false);

-    $('sinaMicroblogBtn').addEventListener('click', function() {

-      UploadUI.showUploadContentWrapper(SinaMicroblog.siteId);

-    }, false);

-    $('imgurBtn').addEventListener('click', function() {

-      UploadUI.showUploadContentWrapper(Imgur.siteId);

-    }, false);

-    $('shareToOtherAccount').addEventListener('click', function() {

-      var currentSite = UploadUI.currentSite;

-

-      // Validate image description first

-      if (UploadUI.validatePhotoDescription(currentSite)) {

-        var callback = function() {

-          var authenticationTip =

-            chrome.i18n.getMessage('user_authentication_tip');

-          UploadUI.showAuthenticationProgress(authenticationTip);

-          UploadUI.getAccessToken(currentSite);

-        };

-        var users = Account.getUsers(currentSite);

-        var numberOfUsers = Object.keys(users).length;

-

-        // Logout when user has authenticated app

-        if (numberOfUsers) {

-          var logoutTip = chrome.i18n.getMessage('user_logout_tip');

-          UploadUI.showAuthenticationProgress(logoutTip);

-          var site = UploadUI.getSiteObject(currentSite);

-          site.logout(callback);

-        } else {

-          callback();

-        }

-      }

-    }, false);

-    $('lastStep').addEventListener('click', UploadUI.showUploadSitesWrapper,

-      false);

-  },

-

-  showUploadWrapper: function() {

-    var uploadWrapper = $('uploadWrapper');

-    UI.show(uploadWrapper);

-

-    // Reset upload wrapper position

-    var viewportWidth = window.innerWidth;

-    var viewportHeight = window.innerHeight;

-    var wrapperWidth = uploadWrapper.offsetWidth;

-    var wrapperHeight = uploadWrapper.offsetHeight;

-

-    var left = (viewportWidth - wrapperWidth) / 2;

-    var top = (viewportHeight - wrapperHeight) / 3;

-    left = left < 0 ? 0 : left;

-    top = top < 0 ? 0 : top;

-

-    var scrollTop = document.body.scrollTop;

-    var scrollLeft = document.body.scrollLeft;

-

-    UI.setStyle(uploadWrapper, {

-      top: top + scrollTop + 'px',

-      left: left + scrollLeft + 'px'

-    });

-    UploadUI.showUploadSitesWrapper();

-    UploadUI.showOverlay();

-  },

-

-  hideUploadWrapper: function() {

-    UI.hide($('uploadWrapper'));

-    UploadUI.hideOverlay();

-  },

-

-  showOverlay: function() {

-    var overlay = $('overlay');

-    UI.setStyle(overlay, {

-      width: document.body.scrollWidth + 'px',

-      height: document.body.scrollHeight + 'px'

-    });

-    UI.show($('overlay'));

-  },

-

-  hideOverlay: function() {

-    UI.hide($('overlay'));

-  },

-

-  updateUploadHeader: function(title) {

-    $('uploadHeader').firstElementChild.firstElementChild.innerText = title;

-  },

-

-  showUploadSitesWrapper: function() {

-    var uploadHeader = chrome.i18n.getMessage('upload_sites_header');

-    UploadUI.updateUploadHeader(uploadHeader);

-    UI.show($('uploadSitesWrapper'));

-    UploadUI.hideUploadContentWrapper();

-    UI.hide($('lastStep'));

-  },

-

-  hideUploadSitesWrapper: function() {

-    UI.hide($('uploadSitesWrapper'));

-  },

-

-  showUploadContentWrapper: function(site) {

-    UploadUI.currentSite = site;

-

-    // Update upload wrapper UI

-    var uploadHeader = chrome.i18n.getMessage(site + '_upload_header');

-    UploadUI.updateUploadHeader(uploadHeader);

-    UploadUI.hideUploadSitesWrapper();

-    UploadUI.hideErrorInfo();

-    UploadUI.hideAuthenticationProgress();

-    UploadUI.clearPhotoDescription();

-    UI.show($('uploadContentWrapper'));

-    UI.show($('lastStep'));

-    UploadUI.updateShareToOtherAccountText(site);

-    UploadUI.togglePhotoDescriptionRequiredFlag(site);

-

-    // Show authenticated accounts of current site

-    UploadUI.clearAccounts();

-    var users = Account.getUsers(site);

-    for (var userId in users) {

-      UploadUI.addAuthenticatedAccount(site, userId);

-    }

-  },

-

-  hideUploadContentWrapper: function() {

-    UI.hide($('uploadContentWrapper'));

-  },

-

-  clearPhotoDescription: function() {

-    $('imageCaption').value = '';

-  },

-

-  validatePhotoDescription: function(site) {

-    var caption = $('imageCaption');

-    var invalidCaptionMsg = chrome.i18n.getMessage('invalid_caption');

-

-    // Validate photo description

-    if (site == SinaMicroblog.siteId && caption.value == '') {

-      UploadUI.showErrorInfo(invalidCaptionMsg);

-      caption.focus();

-      return false;

-    }

-    return true;

-  },

-

-  togglePhotoDescriptionRequiredFlag: function(siteId) {

-    if (siteId == SinaMicroblog.siteId)

-      UI.show($('requiredFlag'));

-    else

-      UI.hide($('requiredFlag'));

-  },

-

-  updateShareToOtherAccountText: function(siteId) {

-    var users = Account.getUsers(siteId);

-    var userLength = Object.keys(users).length;

-    if (userLength)

-      i18nReplace('shareToOtherAccount', 'share_to_other_account');

-    else

-      i18nReplace('shareToOtherAccount', 'share_to_' + siteId + '_account');

-  },

-

-  showErrorInfo: function(text) {

-    UI.show($('errorWrapper'));

-    $('errorInfo').innerHTML = text;

-    setTimeout(function() {

-      UploadUI.hideErrorInfo();

-    }, HIDE_ERROR_INFO_DELAY_TIME);

-  },

-

-  hideErrorInfo: function() {

-    UI.hide($('errorWrapper'));

-  },

-

-  showProgressBar: function(accountId) {

-    var progress = document.querySelector('#' + accountId +

-      ' .progressBar');

-    UI.show(progress);

-  },

-

-  hideProgressBar: function(accountId) {

-    var progress = document.querySelector('#' + accountId +

-      ' .progressBar');

-    UI.hide(progress);

-  },

-

-  showAuthenticationProgress: function(title) {

-    var progress = $('authenticationProgress');

-    progress.setAttribute('title', title);

-    UI.show(progress);

-  },

-

-  hideAuthenticationProgress: function() {

-    UI.hide($('authenticationProgress'));

-  },

-

-  setProgress: function(accountId, loaded, total) {

-    console.log('In setProgress, loaded: ' + loaded + ', total: ' + total);

-    var progress = document.querySelector('#' + accountId + ' .progressBar');

-

-    // One progress bar has 4 parts to represent progress

-    var level = parseInt(loaded / total / 0.25);

-    UI.setStyle(progress, 'background-position-y', '-' + (12 * level) + 'px');

-  },

-

-  showPhotoLink: function(accountId, link) {

-    var photoLink = document.querySelector('#' + accountId + ' .photoLink');

-    photoLink.setAttribute('href', link);

-    UI.setStyle(photoLink, 'display', 'inline');

-  },

-

-  hidePhotoLink: function(accountId) {

-    var photoLink = document.querySelector('#' + accountId + ' .photoLink');

-    UI.hide(photoLink);

-  },

-

-  showUploadInfo: function(accountId, text) {

-    var uploadInfo = document.querySelector('#' + accountId + ' .uploadInfo');

-    uploadInfo.innerHTML = text;

-    UI.show(uploadInfo);

-  },

-

-  hideUploadInfo: function(accountId) {

-    var uploadInfo = document.querySelector('#' + accountId + ' .uploadInfo');

-    UI.hide(uploadInfo);

-  },

-

-  clearAccounts: function() {

-    $('uploadAccountList').innerHTML = '';

-  },

-

-  addAuthenticatedAccount: function(site, userId) {

-    var template = $('accountItemTemplate').innerHTML;

-

-    // Replace i18n message

-    template = template.replace(/\$\{accountId\}/gi, site + '_' + userId);

-    var shareToText = chrome.i18n.getMessage('share_to');

-    template = template.replace(/\$\{accountName\}/gi,

-      shareToText + ' ' + Account.getUser(site, userId)['name']);

-    template = template.replace('${site}', site);

-    template = template.replace('${userId}', userId);

-    template = template.replace(/\$\{deletionTitle\}/gi,

-      chrome.i18n.getMessage('deletion_title'));

-    template = template.replace(/\$\{photoLinkText\}/gi,

-      chrome.i18n.getMessage('photo_link_text'));

-    template = template.replace(/\$\{progressInfo\}/gi,

-      chrome.i18n.getMessage('progress_info'));

-

-    // At most show 3 authenticated users

-    var uploadAccountList = $('uploadAccountList');

-    var accountsNumber = uploadAccountList.childElementCount;

-    if (accountsNumber == 2) {

-      uploadAccountList.removeChild(uploadAccountList.lastElementChild);

-    }

-    uploadAccountList.innerHTML = template + uploadAccountList.innerHTML;

-

-    $('accountName').addEventListener('click', function(e) {

-      UploadUI.upload(site, userId);

-    });

-    $('deleteBtn').addEventListener('click', function(e) {

-      e.stopPropagation();

-      UploadUI.deleteAccountItem(site + '_' + userId);

-    });

-

-    UploadUI.updateShareToOtherAccountText(site);

-  },

-

-  deleteAccountItem: function(accountId, noConfirm) {

-    if (UploadUI.uploading && !noConfirm)

-      return;

-    var confirmText = chrome.i18n.getMessage('account_deletion_confirm');

-    if (noConfirm || confirm(confirmText)) {

-      $('uploadAccountList').removeChild($(accountId));

-

-      // Clear localStorage

-      var site = accountId.split('_')[0];

-      var userId = accountId.split('_')[1];

-      Account.removeUser(site, userId);

-      UploadUI.updateShareToOtherAccountText(site);

-    }

-  },

-

-  upload: function(siteId, userId) {

-    if (UploadUI.uploading)

-      return;

-

-    // Initialize UI

-    var accountId = siteId + '_' + userId;

-    UploadUI.hideErrorInfo();

-    UploadUI.hideUploadInfo(accountId);

-    UploadUI.hidePhotoLink(accountId);

-    if (!UploadUI.validatePhotoDescription(siteId))

-      return;

-    var caption = $('imageCaption').value;

-

-    // Get ready for upload image.

-    photoshop.draw();

-    UploadUI.setUploading(true);

-    UploadUI.showProgressBar(accountId);

-

-    var site = UploadUI.getSiteObject(siteId);

-    var user = Account.getUser(siteId, userId);

-    var imageData = UploadUI.getImageData();

-    var infoText;

-

-    var callback = function(result, photoIdOrMessage) {

-      if (result == 'success') {

-        infoText = chrome.i18n.getMessage('get_photo_link');

-        UploadUI.showUploadInfo(accountId, infoText);

-        site.getPhotoLink(user, photoIdOrMessage, function(photoLinkResult,

-                                                           photoLinkOrMessage) {

-          if (photoLinkResult == 'success') {

-            UploadUI.setUploading(false);

-            UploadUI.hideUploadInfo(accountId);

-            UploadUI.showPhotoLink(accountId, photoLinkOrMessage);

-          } else {

-            UploadUI.showErrorInfo(photoLinkOrMessage);

-          }

-        });

-      } else {

-        if (photoIdOrMessage == 'bad_access_token' ||

-            photoIdOrMessage == 'invalid_album_id') {

-          Account.removeUser(site.siteId, site.currentUserId);

-          UploadUI.deleteAccountItem(accountId, true);

-          UploadUI.getAccessToken(siteId);

-        }

-        UploadUI.setUploading(false);

-        UploadUI.hideProgressBar(accountId);

-        UploadUI.showErrorInfo(chrome.i18n.getMessage(photoIdOrMessage));

-      }

-      UploadUI.hideProgressBar(accountId);

-    };

-

-    if (user) {

-      site.currentUserId = user.id;

-      site.upload(user, caption, imageData, callback);

-    } else {

-      UploadUI.getAccessToken(siteId);

-    }

-  },

-

-  getAccessToken: function(siteId) {

-    var site = UploadUI.getSiteObject(siteId);

-    var accessTokenCallback = function(result, userOrMessage) {

-      if (result == 'success') {

-        UploadUI.getUserInfo(siteId, userOrMessage);

-      } else {

-        // Show error information according to error reason

-        UploadUI.showErrorInfo(chrome.i18n.getMessage(userOrMessage));

-        UploadUI.hideAuthenticationProgress();

-      }

-    };

-

-    site.getAccessToken(accessTokenCallback);

-  },

-

-  getUserInfo: function(siteId, user) {

-    var site = UploadUI.getSiteObject(siteId);

-    site.getUserInfo(user, function(result, userOrMessage) {

-      if (result == 'success') {

-        var userId = user.id;

-        // Check if the authenticated user is added.

-        if (!Account.getUser(siteId, userId)) {

-          site.currentUserId = userId;

-          Account.addUser(siteId, user);

-          UploadUI.addAuthenticatedAccount(siteId, userId);

-        }

-        UploadUI.upload(siteId, userId);

-      } else {

-        var msg = chrome.i18n.getMessage(userOrMessage);

-        UploadUI.showErrorInfo(msg);

-      }

-      UploadUI.hideAuthenticationProgress();

-    });

-  },

-

-  getImageData: function() {

-    var dataUrl = $('canvas').toDataURL('image/png');

-    var imageDataIndex = dataUrl.indexOf('data:image/png;base64,');

-    if (imageDataIndex != 0) {

-      return;

-    }

-

-    // Decode to binary data

-    return atob(dataUrl.substr(imageDataIndex + 22));

-  },

-

-  saveImage: function() {

-    $('canvas').toBlob(function(blob) {

-      console.log(chrome.extension.getBackgroundPage());

-      saveAs(blob, chrome.extension.getBackgroundPage().screenshot.screenshotName+".png");

-    });

-  }

-};

-

-(function() {

-// Cache tab id of edit page, so that we can get tab focus after getting access

-// token.

-var tabIdOfEditPage;

-chrome.tabs.getSelected(null, function(tab) {

-  tabIdOfEditPage = tab.id;

-});

-

-function selectTab(tabId) {

-  chrome.tabs.update(tabId, {

-    selected: true

-  });

-}

-

-function closeTab(tabId) {

-  chrome.tabs.remove(tabId);

-}

-

-function parseAccessToken(senderId, url, siteId) {

-  var sites = UploadUI.sites;

-  for (var id in sites) {

-    var site = sites[id];

-    if ((siteId && id == siteId) || site.isRedirectUrl(url)) {

-      selectTab(tabIdOfEditPage);

-      closeTab(senderId);

-      site.parseAccessToken(url);

-      return true;

-    }

-  }

-  return false;

-}

-

-chrome.extension.onMessage.addListener(function(request, sender) {

-  switch (request.msg) {

-  case 'url_for_access_token':

-    parseAccessToken(sender.tab.id, request.url, request.siteId);

-    break;

-  }

-});

-})();