Changeset 38410 for lang/javascript

Show
Ignore:
Timestamp:
09/04/10 04:25:04 (3 years ago)
Author:
drry
Message:
  • 過剰なエスケープを修正しました。
  • ほか。
  • なんかぶっ壊してしまったのですんませんがお直しよろしくお願いいたします。
Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lang/javascript/vimperator-plugins/trunk/twittperator.js

    r38378 r38410  
    2626let PLUGIN_INFO = 
    2727<VimperatorPlugin> 
    28   <name>twittperator</name> 
     28  <name>Twittperator</name> 
    2929  <description>Twitter Client using ChirpStream</description> 
    3030  <description lang="ja">OAuth対応Twitterクライアント</description> 
    31   <version>1.4.2</version> 
     31  <version>1.4.2.3.4.5.6.7.8.9.10.11.12.13</version> 
    3232  <minVersion>2.3</minVersion> 
    3333  <maxVersion>2.4</maxVersion> 
     
    4141    - Use completion for comfort. 
    4242    :tw[ittperator] -getPIN 
    43         Opens the page to authorize twittperator and get your PIN from Twitter 
     43        Opens the page to authorize Twittperator and get your PIN from Twitter. 
    4444    :tw[ittperator] -setPIN {PINcode} 
    4545        Allows Twittperator to access Twitter by signifying your PIN. 
    4646 
    4747    :tw[ittperator] 
    48         Shows recent your timeline. ( The timeline will be cashed and expired 90 seconds after Twittperator get from Twitter. ) 
     48        Shows recent your timeline. (The timeline will be cashed and expired 90 seconds after Twittperator get from Twitter.) 
    4949    :tw[ittperator]! 
    5050        Gets recent your timeline from Twitter and shows it. 
     
    7373    ||< 
    7474    and you will get the page to authorize Twittperator to access Twitter in a new tab. 
    75     If you allow and you will get the PIN ( 7 digits numbers ), then yank it. 
     75    If you allow and you will get the PIN (7 digit numbers), then yank it. 
    7676 
    7777    Secondarily, authorize Twittperator with your PIN. 
     
    280280        } 
    281281        return into; 
    282     } 
     282    }; 
    283283 
    284284    OAuth.setProperties(OAuth, // utility functions 
     
    307307            s = s.replace(/\)/g, "%29"); 
    308308            return s; 
    309         } 
    310     , 
     309        }, 
    311310        decodePercent: function decodePercent(s) { 
    312311            if (s != null) { 
     
    316315            } 
    317316            return decodeURIComponent(s); 
    318         } 
    319     , 
     317        }, 
    320318        /** Convert the given parameters to an Array of name-value pairs. */ 
    321319        getParameterList: function getParameterList(parameters) { 
     
    334332            } 
    335333            return list; 
    336         } 
    337     , 
     334        }, 
    338335        /** Convert the given parameters to a map from name to value. */ 
    339336        getParameterMap: function getParameterMap(parameters) { 
     
    355352            } 
    356353            return parameters; 
    357         } 
    358     , 
     354        }, 
    359355        getParameter: function getParameter(parameters, name) { 
    360356            if (!parameters instanceof Array) { 
     
    367363            } 
    368364            return null; 
    369         } 
    370     , 
     365        }, 
    371366        formEncode: function formEncode(parameters) { 
    372367            var form = ""; 
     
    380375            } 
    381376            return form; 
    382         } 
    383     , 
     377        }, 
    384378        decodeForm: function decodeForm(form) { 
    385379            var list = []; 
     
    403397            } 
    404398            return list; 
    405         } 
    406     , 
     399        }, 
    407400        setParameter: function setParameter(message, name, value) { 
    408401            var parameters = message.parameters; 
     
    426419                message.parameters = parameters; 
    427420            } 
    428         } 
    429     , 
     421        }, 
    430422        setParameters: function setParameters(message, parameters) { 
    431423            var list = OAuth.getParameterList(parameters); 
     
    433425                OAuth.setParameter(message, list[i][0], list[i][1]); 
    434426            } 
    435         } 
    436     , 
     427        }, 
    437428        /** Fill in parameters to help construct a request message. 
    438429            This function doesn't fill in every parameter. 
    439430            The accessor object should be like: 
    440             {consumerKey:"foo", consumerSecret:"bar", accessorSecret:"nurn", token:"krelm", tokenSecret:"blah"} 
     431            { consumerKey: "foo", consumerSecret: "bar", accessorSecret: "nurn", 
     432              token: "krelm", tokenSecret: "blah" } 
    441433            The accessorSecret property is optional. 
    442434         */ 
     
    462454            } 
    463455            OAuth.SignatureMethod.sign(message, accessor); 
    464         } 
    465     , 
     456        }, 
    466457        setTimestampAndNonce: function setTimestampAndNonce(message) { 
    467458            OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp()); 
    468459            OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6)); 
    469         } 
    470     , 
     460        }, 
    471461        addToURL: function addToURL(url, parameters) { 
    472462            newURL = url; 
     
    481471            } 
    482472            return newURL; 
    483         } 
    484     , 
     473        }, 
    485474        /** Construct the value of the Authorization header for an HTTP request. */ 
    486475        getAuthorizationHeader: function getAuthorizationHeader(realm, parameters) { 
     
    495484            } 
    496485            return header; 
    497         } 
    498     , 
     486        }, 
    499487        /** Correct the time using a parameter from the URL from which the last script was loaded. */ 
    500488        correctTimestampFromSrc: function correctTimestampFromSrc(parameterName) { 
     
    510498            if (t == null) return; 
    511499            OAuth.correctTimestamp(t); 
    512         } 
    513     , 
     500        }, 
    514501        /** Generate timestamps starting with the given value. */ 
    515502        correctTimestamp: function correctTimestamp(timestamp) { 
    516503            OAuth.timeCorrectionMsec = (timestamp * 1000) - (new Date()).getTime(); 
    517         } 
    518     , 
     504        }, 
    519505        /** The difference between the correct time and my clock. */ 
    520         timeCorrectionMsec: 0 
    521     , 
     506        timeCorrectionMsec: 0, 
    522507        timestamp: function timestamp() { 
    523508            var t = (new Date()).getTime() + OAuth.timeCorrectionMsec; 
    524509            return Math.floor(t / 1000); 
    525         } 
    526     , 
     510        }, 
    527511        nonce: function nonce(length) { 
    528512            var chars = OAuth.nonce.CHARS; 
     
    567551            OAuth.setParameter(message, "oauth_signature", signature); 
    568552            return signature; // just in case someone's interested 
    569         } 
    570     , 
     553        }, 
    571554        /** Set the key string for signing. */ 
    572555        initialize: function initialize(name, accessor) { 
     
    586569 
    587570    /* SignatureMethod expects an accessor object to be like this: 
    588        {tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", accessorSecret: "xcmvzc..."} 
     571         { tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", 
     572           accessorSecret: "xcmvzc..." } 
    589573       The accessorSecret property is optional. 
    590574     */ 
     
    599583            } 
    600584            OAuth.SignatureMethod.newMethod(name, accessor).sign(message); 
    601         } 
    602     , 
     585        }, 
    603586        /** Instantiate a SignatureMethod for the given method name. */ 
    604587        newMethod: function newMethod(name, accessor) { 
     
    617600            err.oauth_acceptable_signature_methods = acceptable; 
    618601            throw err; 
    619         } 
    620     , 
     602        }, 
    621603        /** A map from signature method name to constructor. */ 
    622         REGISTERED : {} 
    623     , 
     604        REGISTERED: {}, 
    624605        /** Subsequently, the given constructor will be used for the named methods. 
    625606            The constructor will be called with no parameters. 
     
    631612                OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor; 
    632613            } 
    633         } 
    634     , 
     614        }, 
    635615        /** Create a subclass of OAuth.SignatureMethod, with the given getSignature function. */ 
    636616        makeSubclass: function makeSubclass(getSignatureFunction) { 
     
    645625            subClass.prototype.constructor = subClass; 
    646626            return subClass; 
    647         } 
    648     , 
     627        }, 
    649628        getBaseString: function getBaseString(message) { 
    650629            var URL = message.action; 
     
    664643             +"&"+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL)) 
    665644             +"&"+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters)); 
    666         } 
    667     , 
     645        }, 
    668646        normalizeUrl: function normalizeUrl(url) { 
    669647            var uri = OAuth.SignatureMethod.parseUri(url); 
     
    673651                        || (scheme == "https" && uri.port == 443); 
    674652            if (dropPort) { 
    675                 // find the last : in the authority 
     653                // find the last ":" in the authority 
    676654                var index = authority.lastIndexOf(":"); 
    677655                if (index >= 0) { 
     
    685663            // we know that there is no query and no fragment here. 
    686664            return scheme + "://" + authority + path; 
    687         } 
    688     , 
     665        }, 
    689666        parseUri: function parseUri(str) { 
    690667            /* This function was adapted from parseUri 1.2.1 
    691668               http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js 
    692669             */ 
    693             var o = {key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], 
    694                      parser: {strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ }}; 
     670            var o = { 
     671              key: ["source", "protocol", "authority", "userInfo", "user", 
     672                    "password", "host", "port", "relative", "path", "directory", 
     673                    "file", "query", "anchor"], 
     674              parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ } 
     675            }; 
    695676            var m = o.parser.strict.exec(str); 
    696677            var uri = {}; 
     
    698679            while (i--) uri[o.key[i]] = m[i] || ""; 
    699680            return uri; 
    700         } 
    701     , 
     681        }, 
    702682        normalizeParameters: function normalizeParameters(parameters) { 
    703683            if (parameters == null) { 
     
    711691                    sortable.push([ OAuth.percentEncode(nvp[0]) 
    712692                                  + " " // because it comes before any character that can appear in a percentEncoded string. 
    713                                   + OAuth.percentEncode(nvp[1]) 
    714                                   , nvp]); 
     693                                  + OAuth.percentEncode(nvp[1]), 
     694                                  nvp]); 
    715695                } 
    716696            } 
    717             sortable.sort(function(a,b) { 
     697            sortable.sort(function(a, b) { 
    718698                              if (a[0] < b[0]) return -1; 
    719699                              if (a[0] > b[0]) return 1; 
     
    729709 
    730710    OAuth.SignatureMethod.registerMethodClass(["PLAINTEXT", "PLAINTEXT-Accessor"], 
    731         OAuth.SignatureMethod.makeSubclass( 
    732             function getSignature(baseString) { 
    733                 return this.key; 
    734             } 
    735         )); 
     711        OAuth.SignatureMethod.makeSubclass(function getSignature(baseString) this.key)); 
    736712 
    737713    OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"], 
    738         OAuth.SignatureMethod.makeSubclass( 
    739             function getSignature(baseString) { 
    740                 b64pad = "="; 
    741                 var signature = b64_hmac_sha1(this.key, baseString); 
    742                 return signature; 
    743             } 
    744         )); 
     714        OAuth.SignatureMethod.makeSubclass(function getSignature(baseString) { 
     715            b64pad = "="; 
     716            var signature = b64_hmac_sha1(this.key, baseString); 
     717            return signature; 
     718        })); 
    745719 
    746720    // oauth.js 2}}} 
     
    961935      }, 
    962936      // temp for request 
    963       request : { 
    964         token :"",// response oauth_token 
     937      request: { 
     938        token :"", // response oauth_token 
    965939        tokenSecret: ""// response oauth_token_secret 
    966940      }, 
    967941      // トークンが取得済みかの真偽値を返す 
    968       isAuthorize : function() { 
     942      isAuthorize: function() { 
    969943        let accessor = this.getAccessor(); 
    970944        if (accessor.consumerKey && accessor.consumerSecret && 
     
    976950      getAccessor: function() { 
    977951        return { 
    978           consumerKey: this.accessor.get("consumerKey",""), 
    979           consumerSecret: this.accessor.get("consumerSecret",""), 
    980           token: this.accessor.get("token",""), 
    981           tokenSecret: this.accessor.get("tokenSecret","") 
     952          consumerKey: this.accessor.get("consumerKey", ""), 
     953          consumerSecret: this.accessor.get("consumerSecret", ""), 
     954          token: this.accessor.get("token", ""), 
     955          tokenSecret: this.accessor.get("tokenSecret", "") 
    982956        }; 
    983957      }, 
    984       deleteAccessor : function() { 
     958      deleteAccessor: function() { 
    985959        var clientInfo = { 
    986960          clientName: this.accessor.get("clientName", ""), 
    987           consumerKey: this.accessor.get("consumerKey",""), 
    988           consumerSecret: this.accessor.get("consumerSecret",""), 
     961          consumerKey: this.accessor.get("consumerKey", ""), 
     962          consumerSecret: this.accessor.get("consumerSecret", ""), 
    989963        }; 
    990964        this.accessor.clear(); 
     
    994968      }, 
    995969      // 認証ページのURLを取得 
    996       getRequestToken : function(callback) { 
     970      getRequestToken: function(callback) { 
    997971        let message = { 
    998972          method: "GET", 
     
    1000974          parameters: { 
    1001975            oauth_signature_method: "HMAC-SHA1", 
    1002             oauth_consumer_key: this.accessor.get("consumerKey","") 
     976            oauth_consumer_key: this.accessor.get("consumerKey", "") 
    1003977          } 
    1004978        }; 
     
    10351009        }); 
    10361010      }, 
    1037       // pinを元にAccess Tokenを取得して保存、callbackにはaccessorオブジェクトを渡す 
     1011      // PINを元にaccess tokenを取得して保存、callbackにはaccessorオブジェクトを渡す 
    10381012      getAccessToken: function(pin, callback) { 
    10391013        var message = { 
     
    10421016          parameters: { 
    10431017            oauth_signature_method: "HMAC-SHA1", 
    1044             oauth_consumer_key: this.accessor.get("consumerKey",""), 
     1018            oauth_consumer_key: this.accessor.get("consumerKey", ""), 
    10451019            oauth_token: this.request.token, // Request Token 
    10461020            oauth_verifier: pin 
     
    10561030          onload: function(d) { 
    10571031            if (d.status == 200) { 
    1058               /* 返り値からAccess Token/Access Token Secretを取り出す */ 
     1032              /* 返り値からaccess token/access token secretを取り出す */ 
    10591033              var res = d.responseText; 
    10601034              var parameter = self.getParameter(res); 
     
    10761050      // api+?+query にアクセスした結果をcallbackに渡す 
    10771051      get: function(api, query, callback) { 
    1078         var btquery = (query)? "?"+this.buildQuery(query) : ""; 
     1052        var btquery =  query ? "?" + this.buildQuery(query) : ""; 
    10791053        var message = { 
    10801054          method: "GET", 
    1081           action: api + btquery, 
     1055          action: setting.apiURLBase + api + btquery, 
    10821056          parameters: { 
    10831057            oauth_signature_method: "HMAC-SHA1", 
    1084             oauth_consumer_key: this.accessor.get("consumerKey",""),// queryの構築 
    1085             oauth_token: this.accessor.get("token","") // Access Token 
     1058            oauth_consumer_key: this.accessor.get("consumerKey", ""), // Queryの構築 
     1059            oauth_token: this.accessor.get("token", "") // Access token 
    10861060          } 
    10871061        }; 
     
    11071081        var message = { 
    11081082          method: "POST", 
    1109           action: api, 
     1083          action: setting.apiURLBase + api, 
    11101084          parameters: { 
    11111085            oauth_signature_method: "HMAC-SHA1", 
    1112             oauth_consumer_key: this.accessor.get("consumerKey",""), 
    1113             oauth_token: this.accessor.get("token","") // Access Token 
     1086            oauth_consumer_key: this.accessor.get("consumerKey", ""), 
     1087            oauth_token: this.accessor.get("token", "") // Access token 
    11141088          } 
    11151089        }; 
    11161090        // 送信するデータをパラメータに追加する 
    1117         for ( var key in content ) { 
     1091        for (var key in content) { 
    11181092          message.parameters[key] = content[key]; 
    11191093        } 
     
    11371111        Utils.xmlhttpRequest(options); // 送信 
    11381112      }, 
     1113      put: function(api, content, callback) { 
     1114        var message = { 
     1115          method: "PUT", 
     1116          action: setting.apiURLBase + api, 
     1117          parameters: { 
     1118            oauth_signature_method: "HMAC-SHA1", 
     1119            oauth_consumer_key: this.accessor.get("consumerKey", ""), 
     1120            oauth_token: this.accessor.get("token", "") // Access token 
     1121          } 
     1122        }; 
     1123        // 送信するデータをパラメータに追加する 
     1124        for (var key in content) { 
     1125          message.parameters[key] = content[key]; 
     1126        } 
     1127        OAuth.setTimestampAndNonce(message); 
     1128        OAuth.SignatureMethod.sign(message, this.getAccessor()); 
     1129        var target = OAuth.addToURL(message.action, message.parameters); 
     1130        var options = { 
     1131          method: message.method, 
     1132          url: target, 
     1133          onload: function(d) { 
     1134            if (d.status == 200) { 
     1135              if (callback) { 
     1136                  callback(d.responseText); 
     1137              } 
     1138            } else { 
     1139              callback(d); 
     1140            } 
     1141          } 
     1142        }; 
     1143        Utils.xmlhttpRequest(options); // 送信 
     1144      }, 
     1145      delete: function(api, content, callback) { 
     1146        var btquery =  query ? "?" + this.buildQuery(query) : ""; 
     1147        var message = { 
     1148          method: "DELETE", 
     1149          action: setting.apiURLBase + api + btquery, 
     1150          parameters: { 
     1151            oauth_signature_method: "HMAC-SHA1", 
     1152            oauth_consumer_key: this.accessor.get("consumerKey", ""), // Queryの構築 
     1153            oauth_token: this.accessor.get("token", "") // Access token 
     1154          } 
     1155        }; 
     1156        OAuth.setTimestampAndNonce(message); 
     1157        OAuth.SignatureMethod.sign(message, this.getAccessor()); 
     1158        var target = OAuth.addToURL(message.action, message.parameters); 
     1159        var options = { 
     1160          method: message.method, 
     1161          url: target, 
     1162          onload: function(d) { 
     1163            if (d.status == 200) { 
     1164              if (callback) { 
     1165                  callback(d.responseText); 
     1166              } 
     1167            }else{ 
     1168              callback(d.statusText); 
     1169            } 
     1170          }, 
     1171        }; 
     1172        Utils.xmlhttpRequest(options); // 送信 
     1173      }, 
    11391174      getAuthorizationHeader: function(api) { 
    11401175        var message = { 
     
    11431178          parameters: { 
    11441179            oauth_signature_method: "HMAC-SHA1", 
    1145             oauth_consumer_key: this.accessor.get("consumerKey",""),// queryの構築 
    1146             oauth_token: this.accessor.get("token",""), // Access Token 
     1180            oauth_consumer_key: this.accessor.get("consumerKey", ""), // Queryの構築 
     1181            oauth_token: this.accessor.get("token", ""), // Access token 
    11471182            oauth_version: "1.0" 
    11481183          } 
     
    11521187        return OAuth.getAuthorizationHeader("Twitter", message.parameters); 
    11531188      }, 
    1154       // utility関数 
     1189      // Utility関数 
    11551190      // http://kevin.vanzonneveld.net 
    1156       urlEncode : function(str) { 
     1191      urlEncode: function(str) { 
    11571192        str = (str+"").toString(); 
    11581193        return encodeURIComponent(str).replace(/!/g, "%21").replace(/"/g, "%27").replace(/\(/g, "%28") 
     
    11601195      }, 
    11611196      // オブジェクトからクエリを生成 
    1162       buildQuery : function(formdata, numeric_prefix, arg_separator) { 
    1163         // * example 1: http_build_query({foo: "bar", php: "hypertext processor", baz: "boom", cow: "milk"}, "", "&amp;"); 
    1164         // * returns 1: "foo=bar&amp;php=hypertext+processor&amp;baz=boom&amp;cow=milk" 
    1165         // * example 2: http_build_query({"php": "hypertext processor", 0: "foo", 1: "bar", 2: "baz", 3: "boom", "cow": "milk"}, "myvar_"); 
    1166         // * returns 2: "php=hypertext+processor&myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_3=boom&cow=milk" 
     1197      buildQuery: function(formdata, numeric_prefix, arg_separator) { 
     1198        // * example 1: http_build_query({ foo: "bar", php: "Hypertext Processor", baz: "boom", cow: "milk" }, "", "&amp;"); 
     1199        // * returns 1: "foo=bar&amp;php=Hypertext+Processor&amp;baz=boom&amp;cow=milk" 
     1200        // * example 2: http_build_query({ "PHP": "Hypertext Processor", 0: "foo", 1: "bar", 2: "baz", 3: "boom", "cow": "milk" }, "myvar_"); 
     1201        // * returns 2: "PHP=Hypertext+Processor&myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_3=boom&cow=milk" 
    11671202        var value, key, tmp = []; 
    11681203        var self = this; 
     
    12011236        return tmp.join(arg_separator); 
    12021237      }, 
    1203       // Query String から 連想配列を返す 
     1238      // Query string から 連想配列を返す 
    12041239      getParameter: function(str) { 
    1205         var dec = decodeURIComponent; 
    1206         var par = {}, itm; 
    1207         if (typeof str == "undefined") return par; 
    1208         if (str.indexOf("?", 0) > -1) str = str.split("?")[1]; 
    1209         str = str.split("&"); 
    1210         for (var i = 0; str.length > i; i++) { 
    1211           itm = str[i].split("="); 
    1212           if (itm[0] != "") { 
    1213             par[itm[0]] = typeof itm[1] == "undefined" ? true : dec(itm[1]); 
    1214           } 
    1215         } 
    1216         return par; 
    1217      } 
    1218    }; 
    1219    return p; 
     1240        if (typeof str == "undefined") return {}; 
     1241        var itm; 
     1242        if (str.indexOf("?", 0) > -1) str = str.split("?", 2)[1]; 
     1243        var regex = str.indexOf("&") > str.indexOf(";") ? /;+/ : /&+/; 
     1244        return str.split(regex).reduce(function(r, v) { 
     1245          var kv = v.split("=", 2); 
     1246          if (kv[0] != "") { 
     1247            r[kv[0]] = typeof kv[1] == "undefined" ? true : decodeURIComponent(kv[1]); 
     1248          } 
     1249          return r; 
     1250        }, {}); 
     1251      } 
     1252    }; 
     1253    return p; 
    12201254  })(); 
    12211255  // }}} 
    12221256 
    12231257  // Twittperator 
    1224   function Stream({host, path}) { // {{{ 
     1258  function Stream({ host, path }) { // {{{ 
    12251259    function extractURL(s) 
    12261260      let (m = s.match(/https?:\/\/\S+/)) 
     
    12351269 
    12361270      if (restartCount > 13) 
    1237         return liberator.echoerr('Twittperator: Gave up to connect to ChirpUserStream...'); 
    1238  
    1239       liberator.echoerr('Twittperator: ChirpUserStream will be restared...'); 
     1271        return liberator.echoerr("Twittperator: Gave up to connect to ChirpUserStream..."); 
     1272 
     1273      liberator.echoerr("Twittperator: ChirpUserStream will be restared..."); 
    12401274 
    12411275      // 試行済み回数^2 秒後にリトライ 
     
    12901324          null, 0, 
    12911325          useProxy ? setting.proxyHost : host, 
    1292           useProxy ? parseInt(setting.proxyPort || '3128', 10) : 80, 
     1326          useProxy ? parseInt(setting.proxyPort || "3128", 10) : 80, 
    12931327          null); 
    12941328      let os = transport.openOutputStream(0, 0, 0); 
     
    13201354            for (let [, line] in Iterator(lines.slice(0, -1))) { 
    13211355              try { 
    1322                 if (/^\s*\{/(line)) 
     1356                if (/^[ \n\r\t]*\{/(line)) 
    13231357                  onMsg(Utils.fixStatusObject(JSON.parse(line)), line); 
    13241358              } catch (e) { liberator.log(e); } 
     
    13281362            buf += data; 
    13291363          } 
    1330         } catch (e if /^(?:NS_ERROR_NET_RESET|NS_BASE_STREAM_CLOSED)$/(e)) { 
    1331           liberator.echoerr('Twittperator: ChirpStream was stopped by ' + e.name + '.'); 
     1364        } catch (e if /^NS_(?:ERROR_NET_RESET|BASE_STREAM_CLOSED)$/(e)) { 
     1365          liberator.echoerr("Twittperator: ChirpStream was stopped by " + e.name + "."); 
    13321366          restart(); 
    13331367        } catch (e) { 
    1334           liberator.echoerr('Twittperator: Unknown error on ChirpStream connection: ' + e.name); 
     1368          liberator.echoerr("Twittperator: Unknown error on ChirpStream connection: " + e.name); 
    13351369          restart(); 
    13361370        } 
     
    13681402    }; 
    13691403  }; // }}} 
    1370   let ChirpUserStream = Stream({host: "chirpstream.twitter.com", path: "/2b/user.json"}); 
     1404  let ChirpUserStream = Stream({ host: "chirpstream.twitter.com", path: "/2b/user.json" }); 
    13711405  let Twitter = { // {{{ 
    13721406    destroy: function(id) { // {{{ 
    1373       tw.post("http://api.twitter.com/1/statuses/destroy/" + id + ".json", null, function(text) { 
     1407      tw.delete("statuses/destroy/" + id + ".json", null, function(text) { 
    13741408        let res = Utils.fixStatusObject(JSON.parse(text)); 
    13751409        Twittperator.echo("delete: " + res.user.name + " " + res.text) 
     
    13771411    }, // }}} 
    13781412    favorite: function(id) { // {{{ 
    1379       tw.post("http://api.twitter.com/1/favorites/create/" + id + ".json", null, function(text) { 
     1413      tw.post("favorites/create/" + id + ".json", null, function(text) { 
    13801414        let res = Utils.fixStatusObject(JSON.parse(text)); 
    13811415        Twittperator.echo("fav: " + res.user.name + " " + res.text) 
     
    13931427        onload(history); 
    13941428      } else { 
    1395         let api = "http://api.twitter.com/1/statuses/home_timeline.json", query = {}; 
     1429        let api = "statuses/home_timeline.json", query = {}; 
    13961430 
    13971431        if (target) { 
    1398           api = "http://api.twitter.com/1/statuses/user_timeline.json"; 
     1432          api = "statuses/user_timeline.json"; 
    13991433          query.screen_name = target; 
    14001434        } else { 
     
    14301464      let sendData = {}; 
    14311465      let prefix, replyUser, replyID, postfix; 
    1432       if (stat.match(/^(.*)@([^\s#]+)(?:#(\d+))(.*)$/)) { 
     1466      if (stat.match(/^(.*)@(\w{1,15})#(\d+)(.*)$/)) { 
    14331467        [prefix, replyUser, replyID, postfix] = [RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$4]; 
    14341468        if (stat.indexOf("RT @" + replyUser + "#" + replyID) == 0) { 
    14351469          Twittperator.withProtectedUserConfirmation( 
    1436             {screenName: replyUser, statusId: replyID}, 
    1437             'retweet', 
    1438             function() Twitter.reTweet(replyID) 
     1470            { screenName: replyUser, statusId: replyID }, 
     1471            "retweet", 
     1472            function() Twitter.retweet(replyID) 
    14391473          ); 
    14401474          return; 
     
    14451479      } 
    14461480      Twittperator.withProtectedUserConfirmation( 
    1447         {screenName: replyUser, statusId: replyID}, 
    1448         'reply', 
     1481        { screenName: replyUser, statusId: replyID }, 
     1482        "reply", 
    14491483        function() { 
    14501484          sendData.status = stat; 
    14511485          sendData.source = "Twittperator"; 
    1452           tw.post("http://api.twitter.com/1/statuses/update.json", sendData, function(text) { 
     1486          tw.post("statuses/update.json", sendData, function(text) { 
    14531487            let t = Utils.fixStatusObject(JSON.parse(text || "{}")).text; 
    14541488            Twittperator.echo("Your post " + '"' + t + '" (' + t.length + " characters) was sent."); 
     
    14571491      ); 
    14581492    }, // }}} 
    1459     reTweet: function(id) { // {{{ 
    1460       let url = "http://api.twitter.com/1/statuses/retweet/" + id + ".json"; 
    1461       tw.post(url, null, function(text) { 
     1493    retweet: function(id) { // {{{ 
     1494      let url = "statuses/retweet/" + id + ".json"; 
     1495      tw.put(url, null, function(text) { 
    14621496        let res = Utils.fixStatusObject(JSON.parse(text)); 
    1463         Twittperator.echo("ReTweet: " + res.retweeted_status.text); 
     1497        Twittperator.echo("Retweet: " + res.retweeted_status.text); 
    14641498      }); 
    14651499    }, // }}} 
    14661500    unfavorite: function(id) { // {{{ 
    1467       tw.post("http://api.twitter.com/1/favorites/destroy/" + id + ".json", null, function(text) { 
     1501      tw.delete("favorites/destroy/" + id + ".json", null, function(text) { 
    14681502        let res = Utils.fixStatusObject(JSON.parse(text)); 
    14691503        Twittperator.echo("unfav: " + res.user.name + " " + res.text, true); 
     
    14801514        let [head, tail] = [center[0], center.slice(1)]; 
    14811515        let right = str.substring(m.index + m[0].length); 
    1482         let content = head === "@" ? <a highlight="URL" href={"http://twitter.com/" + tail}> {center} </a> 
    1483                                    : <a highlight="URL" href={center}> {center} </a> 
     1516        let content = head === "@" ? <a highlight="URL" href={setting.showTLURLScheme + "://twitter.com/" + tail}> {center} </a> 
     1517                                   : <a highlight="URL" href={center}> {center} </a>; 
    14841518        return <>{Utils.anchorLink(left)}{content}{Utils.anchorLink(right)}</>; 
    14851519      } 
     
    14871521    }, // }}} 
    14881522    fixStatusObject: function(st) { // {{{ 
    1489       const Amps = { 
     1523      const ENTITIY_PAIRS = { 
    14901524        lt: "<", 
    14911525        gt: ">", 
    1492         quot: "\"", 
     1526        quot: '"' 
    14931527        hellip: "\u2026", 
    14941528      }; 
    14951529 
    1496       function unescapeAmps(str) 
    1497         str.replace(/&([^;]+);/g, function(m, n) Amps[n] || m); 
     1530      function unescapeSpecificEntities(str) 
     1531        str.replace(/&([a-z\d]+);/g, function(m, n) ENTITIY_PAIRS[n] || m); 
     1532 
     1533      function unescapeBrakets(str) 
     1534        str.replace(/&lt;/g, "<").replace(/&gt;/g, ">"); 
    14981535 
    14991536      let result = {}; 
    15001537      for (let [n, v] in Iterator(st)) { 
    1501         result[n] = v && typeof v === 'object' ? Utils.fixStatusObject(v) : 
    1502                     n === 'text'               ? unescapeAmps(v) : 
     1538        result[n] = v && typeof v === "object" ? Utils.fixStatusObject(v) : 
     1539                    n === "text"               ? unescapeBrakets(v) : 
    15031540                    v; 
    15041541      } 
     
    15201557      liberator.echo("[Twittperator] " + msg); 
    15211558    }, // }}} 
    1522     isProtected: function({statusId, userId, screenName}) { // {{{ 
     1559    isProtected: function({ statusId, userId, screenName }) { // {{{ 
     1560      if (screenName && isp(function(st) st.user && st.user.screen_name == screenName)) 
     1561        return true; 
     1562 
     1563      if (statusId && isp(function(st) st.user && st.id == statusId)) 
     1564        return true; 
     1565 
     1566      if (userId && find(function(st) st.user && st.user.id == userId)) 
     1567        return true; 
     1568 
     1569      return false; 
     1570 
    15231571      function isp(f) { 
    15241572        let r; 
    15251573        history.some(function(st) f(st) && (r = st)); 
    1526         return r && r.user.protected && r.user.screen_name; 
     1574        return (r && r.user.protected && r.user.screen_name) ? true : false; 
    15271575      } 
    1528  
    1529       if (screenName && isp(function(st) st.user && st.user.screen_name == screenName)) 
    1530         return true; 
    1531  
    1532       if (statusId && isp(function(st) st.user && st.id == statusId)) 
    1533         return true; 
    1534  
    1535       if (userId && find(function(st) st.user && st.user.id == userId)) 
    1536         return true; 
    1537  
    1538       return false; 
    15391576    }, // }}} 
    15401577    loadPlugins: function() { // {{{ 
     
    16371674    }, // }}} 
    16381675    showTwitterMentions: function(arg) { // {{{ 
    1639       tw.get("http://api.twitter.com/1/statuses/mentions.json", null, function(text) { 
     1676      tw.get("statuses/mentions.json", null, function(text) { 
    16401677        Twittperator.showTL(JSON.parse(text).map(Utils.fixStatusObject)); 
    16411678      }); 
     
    16791716    withProtectedUserConfirmation: function(check, actionName, action) { // {{{ 
    16801717      function canceled() 
    1681         Twittperator.echo('Canceled.'); 
     1718        Twittperator.echo("Canceled."); 
    16821719 
    16831720      let protectedUserName = Twittperator.isProtected(check); 
    16841721      if (protectedUserName) { 
    16851722        commandline.input( 
    1686           protectedUserName + ' is protected user! Do you really want to ' + actionName + '? Input "yes" if you want. => ', 
    1687           function(s) (s === 'yes' ? action : canceled)(), 
     1723          protectedUserName + " is protected user! Do you really want to " + actionName + '? Input "yes" if you want. => ', 
     1724          function(s) (s === "yes" ? action : canceled)(), 
    16881725          { 
    16891726            onCancel: canceled 
     
    17341771        get expr() { 
    17351772          return RegExp( 
    1736             '^' + 
     1773            "^" + 
    17371774            this.command.map(function(c) 
    17381775              let (r = util.escapeRegex(c)) 
    1739                 (/^\W$/(c) ? r : r + ' ') 
    1740             ).join("|" /* /|/ */) 
     1776                (/^\W$/(c) ? r : r + " ") 
     1777            ).join("|") 
    17411778          ); 
    17421779        }, 
    17431780        match: function(s) s.match(this.expr), 
    1744         action: function(args) init.action(args.literalArg.replace(this.expr, '').trim()) 
     1781        action: function(args) init.action(args.literalArg.replace(this.expr, "").trim()) 
    17451782      }; 
    17461783    }; 
     
    17711808        description: "Show mentions or follower tweets", 
    17721809        action: function(arg) { 
    1773           if (arg.match(/^.+/)) { 
     1810          if (arg.length > 0) { 
    17741811            Twittperator.showFollowersStatus(arg, true); 
    17751812          } else { 
     
    19041941        return; 
    19051942      context.title = ["Sub command", "Description"]; 
    1906       context.completions = SubCommands.map(function({command, description}) [command[0], description]); 
     1943      context.completions = SubCommands.map(function({ command, description }) [command[0], description]); 
    19071944    } // }}} 
    19081945 
     
    19872024      proxyHost: gv.twittperator_proxy_host, 
    19882025      proxyPort: gv.twittperator_proxy_port, 
    1989       screenName: gv.twittperator_screen_name 
     2026      screenName: gv.twittperator_screen_name, 
     2027      apiURLBase: "http" + (!!gv.twittperator_use_ssl_connection_for_api_ep ? "s" : "") + 
     2028                  "://api.twitter.com/" + (gv.twittperator_twitter_api_version || 1)  + "/", 
    19902029    }); 
    19912030