{"ts":1371540825938,"silentsave":true,"restoring":false,"patch":[[]],"length":0}
{"contributors":[],"silentsave":false,"ts":1371541111295,"patch":[[{"diffs":[[1,"var request = require('request');\n\nconsole.log(42);"]],"start1":0,"start2":0,"length1":0,"length2":51}]],"length":51,"saved":false}
{"ts":1371541269245,"patch":[[{"diffs":[[0,");\n\n"],[-1,"console.log(42);"],[1,"function Rotten"]],"start1":31,"start2":31,"length1":20,"length2":19}]],"length":50,"saved":false}
{"ts":1371541305069,"patch":[[{"diffs":[[0,"n Rotten"],[1," (opt ) {\n       \n}"]],"start1":42,"start2":42,"length1":8,"length2":27}]],"length":69,"saved":false}
{"ts":1371541431274,"patch":[[{"diffs":[[0,"ten (opt"],[-1," "],[0,") {\n    "]],"start1":47,"start2":47,"length1":17,"length2":16},{"diffs":[[0,"      \n}"],[1,"\n\nRotten.prototype.get = function (id, cb) {\n    \n\n}"]],"start1":60,"start2":60,"length1":8,"length2":60}]],"length":120,"saved":false}
{"ts":1371541438820,"patch":[[{"diffs":[[0,"b) {"],[-1,"\n    \n\n"],[0,"}"]],"start1":108,"start2":108,"length1":12,"length2":5}]],"length":113,"saved":false}
{"ts":1371541774008,"patch":[[{"diffs":[[0,"st')"],[-1,";\n"],[1,",\n    URL = {\n        \n        \n    };\n\n/**\n * \n */"],[0,"\nfun"]],"start1":28,"start2":28,"length1":10,"length2":59},{"diffs":[[0,", cb) {}"],[1,"\nRotten.prototype.get = function (id, cb) {}"]],"start1":154,"start2":154,"length1":8,"length2":52}]],"length":206,"saved":false}
{"ts":1371542026986,"patch":[[{"diffs":[[0,"    \n}\n\n"],[1,"\n"],[0,"Rotten.p"]],"start1":111,"start2":111,"length1":16,"length2":17},{"diffs":[[0,"otten.prototype."],[-1,"get"],[1,"boxoffice"],[0," = function (id,"]],"start1":121,"start2":121,"length1":35,"length2":41},{"diffs":[[0,"= function ("],[-1,"id, cb"],[1,") {}\nRotten.prototype.info = Rotten.prototype.get = function ("],[0,") {}\nRotten."]],"start1":147,"start2":147,"length1":30,"length2":86},{"diffs":[[0,"otten.prototype."],[-1,"ge"],[1,"cas"],[0,"t = function (id"]],"start1":227,"start2":227,"length1":34,"length2":35},{"diffs":[[0,"on ("],[-1,"id, cb) {}"],[1,") {}\n\n\nRotten.prototype.search = function () {}\n\n\n\n"]],"start1":256,"start2":256,"length1":14,"length2":55}]],"length":311,"saved":false}
{"ts":1371542112928,"patch":[[{"diffs":[[0," function () {}\n"],[1,"\n"],[0,"Rotten.prototype"]],"start1":148,"start2":148,"length1":32,"length2":33},{"diffs":[[0,".info = "],[1,"function () {}\n"],[0,"Rotten.p"]],"start1":181,"start2":181,"length1":16,"length2":31},{"diffs":[[0,"ype."],[-1,"get = function () {}\nRotten.prototype.c"],[1,"cast = function () {}\nRotten.prototype.clips = function () {}\nRotten.prototype.reviews = function () {}\nRotten.prototype.similar = function () {}\nRotten.prototype.ali"],[0,"as"],[-1,"t"],[0," = f"]],"start1":217,"start2":217,"length1":50,"length2":176},{"diffs":[[0,"ion () {}\n\n\n"],[1,"\n"],[0,"Rotten.proto"]],"start1":397,"start2":397,"length1":24,"length2":25}]],"length":454,"saved":false}
{"ts":1371542184189,"patch":[[{"diffs":[[0,"type.box"],[-1,"o"],[1,"O"],[0,"ffice = "]],"start1":132,"start2":132,"length1":17,"length2":17},{"diffs":[[0,"on () {}"],[1,"\nRotten.prototype.inTheaters = function () {}\nRotten.prototype.opening = function () {}\nRotten.prototype.upcoming = function () {}"],[0,"\n\nRotten"]],"start1":155,"start2":155,"length1":16,"length2":146},{"diffs":[[0," () {}\n\n"],[-1,"\n\n"],[0,"Rotten.p"]],"start1":530,"start2":530,"length1":18,"length2":16}]],"length":582,"saved":false}
{"ts":1371542575363,"patch":[[{"diffs":[[0,"        "],[-1,"\n        "],[1,"\"boxOffice\": \"\",\n        \"inTheaters\": \"\",\n        \"opening\": \"\",\n        \"upcoming\""],[0,"\n    };\n"]],"start1":46,"start2":46,"length1":25,"length2":100}]],"length":657,"saved":false}
{"contributors":[],"silentsave":false,"ts":1371630602327,"patch":[[{"diffs":[[0,"'),\n"],[1,"\n"],[0,"    "],[-1,"URL = {\n        \"boxOffice\": \"\""],[1,"util = require('util'),\n    API = require('./API'),\n\n    /**\n     * Returns the specified data as a JSON object,\n     * or an object with a single 'error' property if \n     * the parsing fails.\n     * \n     * @param data the data to parse as JSON\n     */\n    toJSON = function(data) {\n        try {\n            return JSON.parse(data);\n        } catch (e) {\n            return {\n                \"error\": \"Error parsing the response !\"\n            };\n        }\n    },\n\n    // true if the provided id is valid, false otherwise\n    isId = (function () {\n        var regex = /^[0-9]+$/;\n        return (function (id) { return regex.test(id); });\n    })(),\n    \n    // true if the provided imdb id is valid, false otherwise\n    isImdbId = (function () {\n        var regex = /^(tt)?[0-9]+$/;\n        return (function (id) { return regex.test(id); });\n    })(),\n    \n    // Invoke the callback or throw the error\n    cbOrThrow = function (cb, err) {\n        if (typeof cb === 'function') {\n            cb(err, null); \n        } else {\n            throw err;\n        }\n    },\n    \n    // Checks the given id, informing the client with the specified callback\n    // if the id is not valid.\n    checkId = function (id) {\n        return (typeof id === 'string' && isId(id)) ? id : undefined; \n    }"],[0,",\n    "],[1,"\n"],[0,"    "],[-1,"\"inTheaters\": \"\",\n        \"opening\": \"\",\n        \"upcoming\"\n    };\n\n/**\n * \n */\nfunction Rotten (opt) {\n       \n"],[1,"/**\n     * Handles the actual HTTP GET request at the specified url\n     * with the given parameters. \n     * Calls the optionnal callback upon completion\n     * \n     * @param url {String} the url where to make the request to\n     * @param params {Object} the request parameters\n     * @param cb [optional] {Function} the callback\n     */\n    _get = function(url, params, cb) {\n        \n        request.get({\n            \"uri\": url,\n            \"qs\": params\n        }, function(url, res, data) {\n\n            var err = null;\n            data = toJSON(data);\n\n            if (res.statusCode !== 200) {\n                err = new Error(\"Status code : \" + res.statusCode);\n            } else if (data && data.error) {\n                err = new Error(data.error);\n            }\n\n            if (typeof cb === 'function') {\n                cb(err, data);\n            }\n        });\n    },\n    \n    /**\n     * Handles the client request for the named API.\n     * \n     * @param name {String} the API service\n     * @param opt {Object} the request options\n     * @param cb [optional] {Function} the callback\n     */\n    _handle = function (name, opt, cb) {\n        \n        var api = API[name],\n            url = api.url,\n            params = api.params ? api.params() : {};\n        \n        // Require a callback to exists.\n        if (typeof cb !== 'function') {\n            throw new Error(\"Callback is required !\");\n        }\n        \n        // Format url if needed\n        if (api.format && opt[api.format]) {\n            url = util.format.call(null, url, opt[api.format]);\n        }\n        \n        // Get client parameters\n        opt = opt || {};\n        for (var p in params) {\n            if (p in opt) {\n                params[p] = opt[p];\n            }\n        }\n        params.apikey = this.key;\n        \n        _get(url, params, cb);\n    };\n\n/**\n * Constructs a Rotten object with the given options.\n * \n * If opt is a String it is considered as the API key.\n * If it is an object, the following properties apply :\n *  - 'key' : the Rotten Tomatoes API key\n *  - 'limit' : the result limit per page when applicable \n */\nfunction Rotten(opt) {\n\n    if (typeof opt === 'string') { opt = {\"key\": opt}; }\n\n    opt = opt || {};\n    \n    this.key = opt.key;\n    this.limit = opt.limit || API.LIMIT;\n\n    if (typeof this.key !== 'string') {\n        throw new Error(\"Invalid API key\");\n    "],[0,"}\n"],[1,"}"],[0,"\n\n"],[1,"/**\n *\n * \n */\n"],[0,"Rott"]],"start1":30,"start2":30,"length1":169,"length2":3722},{"diffs":[[0,"tion"],[-1," () {}\nRotten.prototype.inTheaters = function () {}\nRotten.prototype.opening = function () {}\nRotten.prototype.upcoming = function () {}\n\nRotten.prototype.info = function () {}\nRotten.prototype.cast = function () {}\nRotten.prototype.clips = function () {}\nRotten.prototype.reviews = function () {}\nRotten.prototype.similar = function () {}\nRotten.prototype.alias = function () {}\n\nRotten.prototype.search = function () {}\n\n\n"],[1,"(opt, cb) {\n    \n    if (arguments.length === 1) { \n        cb = opt;\n        opt = null;\n    } else {\n        if (typeof opt === 'string') { \n            opt = {\"country\": opt};\n        } else if (typeof opt === 'number') {\n            opt = {\"limit\": opt};\n        } \n    }\n    \n    _handle.call(this, \"boxOffice\", opt, cb);\n};\n\n/**\n *\n * \n */\nRotten.prototype.inTheaters = function(opt, cb) {\n    \n    if (arguments.length === 1) { \n        cb = opt;\n        opt = null;\n    } else {\n        if (typeof opt === 'string') {\n            opt = {\"country\": opt};\n        } else if (typeof opt === 'number') {\n            opt = {\"page_limit\": opt};\n        } else {\n            opt.page_limit = opt ? (opt.limit || opt.page_limit || this.limit) : this.limit;\n        }\n    }\n    \n    _handle.call(this, \"inTheaters\", null, cb);\n};\n\n/**\n *\n * \n */\nRotten.prototype.opening = function(opt, cb) {\n    \n    if (arguments.length === 1) { \n        cb = opt;\n        opt = null;\n    } else {\n        if (typeof opt === 'string') { \n            opt = {\"country\": opt};\n        } else if (typeof opt === 'number') {\n            opt = {\"limit\": opt};\n        } \n    }\n    \n    _handle.call(this, \"opening\", null, cb);\n};\n\n/**\n *\n * \n */\nRotten.prototype.upcoming = function(opt, cb) {\n    \n    if (arguments.length === 1) { \n        cb = opt;\n        opt = null;\n    } else {\n        if (typeof opt === 'string') { \n            opt = {\"country\": opt};\n        } else if (typeof opt === 'number') {\n            opt = {\"limit\": opt};\n        } \n    }\n    _handle.call(this, \"upcoming\", null, cb);\n};\n\n/**\n * Retrieves detailed information on a movie specified by its id.\n * \n * @param id {String} the movie's id\n */\nRotten.prototype.get = \nRotten.prototype.info = function(id, cb) {\n    id = checkId(id);\n    if (!id) {\n        return cbOrThrow(cb, new Error(\"Invalid id.\"));\n    }\n    _handle.call(this, \"info\", {\"id\": id}, cb);\n};\n\n/**\n * Retrieves the full casting of the movie specified by its id.\n * \n * @param id {String} the movie's id\n */\nRotten.prototype.cast = function(id, cb) {\n    id = checkId(id);\n    if (!id) {\n        return cbOrThrow(cb, new Error(\"Invalid id.\"));\n    }\n    _handle.call(this, \"cast\", {\"id\": id}, cb);\n};\n\n/**\n * Retrieves movie clips related to the movie specified by its id.\n * \n * @param id {String} the movie's id\n */\nRotten.prototype.clips = function(id, cb) {\n    id = checkId(id);\n    if (!id) {\n        return cbOrThrow(cb, new Error(\"Invalid id.\"));\n    }\n    _handle.call(this, \"clips\", {\"id\": id}, cb);\n};\n\n/**\n * \n * \n */\nRotten.prototype.reviews = function(opt, cb) {\n    var id = checkId(opt);\n    \n    opt = opt || {};\n    \n    opt.id = id || opt.id;\n    opt.page_limit = opt.limit || opt.page_limit || this.limit;\n    \n    if (!opt.id) {\n        return cbOrThrow(cb, new Error(\"Invalid id.\"));\n    }\n    \n    _handle.call(this, \"reviews\", opt, cb);\n};\n\n/**\n * \n * \n */\nRotten.prototype.similar = function(opt, cb) {\n    \n    var id = checkId(opt);\n    \n    if (typeof opt ==='string') {\n        opt = {\"id\": id}\n    } else {\n        opt = opt || {};\n        \n        opt.id = id || opt.id;\n        opt.page_limit = opt.limit || opt.page_limit || this.limit;\n    }\n    \n    if (!opt.id) {\n        return cbOrThrow(cb, new Error(\"Invalid id.\"));\n    }\n    \n    _handle.call(this, \"similar\", opt, cb);\n};\n\n/**\n * Retrieves detailed information on a movie specified by its IMDB id.\n * \n * @param id {String} the movie's IMDB id, optionaly starting with 'tt' as IMDB ids do.\n */\nRotten.prototype.alias = function(id, cb) {\n     \n    if (typeof id === 'string' && isImdbId(id)) {\n        id = {\"id\": id.replace(\"tt\", '')}; \n    } else {\n        return cbOrThrow(cb, new Error(\"Invalid IMDB id.\"));\n    }\n    \n    _handle.call(this, \"alias\", id, cb);\n};\n\n/**\n * Search for a movie based on a query String.\n * \n * @param opt {String|Object} the search options\n *  - If opt is a String then it is treated as the query String\n *  - If opt is an object then the following properties apply :\n *      q | query : the query string, must be non-empty !\n *      page      : the page number (not the number of page)\n *      limit     : the limit of result per page\n */\nRotten.prototype.search = function(opt, cb) {\n    \n    if (typeof opt === 'string' || typeof opt === 'number') { \n        opt = {\"q\": opt + ''}; \n    } else {\n        opt = opt || {};\n        opt.q = opt.q || opt.query || null;\n        opt.page_limit = opt.limit || opt.page_limit || this.limit;\n    }\n    \n    // Don't make the query on an empty string\n    if (typeof opt.q !== 'string' || opt.q.trim() === '') {\n        return cbOrThrow(cb, new Error(\"Query must be a non-empty string.\"));\n    }\n    \n    _handle.call(this, \"search\", opt, cb);\n};\n\nmodule.exports = function(opt) {\n    return new Rotten(opt);\n};"],[0,"\n"]],"start1":3781,"start2":3781,"length1":429,"length2":4807}]],"length":8588,"saved":false}
{"ts":1371630630354,"patch":[[{"diffs":[[0,"ded "],[-1,"imdb"],[1,"IMDB"],[0," id "]],"start1":720,"start2":720,"length1":12,"length2":12}]],"length":8588,"saved":false}
{"ts":1371630665425,"patch":[[{"diffs":[[0,"ack "],[-1,"or throw the error"],[1,"with given error or throw it"],[0,"\n   "]],"start1":922,"start2":922,"length1":26,"length2":36}]],"length":8598,"saved":false}
{"ts":1371630713360,"patch":[[{"diffs":[[0," // "],[-1,"Checks the given id, informing the client with the specified callback\n    // if the id is not valid."],[1,"returns the specified id if valid, undefined otherwise"],[0,"\n   "]],"start1":1125,"start2":1125,"length1":108,"length2":62}]],"length":8552,"saved":false}
{"ts":1371630729312,"patch":[[{"diffs":[[0,"fied url"],[-1,"\n     *"],[0," with th"]],"start1":1360,"start2":1360,"length1":23,"length2":16}]],"length":8545,"saved":false}
{"ts":1371630731280,"patch":[[{"diffs":[[0,"ied url "],[1,"\n     * "],[0,"with the"]],"start1":1361,"start2":1361,"length1":16,"length2":24}]],"length":8553,"saved":false}
{"ts":1371630736100,"patch":[[{"diffs":[[0,"eters. \n"],[1,"     * \n"],[0,"     * C"]],"start1":1397,"start2":1397,"length1":16,"length2":24},{"diffs":[[0,"mpletion"],[1,"."],[0,"\n     * "]],"start1":1456,"start2":1456,"length1":16,"length2":17}]],"length":8562,"saved":false}
{"ts":1371630840734,"patch":[[{"diffs":[[0,"ies apply :\n"],[1," * \n"],[0," *  - 'key' "]],"start1":3323,"start2":3323,"length1":24,"length2":28},{"diffs":[[0,"' : the "],[1,"default "],[0,"result l"]],"start1":3393,"start2":3393,"length1":16,"length2":24}]],"length":8574,"saved":false}
{"ts":1371630849955,"patch":[[{"diffs":[[0,"ing') { "],[1,"\n        "],[0,"opt = {\""]],"start1":3503,"start2":3503,"length1":16,"length2":25},{"diffs":[[0,": opt}; "],[1,"\n    "],[0,"}\n\n    o"]],"start1":3532,"start2":3532,"length1":16,"length2":21}]],"length":8588,"saved":false}
{"ts":1371631109512,"patch":[[{"diffs":[[0,"\n    }\n}\n\n/**\n *"],[1," Retrieves Top Box Office Earning Movies.\n * Sorted by Most Recent Weekend Gross Ticket Sales.\n * \n * If a single parameter is given, then it should\n * be the callback. The result limit and country will defaults\n * to respectively 10 and 'us'.'\n * \n * @param opt {Object|String|int|function}\n * @param cb {function} the callback\n * "],[0,"\n * \n */\nRotten."]],"start1":3723,"start2":3723,"length1":32,"length2":364}]],"length":8920,"saved":false}
{"ts":1371631176954,"patch":[[{"diffs":[[0,"nction}\n"],[1," *  - a string to specify the country as (ISO 3166-1 alpha-2)\n *  - a number to specify the limit\n *  - an object with both properties 'limit' and 'country'\n * \n"],[0," * @para"]],"start1":4023,"start2":4023,"length1":16,"length2":177},{"diffs":[[0,"allback\n * \n"],[-1," * \n"],[0," */\nRotten.p"]],"start1":4221,"start2":4221,"length1":28,"length2":24}]],"length":9077,"saved":false}
{"ts":1371631248471,"patch":[[{"diffs":[[0,"allback\n"],[-1," * \n"],[0," */\nRott"]],"start1":4221,"start2":4221,"length1":20,"length2":16},{"diffs":[[0," cb);\n};\n\n/**\n *"],[-1,"\n * "],[1," Retrieves movies currently in theaters.\n *\n * The same parameters as the Rotten#boxOffice method apply."],[0,"\n */\nRotten.prot"]],"start1":4591,"start2":4591,"length1":36,"length2":136}]],"length":9173,"saved":false}
{"ts":1371631295864,"patch":[[{"diffs":[[0," cb);\n};\n\n/**\n *"],[-1,"\n * "],[1," Retrieves current opening movies\n *\n * The same parameters as the Rotten#boxOffice method apply."],[0,"\n */\nRotten.prot"]],"start1":5190,"start2":5190,"length1":36,"length2":129},{"diffs":[[0,"\n\n/**\n *"],[-1,"\n * "],[1," Retrieves upcoming movies\n *\n * The same parameters as the Rotten#boxOffice method apply."],[0,"\n */\nRot"]],"start1":5671,"start2":5671,"length1":20,"length2":106}]],"length":9352,"saved":false}
{"ts":1371631372940,"patch":[[{"diffs":[[0," upcoming movies"],[1,"."],[0,"\n *\n * The same "]],"start1":5689,"start2":5689,"length1":32,"length2":33}]],"length":9353,"saved":false}
{"ts":1371631380288,"patch":[[{"diffs":[[0,"heaters."],[1," A 'page' \n * property can be specified if the first parameter is an object."],[0,"\n *\n * T"]],"start1":4639,"start2":4639,"length1":16,"length2":92},{"diffs":[[0,"ce method apply."],[1," A 'page' \n * property can be specified if the first parameter is an object."],[0,"\n */\nRotten.prot"]],"start1":5830,"start2":5830,"length1":32,"length2":108}]],"length":9505,"saved":false}
{"ts":1371631405037,"patch":[[{"diffs":[[0," the movie's id\n"],[1," * @param cb {function) the callback\n"],[0," */\nRotten.proto"]],"start1":6384,"start2":6384,"length1":32,"length2":69}]],"length":9542,"saved":false}
{"ts":1371631412100,"patch":[[{"diffs":[[0," the movie's id\n"],[1," * @param cb {function) the callback\n"],[0," */\nRotten.proto"]],"start1":6752,"start2":6752,"length1":32,"length2":69}]],"length":9579,"saved":false}
{"ts":1371631415489,"patch":[[{"diffs":[[0,"ie's id\n"],[1," * @param cb {function) the callback\n"],[0," */\nRott"]],"start1":7107,"start2":7107,"length1":16,"length2":53}]],"length":9616,"saved":false}
{"ts":1371631556032,"patch":[[{"diffs":[[0,"cb);\n};\n\n/**\n * "],[1,"Retrieves the reviews for a movie."],[0,"\n * \n */\nRotten."]],"start1":7343,"start2":7343,"length1":32,"length2":66},{"diffs":[[0,"\n/**\n * "],[-1,"\n * "],[1,"Shows similar movies for a movie specified by its id. \n * \n * @param opt {Object|String}\n *  - a string to specify the movie's id.\n *  - a object with both 'limit' and 'id' properties\n * @parama cb {function}"],[0,"\n */\nRot"]],"start1":7736,"start2":7736,"length1":20,"length2":224}]],"length":9854,"saved":false}
{"ts":1371631636745,"patch":[[{"diffs":[[0,"ie.\n * \n"],[1," * @param opt {Object}\n *  - 'review_type' : one of \"all\", \"top_critic\" and \"dvd\"\n *  - 'limit' : number of reviews per page\n *  - 'page' : the page number\n *  - 'country' : for localized data\n * @parama cb {function}\n"],[0," */\nRott"]],"start1":7390,"start2":7390,"length1":16,"length2":234}]],"length":10072,"saved":false}
{"contributors":[],"silentsave":false,"ts":1371632088913,"patch":[[{"diffs":[[0,"ids do.\n */\n"],[1,"Rotten.prototype.imdb =\n"],[0,"Rotten.proto"]],"start1":8768,"start2":8768,"length1":24,"length2":48}]],"length":10096,"saved":false}
