<commit_before>"use strict";

var
    _ = require('underscore'),
    async = require('async'),
    fs = require('fs'),
    moment = require('moment'),
    path = require('path');

var Asset = function(settings) {
    this.init(settings);
};

// static members
_.extend(Asset, {
    CACHE_PATH: __dirname + '/cache_path',
    VERSION: 'v1',
    configure: function(opts) {
        opts = opts || {};

        Asset.CACHE_ID = opts.cacheId;
        Asset.CACHE_PATH = opts.cachePath || Asset.CACHE_PATH;
        Asset.VERSION = opts.version || 'v1';
        Asset.COMPRESS = opts.compress;

        return Asset;
    },
    // default compressors
    compressors: {
        none: function(file, data, cb) {
            cb(null, data);
        }
    },
    registerCompressor: function(id, handler, force) {
        if (Asset.compressors[id] && !force) {
            console.warn("WARNING: There is already a compressor registered with the id '" + id + "'!");
            return false;
        }

        Asset.compressors[id] = handler;
        return true;
    }
});

_.extend(Asset.prototype, {
    init: function(settings) {
        settings = settings || {};

        //save the initial settings for later
        this.settings = settings;

        if (!settings.id) {
            throw new Error('Asset must have an id!');
        }
        this.id = settings.id;

        if (!settings.files) {
            throw new Error('Asset missing a valid set of files!');
        }
        this.files = settings.files;

        if (!settings.pattern) {
            throw new Error('Asset missing a valid pattern!');
        }
        this.pattern = settings.pattern;

        //necessary for reading the contents of binary files (e.g. images)
        this.encoding = settings.binary ? null : 'utf8';

        //a reference to the asset manager
        this.manager = settings.manager;

        //set the maximum age for the document in seconds
        this.maxAge = settings.maxAge || '3600' //one hour

        //set the compressor
        this.compressor = settings.compressor || 'none';
        //ensure we have a valid compressor type
        if (!_.contains(_.keys(Asset.compressors), this.compressor)) {
            console.warn('WARNING: Invalid compressor type supplied for Asset instance. Falling back to "none".');
            this.compressor = 'none';
        }

        //where to cache the rendered file
        this.cachePath = settings.cachePath || Asset.CACHE_PATH;

        //build the cacheId
        if (Asset.CACHE_ID) {
            this.cacheId = Asset.CACHE_ID;
        } else {
            // for development environments

            // get all the modified times for the files
            var mtimes = _.map(this.files, function(file) {
                var mtime = (fs.statSync(file) || {}).mtime || new Date(0);
                return Math.round(+mtime/1000);
            });

            // just take the largest and use that as the cacheId
            this.cacheId = Math.max.apply(Math, mtimes);
        }

        //expand the path pattern
        this._uri = this.pattern
                        .replace(/\:version/g, Asset.VERSION)
                        .replace(/\:cacheId/g, this.cacheId);
        this.__defineGetter__('uri', function() {
            return this._uri;
        });

        //get the cache headers for this asset
        this.__defineGetter__('cacheHeaders', function() {
            var headers = {},
                cacheControl = [],
                d = moment(),
                httpFormat = 'ddd, DD MMM YYYY HH:mm:ss \\G\\M\\T';

            if (this.cachedPath) {
                var mtime = fs.statSync(this.cachedPath).mtime;
                d = moment(mtime);
            }

            //use utc for http headers
            d.utc();

            //Last-Modified
            headers['Last-Modified'] = d.format(httpFormat);

            //Expires
            d.add('seconds', this.maxAge);
            headers['Expires'] = d.format(httpFormat);

            //Cache-Control
            cacheControl.push('max-age=' + this.maxAge);
            cacheControl.push('public');
            headers['Cache-Control'] = cacheControl.join(', ');

            //ETag
            headers['Etag'] = this.cacheId;

            //X-Powered-By
            headers['X-Powered-By'] = 'Express/exstatic';

            return headers;
        });
    },
    render: function(cb) {
        // should be overridden for each distinct type of asset
        var self = this,
            output = [];

        async.forEachSeries(
            this.files,
            function(file, forEachNext) {
                var basename = '/* ' + path.basename(file) + ' */\n',
                    contents = fs.readFileSync('./' + file, self.encoding);

                async.waterfall(
                    [
                        //preprocess
                        function(waterfallNext) {
                            if (self.preprocess && _.isFunction(self.preprocess)) {
                                self.preprocess(file, contents, function(err, processedContents) {
                                    if (err) {
                                        console.error("ERROR: Couldn't preprocess file " + file);
                                        console.error(err);

                                        //complain, but just pass along the unprocessed contents (for now)
                                        return waterfallNext(null, contents);
                                    }

                                    return waterfallNext(null, processedContents);
                                });
                            } else {
                                waterfallNext(null, contents);
                            }
                        },
                        //compress
                        function(data, waterfallNext) {
                            if (Asset.COMPRESS) {
                                Asset.compressors[self.compressor](
                                    file,
                                    data,
                                    function(err, out) {
                                        //not expecting an error
                                        waterfallNext(null, out);
                                    }
                                );
                            } else {
                                waterfallNext(null, data);
                            }
                        }
                    ],
                    //append to output
                    function(err, result) {
                        self.encoding && (result = basename + result);

                        output.push(result);
                        forEachNext();
                    }
                );
            },
            function(err) {
                //not expecting an error
                cb(null, output.length > 1 ? output.join('\n\n') : output[0]);
            }
        );
    },
    saveRenderedFile: function(cb) {
        var self = this,
            fullpath = path.join(this.cachePath, this.uri),
            created = [],
            pending = path.dirname(fullpath).split('/');

        pending[0] = '/' + pending[0];

        //create directories as needed
        while (pending.length) {
            created.push(pending.shift());

            var create = path.join.apply(path, created);

            if (!path.existsSync(create)) {
                fs.mkdirSync(create, '0755');
            }
        }

        //render and save the output
        this.render(function(err, fileContents) {
            //not expecting an error
            fs.writeFileSync(fullpath, fileContents, self.encoding);

            cb(null, fullpath);
        });
    },
    fetchCachedPath: function(cb) {
        if (this.cachedFilePath) {
            cb(null, this.cachedFilePath);
        } else {
            var self = this;

            this.saveRenderedFile(function(err, cachedFilePath) {
                //not expecting an error
                self.cachedFilePath = cachedFilePath;
                cb(null, cachedFilePath);
            });
        }
    }
});

module.exports = Asset.configure;
<commit_msg>Cleanup the asset init method<commit_after>"use strict";

var
    _ = require('underscore'),
    async = require('async'),
    fs = require('fs'),
    moment = require('moment'),
    path = require('path'),

    //utilities
    lcFirst = function(str) {
        var arr = str.split('');

        arr[0] = arr[0].toLowerCase();

        return arr.join('');
    },

    setupGetters = function(obj) {
        var funcs = _.functions(obj),
            getters = _.filter(funcs, function(f) { return /^_get\w+/.test(f); }),
            removeRE = /^_get/;

        _.each(getters, function(f) {
            var name = lcFirst(f.replace(removeRE, ''));
            obj.__defineGetter__(name, obj[f]);
        });
    };

var Asset = function(settings) {
    this.init(settings);
};

// static members
_.extend(Asset, {
    CACHE_PATH: __dirname + '/cache_path',
    VERSION: 'v1',
    configure: function(opts) {
        opts = opts || {};

        Asset.CACHE_PATH = opts.cachePath || Asset.CACHE_PATH;
        Asset.VERSION = opts.version || Asset.VERSION;
        Asset.COMPRESS = opts.compress;

        return Asset;
    },
    // default compressors
    compressors: {
        none: function(file, data, cb) {
            cb(null, data);
        }
    },
    registerCompressor: function(id, handler, force) {
        if (Asset.compressors[id] && !force) {
            console.warn("WARNING: There is already a compressor registered with the id '" + id + "'!");
            return false;
        }

        Asset.compressors[id] = handler;
        return true;
    }
});

_.extend(Asset.prototype, {
    init: function(settings) {
        settings = settings || {};

        //save the initial settings for later
        this.settings = settings;

        if (!settings.id) {
            throw new Error('Asset must have an id!');
        }
        this.id = settings.id;

        if (!settings.files) {
            throw new Error('Asset missing a valid set of files!');
        }
        this.files = settings.files;

        if (!settings.pattern) {
            throw new Error('Asset missing a valid pattern!');
        }
        this.pattern = settings.pattern;

        //necessary for reading the contents of binary files (e.g. images)
        this.encoding = settings.binary ? null : 'utf8';

        //a reference to the asset manager
        this.manager = settings.manager;

        //set the maximum age for the document in seconds
        this.maxAge = settings.maxAge || '3600' //one hour

        //set the compressor
        this.compressor = settings.compressor || 'none';
        //ensure we have a valid compressor type
        if (!_.contains(_.keys(Asset.compressors), this.compressor)) {
            console.warn('WARNING: Invalid compressor type supplied for Asset instance. Falling back to "none".');
            this.compressor = 'none';
        }

        //where to cache the rendered file
        this.cachePath = settings.cachePath || Asset.CACHE_PATH;

        //define getters
        setupGetters(this);
    },
    _getCacheId: function() {
        if (!this._cacheId) {
            // get all the modified times for the files
            var mtimes = _.map(this.files, function(file) {
                var mtime = (fs.statSync(file) || {}).mtime || new Date(0);
                return Math.round(+mtime/1000);
            });

            // just take the largest and use that as the cacheId
            this._cacheId = Math.max.apply(Math, mtimes);
        }

        return this._cacheId;
    },
    _getUri: function() {
        if (!this._uri) {
            //expand the path pattern
            this._uri = this.pattern
                            .replace(/\:version/g, Asset.VERSION)
                            .replace(/\:cacheId/g, this.cacheId);
        }

        return this._uri;
    },
    _getCacheHeaders: function() {
        if (!this._cacheHeaders) {
            var headers = {},
                cacheControl = [],
                d = moment(),
                httpFormat = 'ddd, DD MMM YYYY HH:mm:ss \\G\\M\\T';

            if (this.cachedPath) {
                var mtime = fs.statSync(this.cachedPath).mtime;
                d = moment(mtime);
            }

            //use utc for http headers
            d.utc();

            //Last-Modified
            headers['Last-Modified'] = d.format(httpFormat);

            //Expires
            d.add('seconds', this.maxAge);
            headers['Expires'] = d.format(httpFormat);

            //Cache-Control
            cacheControl.push('max-age=' + this.maxAge);
            cacheControl.push('public');
            headers['Cache-Control'] = cacheControl.join(', ');

            //ETag
            headers['Etag'] = this.cacheId;

            //X-Powered-By
            headers['X-Powered-By'] = 'Express/exstatic';

            this._cacheHeaders = headers;
        }

        return this._cacheHeaders;
    },
    render: function(cb) {
        // should be overridden for each distinct type of asset
        var self = this,
            output = [];

        async.forEachSeries(
            this.files,
            function(file, forEachNext) {
                var basename = '/* ' + path.basename(file) + ' */\n',
                    contents = fs.readFileSync('./' + file, self.encoding);

                async.waterfall(
                    [
                        //preprocess
                        function(waterfallNext) {
                            if (self.preprocess && _.isFunction(self.preprocess)) {
                                self.preprocess(file, contents, function(err, processedContents) {
                                    if (err) {
                                        console.error("ERROR: Couldn't preprocess file " + file);
                                        console.error(err);

                                        //complain, but just pass along the unprocessed contents (for now)
                                        return waterfallNext(null, contents);
                                    }

                                    return waterfallNext(null, processedContents);
                                });
                            } else {
                                waterfallNext(null, contents);
                            }
                        },
                        //compress
                        function(data, waterfallNext) {
                            if (Asset.COMPRESS) {
                                Asset.compressors[self.compressor](
                                    file,
                                    data,
                                    function(err, out) {
                                        //not expecting an error
                                        waterfallNext(null, out);
                                    }
                                );
                            } else {
                                waterfallNext(null, data);
                            }
                        }
                    ],
                    //append to output
                    function(err, result) {
                        self.encoding && (result = basename + result);

                        output.push(result);
                        forEachNext();
                    }
                );
            },
            function(err) {
                //not expecting an error
                cb(null, output.length > 1 ? output.join('\n\n') : output[0]);
            }
        );
    },
    saveRenderedFile: function(cb) {
        var self = this,
            fullpath = path.join(this.cachePath, this.uri),
            created = [],
            pending = path.dirname(fullpath).split('/');

        pending[0] = '/' + pending[0];

        //create directories as needed
        while (pending.length) {
            created.push(pending.shift());

            var create = path.join.apply(path, created);

            if (!path.existsSync(create)) {
                fs.mkdirSync(create, '0755');
            }
        }

        //render and save the output
        this.render(function(err, fileContents) {
            //not expecting an error
            fs.writeFileSync(fullpath, fileContents, self.encoding);

            cb(null, fullpath);
        });
    },
    fetchCachedPath: function(cb) {
        if (this.cachedFilePath) {
            cb(null, this.cachedFilePath);
        } else {
            var self = this;

            this.saveRenderedFile(function(err, cachedFilePath) {
                //not expecting an error
                self.cachedFilePath = cachedFilePath;
                cb(null, cachedFilePath);
            });
        }
    }
});

module.exports = Asset.configure;
<|endoftext|>


<commit_before>'use strict';

// BIP21
// =======
// Helper for parsing and building bitcoin: URIs
//
// Examples:
// =======
//  var uriString = 'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?message=Hey%20there&amount=1.212';
//
//  var uri = new BIP21(uriString);
//  uri.isValid() // true
//  uri.address // bitcore.Address object
//  uri.data.message // 'Hey there'
//  uri.data.amount // 1.212
//
//  uriString = new BIP21({
//    address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
//    message: 'Hey there',
//    amount: 1.212
//  }).getURI();

var URL = require('url');
var Address = require('./Address');

var BIP21 = function(arg) {
  this.data = {};
  this.address = undefined;

  if (typeof(arg) == 'string') {
    this.parse(arg);
  } else if (typeof(arg) == 'object') {
    this.fromObj(arg);
  } else if (typeof(arg) != 'undefined') {
    throw new Error('Invalid argument');
  }
}

BIP21.prototype.fromObj = function(obj) {
  for (var key in obj) {
    this.data[key] = obj[key];
  }

  if (obj.address) {
    delete this.data.address;
    this.setAddress(obj.address);
  }
}

BIP21.prototype.parse = function(uri) {
  var info = URL.parse(uri, true);

  if (info.protocol != 'bitcoin:') {
    throw new Error('Invalid protocol');
  }

  // workaround to host insensitiveness
  var group = /[^:]*:/?/?([^?]*)/.exec(uri);
  this.setAddress(group && group[1]);

  for (var arg in info.query) {
    var val = info.query[arg];
    if (arg === 'amount') val = Number(val);
    if (arg === 'r') this.data.merchant = val;
    this.data[arg] = val;
  }
}

BIP21.prototype.isValid = function(known) {
  var knownArguments = known || [];
  var valid = true;

  if (typeof(this.data.amount) != 'undefined') {
    valid &= !isNaN(this.data.amount);
  }

  if (this.address) {
    valid &= typeof(this.address) == 'object' && this.address.isValid();
  }

  // Require address or PayPro info
  valid &= !!(this.address || this.data.r);

  // Check required arguments
  for (var key in this.data) {
    if (key.indexOf('req-') == 0) {
      valid &= knownArguments.indexOf(key) != -1;
    }
  }

  return !!valid;
}

BIP21.prototype.setAddress = function(addr) {
  if (addr) {
    this.address = Address.validate(addr) ? new Address(addr) : addr;
  }

  return this;
}

BIP21.prototype.getURI = function() {
  return URL.format({
    protocol: 'bitcoin:',
    host: this.address,
    query: this.data
  });
}

module.exports = BIP21;
<commit_msg>bip21: fix regex parse error.<commit_after>'use strict';

// BIP21
// =======
// Helper for parsing and building bitcoin: URIs
//
// Examples:
// =======
//  var uriString = 'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?message=Hey%20there&amount=1.212';
//
//  var uri = new BIP21(uriString);
//  uri.isValid() // true
//  uri.address // bitcore.Address object
//  uri.data.message // 'Hey there'
//  uri.data.amount // 1.212
//
//  uriString = new BIP21({
//    address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
//    message: 'Hey there',
//    amount: 1.212
//  }).getURI();

var URL = require('url');
var Address = require('./Address');

var BIP21 = function(arg) {
  this.data = {};
  this.address = undefined;

  if (typeof(arg) == 'string') {
    this.parse(arg);
  } else if (typeof(arg) == 'object') {
    this.fromObj(arg);
  } else if (typeof(arg) != 'undefined') {
    throw new Error('Invalid argument');
  }
}

BIP21.prototype.fromObj = function(obj) {
  for (var key in obj) {
    this.data[key] = obj[key];
  }

  if (obj.address) {
    delete this.data.address;
    this.setAddress(obj.address);
  }
}

BIP21.prototype.parse = function(uri) {
  var info = URL.parse(uri, true);

  if (info.protocol != 'bitcoin:') {
    throw new Error('Invalid protocol');
  }

  // workaround to host insensitiveness
  var group = /[^:]*:\/?\/?([^?]*)/.exec(uri);
  this.setAddress(group && group[1]);

  for (var arg in info.query) {
    var val = info.query[arg];
    if (arg === 'amount') val = Number(val);
    if (arg === 'r') this.data.merchant = val;
    this.data[arg] = val;
  }
}

BIP21.prototype.isValid = function(known) {
  var knownArguments = known || [];
  var valid = true;

  if (typeof(this.data.amount) != 'undefined') {
    valid &= !isNaN(this.data.amount);
  }

  if (this.address) {
    valid &= typeof(this.address) == 'object' && this.address.isValid();
  }

  // Require address or PayPro info
  valid &= !!(this.address || this.data.r);

  // Check required arguments
  for (var key in this.data) {
    if (key.indexOf('req-') == 0) {
      valid &= knownArguments.indexOf(key) != -1;
    }
  }

  return !!valid;
}

BIP21.prototype.setAddress = function(addr) {
  if (addr) {
    this.address = Address.validate(addr) ? new Address(addr) : addr;
  }

  return this;
}

BIP21.prototype.getURI = function() {
  return URL.format({
    protocol: 'bitcoin:',
    host: this.address,
    query: this.data
  });
}

module.exports = BIP21;
<|endoftext|>


<commit_before>"use strict"
/*
 * Crawl a URL and fetch all childs of that page.
 * TODO: Validate repeated pages through the site
 *
 * Created by chriteixeira
 */
const request = require('request');
const cheerio = require('cheerio');
var Crawl = function(url, options){
    this.url = url;
    this.options = options;
    this.response = null;
    this.html = null;
    this.childs = [];
}

Crawl.prototype.start = function(){
    var options = {
        url: this.url,
        strictSSL: false
    }
    var self = this;
    request(options,function(err, response, html){
        if(err)
            return console.error(err);
        var $ = cheerio.load(html);
        self.html = html;
        self.response = response;
        extractChilds(self,$);

    });

}

function extractChilds(crawl, $){
    var links = $("a[href^='/']");
    var url = crawl.response.request.uri.protocol + "//" + crawl.response.request.uri.host;
    for(var i in links){
        if( links[i].attribs !== undefined && links[i].attribs['href'] !== undefined ){
            var linkUrl = url + links[i].attribs['href'];
            if(linkUrl !== crawl.url && crawl.childs.indexOf(linkUrl) === -1){
                crawl.childs.push(linkUrl);
            }
        }
    }
    console.log(crawl.childs);
}

module.exports = Crawl;<commit_msg>Small refactor<commit_after>"use strict"
/*
 * Crawl a URL and fetch all childs of that page.
 * TODO: Validate repeated pages through the site
 *
 * Created by chriteixeira
 */
const request = require('request');
const cheerio = require('cheerio');
var Crawl = function(url, options, _parent){
    this.url = url;
    this.options = options;
    this.response = null;
    this.html = null;
    this.childs = [];
    this.parent = _parent;
}

Crawl.prototype.start = function(){
    var options = {
        url: this.url,
        strictSSL: false
    }
    var self = this;
    request(options,function(err, response, html){
        if(err)
            return console.error(err);
        var $ = cheerio.load(html);
        self.html = html;
        self.response = response;
        extractChilds(self,$);
    });
}

/*
 * Extract all the child pages of a single page. The child extaction will be based on the
 * crawl options.
 */
function extractChilds(crawl, $){
    var links = $("a[href^='/']");
    var url = crawl.response.request.uri.protocol + "//" + crawl.response.request.uri.host;
    for(var i in links){
        if( links[i].attribs !== undefined && links[i].attribs['href'] !== undefined ){
            var linkUrl = url + links[i].attribs['href'];
            if(linkUrl !== crawl.url && crawl.childs.indexOf(linkUrl) === -1){
                crawl.childs.push(new Crawl(linkUrl, crawl.options, crawl));
            }
        }
    }
    console.log(crawl.childs);
}

module.exports = Crawl;<|endoftext|>


<commit_before>'use strict'
const grunt = require('gruntfile-api')
const fs = require('fs')
const path = require('path')
const spawn = require('child_process').spawn

global.processes = {}

exports.getTasks = function () {
  return new Promise(function (resolve, reject) {
    const gruntfile = fs.readFileSync(path.join(window.localStorage.getItem('current'), 'Gruntfile.js'))
    grunt.init(gruntfile)
    let tasks = JSON.parse(grunt.getJsonTasks())

    let taskList = []

    for (let task in tasks) {
      taskList.push(task)
    }

    return resolve(taskList)
  })
}

exports.runTask = function (task, cb) {
  // Stop task if running
  if (global.processes[task]) {
    global.processes[task].kill()
    return
  }

  let dir = window.localStorage.getItem('current')
  var command = spawn('grunt', [task], {cwd: dir})

  // Save
  global.processes[task] = command

  cb()

  // Remove when done
  command.on('close', function () {
    delete global.processes[task]
    cb()
  })
}
<commit_msg>Use callback instead of sync<commit_after>'use strict'
const grunt = require('gruntfile-api')
const fs = require('fs')
const path = require('path')
const spawn = require('child_process').spawn

global.processes = {}

exports.getTasks = function () {
  return new Promise(function (resolve, reject) {
    fs.readFile(path.join(window.localStorage.getItem('current'), 'Gruntfile.js'), function (err, gruntfile) {
      if (err) return resolve([])

      grunt.init(gruntfile)
      let tasks = JSON.parse(grunt.getJsonTasks())

      let taskList = []

      for (let task in tasks) {
        taskList.push(task)
      }

      return resolve(taskList)
    })
  })
}

exports.runTask = function (task, cb) {
  // Stop task if running
  if (global.processes[task]) {
    global.processes[task].kill()
    return
  }

  let dir = window.localStorage.getItem('current')
  var command = spawn('grunt', [task], {cwd: dir})

  // Save
  global.processes[task] = command

  cb()

  // Remove when done
  command.on('close', function () {
    delete global.processes[task]
    cb()
  })
}
<|endoftext|>


<commit_before>var AlexaAppServer = require('alexa-app-server');
var alexa = require('alexa-app');
var SpotifyWebApi = require('spotify-web-api-node');
var request = require('request');
var randomstring = require('randomstring');
var express = require('express');
var cookieParser = require('cookie-parser');
var querystring = require('querystring');

// var server = new AlexaAppServer({
//     httpsEnabled: false,
//     port: process.env.PORT || 443
// });

// server.start();

var express_app = express();

var app = new alexa.app('connect');
app.express({ expressApp: express_app });

var spotifyApi = new SpotifyWebApi({
    clientId: '8f8e09d45e574e07b0a040bd70c95fb6',
    clientSecret: process.env.client_secret,
    redirectUri: 'https://alexa-spotify-connect.herokuapp.com/callback'
});

app.intent('PlayIntent', {
    "utterances": [
        "play",
        "resume",
        "continue"
    ]
},
    function (req, res) {
        res.say('Playing');
    }
);

app.intent('PauseIntent', {
    "utterances": [
        "pause",
        "pause music"
    ]
},
    function (req, res) {
        res.say('Paused');
    }
);

express_app.use(express.static(__dirname));

express_app.get('/login', function (req, res) {
    var scopes = ['user-read-playback-state', 'user-modify-playback-state'];
    var state = randomstring.generate(16);
    res.cookie('spotify_auth_state', state);
    var authorizeURL = spotifyApi.createAuthorizeURL(scopes, state);
    res.redirect(authorizeURL);
});

express_app.get('/callback', function (req, res) {

    var code = req.query.code;
    var state = req.query.state;

    spotifyApi.authorizationCodeGrant(code)
        .then(function (data) {
            console.log('The token expires in ' + data.body['expires_in']);
            console.log('The access token is ' + data.body['access_token']);
            console.log('The refresh token is ' + data.body['refresh_token']);

            // Set the access token on the API object to use it in later calls
            spotifyApi.setAccessToken(data.body['access_token']);
            spotifyApi.setRefreshToken(data.body['refresh_token']);
            res.cookie('access_token', data.body['access_token']);
            res.redirect('/#' + querystring.stringify({ access_token: data.body['access_token'], refresh_token: data.body['refresh_token'] }));
        }, function (err) {
            console.log('Something went wrong!', err);
        });
});

express_app.get('/refresh_token', function (req, res) {
    spotifyApi.refreshAccessToken()
        .then(function (data) {
            console.log('The access token has been refreshed!');
            console.log('The access token is ' + data.body['access_token']);

            // Save the access token so that it's used in future calls
            spotifyApi.setAccessToken(data.body['access_token']);
            res.redirect('/#' + querystring.stringify({ access_token: data.body['access_token'] }));
        }, function (err) {
            console.log('Could not refresh access token', err);
        });
});

express_app.post('/playpause', function (req, res) {
    console.log("PLAYPAUSE");
    //var playing = request.get("https://api.spotify.com/v1/me/player", { "auth":{"bearer":spotifyApi.getAccessToken()}, json: true });
    if (playing) {
        request.put("https://api.spotify.com/v1/me/player/pause").auth(null, null, true, spotifyApi.getAccessToken())
    }
    else {
        request.put("https://api.spotify.com/v1/me/player/play").auth(null, null, true, spotifyApi.getAccessToken())
    }
});

express_app.post('/getdevices', function (req, res) {
    spotifyApi.getMyDevices()
        .then(function (data) {
            var devices = data.body.devices;
            for (var i = 0; i < devices.length; i++) {
                console.log(devices[i].id + ":" + devices[i].name + ":" + devices[i].volume_percent);
            }
        }, function (err) {
            console.error(err);
        });
});

var port = process.env.PORT || 8888;
console.log('Listening on ' + port);
express_app.listen(port);

module.exports = app;
<commit_msg>Test access token<commit_after>var AlexaAppServer = require('alexa-app-server');
var alexa = require('alexa-app');
var SpotifyWebApi = require('spotify-web-api-node');
var request = require('request');
var randomstring = require('randomstring');
var express = require('express');
var cookieParser = require('cookie-parser');
var querystring = require('querystring');

var express_app = express();

var app = new alexa.app('connect');
app.express({ expressApp: express_app });

var spotifyApi = new SpotifyWebApi({
    clientId: '8f8e09d45e574e07b0a040bd70c95fb6',
    clientSecret: process.env.client_secret,
    redirectUri: 'https://alexa-spotify-connect.herokuapp.com/callback'
});

app.intent('PlayIntent', {
    "utterances": [
        "play",
        "resume",
        "continue"
    ]
},
    function (req, res) {
        request.put("https://api.spotify.com/v1/me/player/pause").auth(null, null, true, req.sessionDetails.accessToken);
        res.say('Playing');
    }
);

app.intent('PauseIntent', {
    "utterances": [
        "pause"
    ]
},
    function (req, res) {
        res.say('Paused');
    }
);

express_app.use(express.static(__dirname));

express_app.get('/login', function (req, res) {
    var scopes = ['user-read-playback-state', 'user-modify-playback-state'];
    var state = randomstring.generate(16);
    res.cookie('spotify_auth_state', state);
    var authorizeURL = spotifyApi.createAuthorizeURL(scopes, state);
    res.redirect(authorizeURL);
});

express_app.get('/callback', function (req, res) {

    var code = req.query.code;
    var state = req.query.state;

    spotifyApi.authorizationCodeGrant(code)
        .then(function (data) {
            console.log('The token expires in ' + data.body['expires_in']);
            console.log('The access token is ' + data.body['access_token']);
            console.log('The refresh token is ' + data.body['refresh_token']);

            // Set the access token on the API object to use it in later calls
            spotifyApi.setAccessToken(data.body['access_token']);
            spotifyApi.setRefreshToken(data.body['refresh_token']);
            res.cookie('access_token', data.body['access_token']);
            res.redirect('/#' + querystring.stringify({ access_token: data.body['access_token'], refresh_token: data.body['refresh_token'] }));
        }, function (err) {
            console.log('Something went wrong!', err);
        });
});

express_app.get('/refresh_token', function (req, res) {
    spotifyApi.refreshAccessToken()
        .then(function (data) {
            console.log('The access token has been refreshed!');
            console.log('The access token is ' + data.body['access_token']);

            // Save the access token so that it's used in future calls
            spotifyApi.setAccessToken(data.body['access_token']);
            res.redirect('/#' + querystring.stringify({ access_token: data.body['access_token'] }));
        }, function (err) {
            console.log('Could not refresh access token', err);
        });
});

express_app.post('/playpause', function (req, res) {
    console.log("PLAYPAUSE");
    //var playing = request.get("https://api.spotify.com/v1/me/player", { "auth":{"bearer":spotifyApi.getAccessToken()}, json: true });
    if (playing) {
        request.put("https://api.spotify.com/v1/me/player/pause").auth(null, null, true, spotifyApi.getAccessToken())
    }
    else {
        request.put("https://api.spotify.com/v1/me/player/play").auth(null, null, true, spotifyApi.getAccessToken())
    }
});

express_app.post('/getdevices', function (req, res) {
    spotifyApi.getMyDevices()
        .then(function (data) {
            var devices = data.body.devices;
            for (var i = 0; i < devices.length; i++) {
                console.log(devices[i].id + ":" + devices[i].name + ":" + devices[i].volume_percent);
            }
        }, function (err) {
            console.error(err);
        });
});

var port = process.env.PORT || 8888;
console.log('Listening on ' + port);
express_app.listen(port);

module.exports = app;
<|endoftext|>


<commit_before>if (typeof console === 'undefined') {

  /**
   * @see http://getfirebug.com/console.html
   */
  window.console = {};

  if (document.body) {

    var firebug = document.createElement('script');
    firebug.setAttribute('src', 'http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js');
    document.body.appendChild(firebug);
    (function(){
      if (window.pi && window.firebug) {
        firebug.init();
      } else {
        setTimeout(arguments.callee);
      }
    })();

  } else {

    var post = window.opera && opera.postError || alert;

    /**
     * Limit of objects dimensions
     * console.dimensions_limit = 0
     * console.log([42]) ==> [?]
     * console.dimensions_limit = 1
     * console.log([42]) ==> [42]
     */
    console.dimensions_limit = 1;

    /**
     * console.log({x:2, y:8, z:[4,3]}) ==> '{ x: 2, y: 8, z: [4, 3] }'
     * @param Objects
     */
    console.log = console.info = console.warn = console.error = console.debug = console.dir = function log () {

      /**
       * source_of({x:2, y:8}) === "{'x':2, 'y':8}"
       * @param {Object} arg
       * @param {Number} limit dimension of objects
       * @return {String} string representation of input
       */
      var source_of = function source_of (arg, limit) {

        if (typeof limit == 'undefined') {
          var limit = console.dimensions_limit;
        }

        var result = '';

        // Is array?
        if (arg && typeof arg.length === 'number' && typeof arg.splice === 'function') {
          if (!limit) return '[?]';
          result += '[';
          var arr_list = [];
          for (var j = 0; j < arg.length; j++) {
            arr_list.push( source_of(arg[j], limit-1) );
          }
          result += arr_list.join(', ') +']';
        } else if (typeof arg == 'object') {
          if (!limit) return '{?}';
          result += '{ ';
          var arr_obj = [];
          for (var key in arg) {
            arr_obj.push( "'"+ key +"': "+ source_of(arg[key], limit-1) );
          }
          result += arr_obj.join(', ') +' }';
        } else if (typeof arg == 'string') {
          return "'"+ arg +"'";
        } else {
          return arg;
        }

        return result;
      };

      for (var i=0; i<arguments.length; i++) {
        post( source_of(arguments[i]) );
      }

    };

    /**
     * Simplified version of http://eriwen.com/javascript/js-stack-trace/
     */
    console.trace = function trace() {
      try {
        i.dont.exist++;
      } catch(e) {
        var stack = e.stack || e.stacktrace;
        stack = stack.split('\n').slice(2).join('\n');
        post(stack);
      }
    };

    /**
     * console.assert(false, "I'm gonna fail")
     * @param {Boolean} is_ok
     * @param {String} message optional
     */
    console.assert = function assert (is_ok, message) {
      if (!is_ok) post( 'ASSERT FAIL: '+ message );
    };

    /**
     * @param {String} name optional
     */
    console.group = console.groupCollapsed = function group (name) {
      post('\n-------------------- '+ name +' --------------------');
    };

    /**
     * Print 3 line breaks
     */
    console.groupEnd = function groupEnd () {
      post('\n\n\n');
    };

    /**
     * @param {String} title optional
     */
    console.count = function count (title) {
      var title = title || '';
      arguments.callee.counters = arguments.callee.counters || {};
      if (arguments.callee.counters[title]) {
        arguments.callee.counters[title]++;
      } else {
        arguments.callee.counters[title] = 1;
      }
      post(title +' '+ arguments.callee.counters[title]);
    };

    /**
     * @param {String} title optional
     */
    console.profile = function profile (title) {
      return 'Not implemented';
    };
    console.profileEnd = function profileEnd () {
      return 'Not implemented';
    };

    /**
     * @param {String} name
     */
    console.time = function time (name) {
      return 'Not implemented';
    };
    /**
     * @param {String} name
     */
    console.timeEnd = function timeEnd (name) {
      return 'Not implemented';
    };

  }
}<commit_msg>Firebug lite removed. Use Firebug lite without console.js http://wiki.github.com/NV/console.js/firebug-lite<commit_after>if (typeof console === 'undefined') {

  /**
   * @see http://getfirebug.com/console.html
   */
  window.console = {};

  var post = window.opera && opera.postError || alert;

  /**
   * Limit of objects dimensions
   * console.dimensions_limit = 0
   * console.log([42]) ==> [?]
   * console.dimensions_limit = 1
   * console.log([42]) ==> [42]
   */
  console.dimensions_limit = 1;

  /**
   * console.log({x:2, y:8, z:[4,3]}) ==> '{ x: 2, y: 8, z: [4, 3] }'
   * @param Objects
   */
  console.log = console.info = console.warn = console.error = console.debug = console.dir = function log () {

    /**
     * source_of({x:2, y:8}) === "{'x':2, 'y':8}"
     * @param {Object} arg
     * @param {Number} limit dimension of objects
     * @return {String} string representation of input
     */
    var source_of = function source_of (arg, limit) {

      if (typeof limit == 'undefined') {
        var limit = console.dimensions_limit;
      }

      var result = '';

      // Is array?
      if (arg && typeof arg.length === 'number' && typeof arg.splice === 'function') {
        if (!limit) return '[?]';
        result += '[';
        var arr_list = [];
        for (var j = 0; j < arg.length; j++) {
          arr_list.push( source_of(arg[j], limit-1) );
        }
        result += arr_list.join(', ') +']';
      } else if (typeof arg == 'object') {
        if (!limit) return '{?}';
        result += '{ ';
        var arr_obj = [];
        for (var key in arg) {
          arr_obj.push( "'"+ key +"': "+ source_of(arg[key], limit-1) );
        }
        result += arr_obj.join(', ') +' }';
      } else if (typeof arg == 'string') {
        return "'"+ arg +"'";
      } else {
        return arg;
      }

      return result;
    };

    for (var i=0; i<arguments.length; i++) {
      post( source_of(arguments[i]) );
    }

  };

  /**
   * Simplified version of http://eriwen.com/javascript/js-stack-trace/
   */
  console.trace = function trace() {
    try {
      i.dont.exist++;
    } catch(e) {
      var stack = e.stack || e.stacktrace;
      stack = stack.split('\n').slice(2).join('\n');
      post(stack);
    }
  };

  /**
   * console.assert(false, "I'm gonna fail")
   * @param {Boolean} is_ok
   * @param {String} message optional
   */
  console.assert = function assert (is_ok, message) {
    if (!is_ok) post( 'ASSERT FAIL: '+ message );
  };

  /**
   * @param {String} name optional
   */
  console.group = console.groupCollapsed = function group (name) {
    post('\n-------------------- '+ name +' --------------------');
  };

  /**
   * Print 3 line breaks
   */
  console.groupEnd = function groupEnd () {
    post('\n\n\n');
  };

  /**
   * @param {String} title optional
   */
  console.count = function count (title) {
    var title = title || '';
    arguments.callee.counters = arguments.callee.counters || {};
    if (arguments.callee.counters[title]) {
      arguments.callee.counters[title]++;
    } else {
      arguments.callee.counters[title] = 1;
    }
    post(title +' '+ arguments.callee.counters[title]);
  };

  /**
   * @param {String} title optional
   */
  console.profile = function profile (title) {
    return 'Not implemented';
  };
  console.profileEnd = function profileEnd () {
    return 'Not implemented';
  };

  /**
   * @param {String} name
   */
  console.time = function time (name) {
    return 'Not implemented';
  };
  /**
   * @param {String} name
   */
  console.timeEnd = function timeEnd (name) {
    return 'Not implemented';
  };

}<|endoftext|>


<commit_before>var Instance        = require("./Instance").Instance;
var Singleton       = require("./Singleton");
var OneAssociation  = require("./Associations/One");
var ManyAssociation = require("./Associations/Many");
var ChainFind       = require("./ChainFind");
var LazyLoad        = require("./LazyLoad");

exports.Model = Model;

function Model(opts) {
	opts = opts || {};
	opts.id = opts.id;

	var one_associations = [];
	var many_associations = [];
	var association_properties = [];
	var model_fields = null;

	var createInstance = function (data, inst_opts, cb) {
		if (!inst_opts) {
			inst_opts = {};
		}
		var instance = new Instance({
			id                     : opts.id,
			is_new                 : inst_opts.is_new || false,
			data                   : data,
			autoSave               : inst_opts.autoSave || false,
			extra                  : inst_opts.extra,
			extra_info             : inst_opts.extra_info,
			model                  : model,
			driver                 : opts.driver,
			table                  : opts.table,
			properties             : opts.properties,
			hooks                  : opts.hooks,
			methods                : opts.methods,
			validations            : opts.validations,
			association_properties : association_properties
		});
		if (model_fields !== null) {
			LazyLoad.extend(instance, model, opts.properties);
		}
		OneAssociation.extend(model, instance, opts.driver, one_associations, {
			autoFetch      : inst_opts.autoFetch || false,
			autoFetchLimit : inst_opts.autoFetchLimit,
			cascadeRemove  : inst_opts.cascadeRemove
		}, function () {
			ManyAssociation.extend(model, instance, opts.driver, many_associations, {
				autoFetch      : inst_opts.autoFetch || false,
				autoFetchLimit : inst_opts.autoFetchLimit,
				cascadeRemove  : inst_opts.cascadeRemove
			}, function () {
				if (typeof cb == "function") {
					return cb(instance);
				}
			});
		});
		return instance;
	};

	var model = function (data) {
		var instance;
		if (typeof data == "number") {
			var data2 = {};
			data2[opts.id] = data;

			return createInstance(data2);
		} else if (typeof data == "undefined") {
			data = {};
		}

		return createInstance(data, {
			is_new        : !data.hasOwnProperty(opts.id),
			autoSave      : opts.autoSave,
			cascadeRemove : opts.cascadeRemove
		});
	};

	for (var k in opts.properties) {
		if (opts.properties[k].lazyload === true) {
			model_fields = [ opts.id ];
			for (k in opts.properties) {
				if (opts.properties[k].lazyload !== true) {
					model_fields.push(k);
				}
			}
			break;
		}
	}

	OneAssociation.prepare(model, one_associations, association_properties);
	ManyAssociation.prepare(model, many_associations);

	model.settings = opts.settings;

	model.drop = function (cb) {
		if (typeof opts.driver.drop == "function") {
			opts.driver.drop({
				id                : opts.id,
				table             : opts.table,
				properties        : opts.properties,
				one_associations  : one_associations,
				many_associations : many_associations
			}, cb);

			return this;
		}

		return cb(new Error("Driver does not support Model.drop()"));
	};

	model.sync = function (cb) {
		if (typeof opts.driver.sync == "function") {
			opts.driver.sync({
				id                : opts.id,
				table             : opts.table,
				properties        : opts.properties,
				one_associations  : one_associations,
				many_associations : many_associations
			}, cb);

			return this;
		}

		return cb(new Error("Driver does not support Model.sync()"));
	};

	model.get = function (id, options, cb) {
		var conditions = {};
		conditions[opts.id] = id;

		if (typeof options == "function") {
			cb = options;
			options = {};
		} else {
			options = options || {};
		}

		if (typeof cb != "function") {
			throw new Error("Missing Model.get() callback");
		}

		if (!options.hasOwnProperty("cache")) {
			options.cache = opts.cache;
		}

		opts.driver.find(model_fields, opts.table, conditions, { limit: 1 }, function (err, data) {
			if (err) {
				return cb(err);
			}
			if (data.length === 0) {
				return cb(new Error("Not found"));
			}
			Singleton.get(opts.table + "/" + id, { cache: options.cache }, function (cb) {
				return createInstance(data[0], {
					autoSave       : opts.autoSave,
					autoFetch      : (options.autoFetchLimit === 0 ? false : opts.autoFetch),
					autoFetchLimit : options.autoFetchLimit || opts.autoFetchLimit,
					cascadeRemove  : options.cascadeRemove || opts.cascadeRemove
				}, cb);
			}, function (instance) {
				return cb(null, instance);
			});
		});

		return this;
	};

	model.find = function () {
		var options    = {};
		var conditions = null;
		var cb         = null;
		var limit      = null;
		var order      = null;
		var merge      = null;

		for (var i = 0; i < arguments.length; i++) {
			switch (typeof arguments[i]) {
				case "number":
					limit = arguments[i];
					break;
				case "object":
					if (Array.isArray(arguments[i]) && arguments[i].length) {
						order = arguments[i];
					} else {
						if (conditions === null) {
							conditions = arguments[i];
						} else {
							options = arguments[i];
							if (options.hasOwnProperty("__merge")) {
								merge = options.__merge;
								delete options.__merge;
							}
						}
					}
					break;
				case "function":
					cb = arguments[i];
					break;
				case "string":
					order = [ arguments[i] ];
					break;
			}
		}

		if (!options.hasOwnProperty("cache")) {
			options.cache = opts.cache;
		}

		var chain = new ChainFind({
			only       : options.only || model_fields,
			id         : opts.id,
			table      : opts.table,
			driver     : opts.driver,
			conditions : conditions,
			limit      : limit,
			order      : order,
			merge      : merge,
			offset     : options.offset,
			newInstance: function (data, cb) {
				Singleton.get(opts.table + (merge ? "+" + merge.from.table : "") + "/" + data[opts.id],
				              { cache: options.cache },
				function (cb) {
					return createInstance(data, {
						autoSave       : opts.autoSave,
						autoFetch      : (options.autoFetchLimit === 0 ? false : opts.autoFetch),
						autoFetchLimit : options.autoFetchLimit || opts.autoFetchLimit,
						cascadeRemove  : options.cascadeRemove || opts.cascadeRemove,
						extra          : options.extra,
						extra_info     : options.extra_info
					}, cb);
				}, function (instance) {
					return cb(null, instance);
				});
			}
		});
		if (cb === null) {
			return chain;
		}

		chain.run(cb);

		return this;
	};

	model.count = function () {
		var conditions = null;
		var cb         = null;

		for (var i = 0; i < arguments.length; i++) {
			switch (typeof arguments[i]) {
				case "object":
					conditions = arguments[i];
					break;
				case "function":
					cb = arguments[i];
					break;
			}
		}

		if (typeof cb != "function") {
			throw new Error("Missing Model.count() callback");
		}

		opts.driver.count(opts.table, conditions, function (err, data) {
			if (err || data.length === 0) {
				return cb(err);
			}
			return cb(null, data[0].c);
		});
		return this;
	};

	model.exists = function (id, cb) {
		if (typeof cb != "function") {
			throw new Error("Missing Model.exists() callback");
		}

		var conditions = {};
		conditions[opts.id] = id;

		opts.driver.count(opts.table, conditions, function (err, data) {
			if (err || data.length === 0) {
				return cb(err);
			}
			return cb(null, data[0].c > 0);
		});
		return this;
	};

	model.create = function () {
		var Instances = [];
		var options = {};
		var cb = null, idx = 0;
		var createNext = function () {
			if (idx >= Instances.length) {
				return cb(null, Instances);
			}

			Instances[idx] = createInstance(Instances[idx], {
				is_new    : true,
				autoSave  : opts.autoSave,
				autoFetch : false
			});
			Instances[idx].save(function (err) {
				if (err) {
					err.index = idx;
					err.instance = Instances[idx];

					return cb(err);
				}

				idx += 1;
				createNext();
			});
		};

		for (var i = 0; i < arguments.length; i++) {
			if (Array.isArray(arguments[i])) {
				Instances = Instances.concat(arguments[i]);
				continue;
			}

			switch (typeof arguments[i]) {
				case "object":
					options = arguments[i];
					break;
				case "function":
					cb = arguments[i];
					break;
			}
		}

		createNext();

		return this;
	};

	model.clear = function (cb) {
		opts.driver.clear(opts.table, function (err) {
			if (typeof cb == "function") cb(err);
		});

		return this;
	};

	Object.defineProperty(model, "table", {
		value: opts.table,
		enumerable: false
	});
	Object.defineProperty(model, "id", {
		value: opts.id,
		enumerable: false
	});

	return model;
}
<commit_msg>Changes previous fix to behave like before<commit_after>var Instance        = require("./Instance").Instance;
var Singleton       = require("./Singleton");
var OneAssociation  = require("./Associations/One");
var ManyAssociation = require("./Associations/Many");
var ChainFind       = require("./ChainFind");
var LazyLoad        = require("./LazyLoad");

exports.Model = Model;

function Model(opts) {
	opts = opts || {};
	opts.id = opts.id;

	var one_associations = [];
	var many_associations = [];
	var association_properties = [];
	var model_fields = null;

	var createInstance = function (data, inst_opts, cb) {
		if (!inst_opts) {
			inst_opts = {};
		}
		var instance = new Instance({
			id                     : opts.id,
			is_new                 : inst_opts.is_new || false,
			data                   : data,
			autoSave               : inst_opts.autoSave || false,
			extra                  : inst_opts.extra,
			extra_info             : inst_opts.extra_info,
			model                  : model,
			driver                 : opts.driver,
			table                  : opts.table,
			properties             : opts.properties,
			hooks                  : opts.hooks,
			methods                : opts.methods,
			validations            : opts.validations,
			association_properties : association_properties
		});
		if (model_fields !== null) {
			LazyLoad.extend(instance, model, opts.properties);
		}
		OneAssociation.extend(model, instance, opts.driver, one_associations, {
			autoFetch      : inst_opts.autoFetch || false,
			autoFetchLimit : inst_opts.autoFetchLimit,
			cascadeRemove  : inst_opts.cascadeRemove
		}, function () {
			ManyAssociation.extend(model, instance, opts.driver, many_associations, {
				autoFetch      : inst_opts.autoFetch || false,
				autoFetchLimit : inst_opts.autoFetchLimit,
				cascadeRemove  : inst_opts.cascadeRemove
			}, function () {
				if (typeof cb == "function") {
					return cb(instance);
				}
			});
		});
		return instance;
	};

	var model = function (data) {
		var instance;
		if (typeof data == "number") {
			var data2 = {};
			data2[opts.id] = data;

			return createInstance(data2);
		} else if (typeof data == "undefined") {
			data = {};
		}

		return createInstance(data, {
			is_new        : !data.hasOwnProperty(opts.id),
			autoSave      : opts.autoSave,
			cascadeRemove : opts.cascadeRemove
		});
	};

	for (var k in opts.properties) {
		if (opts.properties[k].lazyload === true) {
			model_fields = [ opts.id ];
			for (k in opts.properties) {
				if (opts.properties[k].lazyload !== true) {
					model_fields.push(k);
				}
			}
			break;
		}
	}

	OneAssociation.prepare(model, one_associations, association_properties);
	ManyAssociation.prepare(model, many_associations);

	model.settings = opts.settings;

	model.drop = function (cb) {
		if (typeof opts.driver.drop == "function") {
			opts.driver.drop({
				id                : opts.id,
				table             : opts.table,
				properties        : opts.properties,
				one_associations  : one_associations,
				many_associations : many_associations
			}, cb);

			return this;
		}

		return cb(new Error("Driver does not support Model.drop()"));
	};

	model.sync = function (cb) {
		if (typeof opts.driver.sync == "function") {
			opts.driver.sync({
				id                : opts.id,
				table             : opts.table,
				properties        : opts.properties,
				one_associations  : one_associations,
				many_associations : many_associations
			}, cb);

			return this;
		}

		return cb(new Error("Driver does not support Model.sync()"));
	};

	model.get = function (id, options, cb) {
		var conditions = {};
		conditions[opts.id] = id;

		if (typeof options == "function") {
			cb = options;
			options = {};
		} else {
			options = options || {};
		}

		if (typeof cb != "function") {
			throw new Error("Missing Model.get() callback");
		}

		if (!options.hasOwnProperty("cache")) {
			options.cache = opts.cache;
		}

		opts.driver.find(model_fields, opts.table, conditions, { limit: 1 }, function (err, data) {
			if (err) {
				return cb(err);
			}
			if (data.length === 0) {
				return cb(new Error("Not found"));
			}
			Singleton.get(opts.table + "/" + id, { cache: options.cache }, function (cb) {
				return createInstance(data[0], {
					autoSave       : opts.autoSave,
					autoFetch      : (options.autoFetchLimit === 0 ? false : opts.autoFetch),
					autoFetchLimit : options.autoFetchLimit || opts.autoFetchLimit,
					cascadeRemove  : options.cascadeRemove || opts.cascadeRemove
				}, cb);
			}, function (instance) {
				return cb(null, instance);
			});
		});

		return this;
	};

	model.find = function () {
		var options    = {};
		var conditions = null;
		var cb         = null;
		var limit      = null;
		var order      = null;
		var merge      = null;

		for (var i = 0; i < arguments.length; i++) {
			switch (typeof arguments[i]) {
				case "number":
					limit = arguments[i];
					break;
				case "object":
					if (Array.isArray(arguments[i])) {
						if (arguments[i].length > 0) {
							order = arguments[i];
						}
					} else {
						if (conditions === null) {
							conditions = arguments[i];
						} else {
							options = arguments[i];
							if (options.hasOwnProperty("__merge")) {
								merge = options.__merge;
								delete options.__merge;
							}
						}
					}
					break;
				case "function":
					cb = arguments[i];
					break;
				case "string":
					order = [ arguments[i] ];
					break;
			}
		}

		if (!options.hasOwnProperty("cache")) {
			options.cache = opts.cache;
		}

		var chain = new ChainFind({
			only       : options.only || model_fields,
			id         : opts.id,
			table      : opts.table,
			driver     : opts.driver,
			conditions : conditions,
			limit      : limit,
			order      : order,
			merge      : merge,
			offset     : options.offset,
			newInstance: function (data, cb) {
				Singleton.get(opts.table + (merge ? "+" + merge.from.table : "") + "/" + data[opts.id],
				              { cache: options.cache },
				function (cb) {
					return createInstance(data, {
						autoSave       : opts.autoSave,
						autoFetch      : (options.autoFetchLimit === 0 ? false : opts.autoFetch),
						autoFetchLimit : options.autoFetchLimit || opts.autoFetchLimit,
						cascadeRemove  : options.cascadeRemove || opts.cascadeRemove,
						extra          : options.extra,
						extra_info     : options.extra_info
					}, cb);
				}, function (instance) {
					return cb(null, instance);
				});
			}
		});
		if (cb === null) {
			return chain;
		}

		chain.run(cb);

		return this;
	};

	model.count = function () {
		var conditions = null;
		var cb         = null;

		for (var i = 0; i < arguments.length; i++) {
			switch (typeof arguments[i]) {
				case "object":
					conditions = arguments[i];
					break;
				case "function":
					cb = arguments[i];
					break;
			}
		}

		if (typeof cb != "function") {
			throw new Error("Missing Model.count() callback");
		}

		opts.driver.count(opts.table, conditions, function (err, data) {
			if (err || data.length === 0) {
				return cb(err);
			}
			return cb(null, data[0].c);
		});
		return this;
	};

	model.exists = function (id, cb) {
		if (typeof cb != "function") {
			throw new Error("Missing Model.exists() callback");
		}

		var conditions = {};
		conditions[opts.id] = id;

		opts.driver.count(opts.table, conditions, function (err, data) {
			if (err || data.length === 0) {
				return cb(err);
			}
			return cb(null, data[0].c > 0);
		});
		return this;
	};

	model.create = function () {
		var Instances = [];
		var options = {};
		var cb = null, idx = 0;
		var createNext = function () {
			if (idx >= Instances.length) {
				return cb(null, Instances);
			}

			Instances[idx] = createInstance(Instances[idx], {
				is_new    : true,
				autoSave  : opts.autoSave,
				autoFetch : false
			});
			Instances[idx].save(function (err) {
				if (err) {
					err.index = idx;
					err.instance = Instances[idx];

					return cb(err);
				}

				idx += 1;
				createNext();
			});
		};

		for (var i = 0; i < arguments.length; i++) {
			if (Array.isArray(arguments[i])) {
				Instances = Instances.concat(arguments[i]);
				continue;
			}

			switch (typeof arguments[i]) {
				case "object":
					options = arguments[i];
					break;
				case "function":
					cb = arguments[i];
					break;
			}
		}

		createNext();

		return this;
	};

	model.clear = function (cb) {
		opts.driver.clear(opts.table, function (err) {
			if (typeof cb == "function") cb(err);
		});

		return this;
	};

	Object.defineProperty(model, "table", {
		value: opts.table,
		enumerable: false
	});
	Object.defineProperty(model, "id", {
		value: opts.id,
		enumerable: false
	});

	return model;
}
<|endoftext|>


<commit_before>const querystring = require('querystring');
const AccessToken = require('./AccessToken');
const http = require('./http');

class OAuth {
  /**
   * 根据appid和appsecret创建OAuth接口
   *
   * @param {String} appid 在公众平台上申请得到的appid
   * @param {String} appsecret 在公众平台上申请得到的app secret
   * @param {Function} getToken 用于获取token的方法 异步操作需返回Promise
   * @param {Function} saveToken 用于保存token的方法 异步操作需返回Promise
   */
  constructor(appid, appsecret, getToken, saveToken) {
    this.appid = appid;
    this.appsecret = appsecret;
    // token的获取和存储
    this.store = {};
    this.getToken = getToken || (openid => this.store[openid]);
    if (!saveToken && process.env.NODE_ENV === 'production') {
      console.warn('Please dont save oauth token into memory under production');
    }
    this.saveToken = saveToken || ((openid, token) => {
      this.store[openid] = token;
    });
    // 默认请求参数
    this.defaults = {};
  }

  /**
   * 用于设置node-fetch的默认options
   *
   * @param {Object} options 默认选项
   */
  setOptions(options) {
    this.defaults = options;
  }

  /**
   * 授权请求
   *
   * 返回结果参见：http://mp.weixin.qq.com/wiki/index.php?title=返回码说明
   * @param {String} url 路径
   * @param {Object} opts urllib选项
   * @return {Promise} 对返回结果的一层封装, 如果遇见微信返回的错误, 将返回一个错误
   * @api private
   */
  async request(url, params) {
    try {
      const data = await http.get(`${url}?${querystring.stringify(params)}`, this.defaults);
      if (data.errcode) {
        const error = new Error(data.errmsg);
        error.code = data.errcode;
        throw error;
      }
      return data;
    } catch (e) {
      if (e.name !== 'WeChatAPIError') {
        e.name = `WeChatAPI${e.name}`;
      }
      throw e;
    }
  }

  /**
   * 获取授权页面的URL地址
   *
   * @param {String} redirect 授权后要跳转的地址
   * @param {String} state 开发者可提供的数据
   * @param {String} scope 作用范围, 值为snsapi_userinfo和snsapi_base, 后者静默授权
   * @return {String}
   */
  getAuthorizeURL(redirect, state, scope) {
    const url = 'https://open.weixin.qq.com/connect/oauth2/authorize';
    const info = {
      appid: this.appid,
      redirect_uri: redirect,
      response_type: 'code',
      scope: scope || 'snsapi_base',
      state: state || '',
    };

    return `${url}?${querystring.stringify(info)}#wechat_redirect`;
  }

  /**
   * 获取授权页面的URL地址
   *
   * @param {String} redirect 授权后要跳转的地址
   * @param {String} state 开发者可提供的数据
   * @param {String} scope 作用范围, 值为snsapi_login
   * @return {String}
   */
  getAuthorizeURLForWebsite(redirect, state, scope) {
    const url = 'https://open.weixin.qq.com/connect/qrconnect';
    const info = {
      appid: this.appid,
      redirect_uri: redirect,
      response_type: 'code',
      scope: scope || 'snsapi_login',
      state: state || '',
    };

    return `${url}?${querystring.stringify(info)}#wechat_redirect`;
  }

  /**
   * 请求／刷新token, 并保存, 更新过期时间
   *
   * @param {Object} url
   * @param {Object} params
   * @return {Promise} AccessToken实例
   * @api private
   */
  async requestAndProcessAccessToken(url, params) {
    const createAt = Date.now();
    const data = await this.request(url, params);
    data.create_at = createAt;
    await this.saveToken(data.openid, data);
    return new AccessToken(data);
  }

  /**
   * 根据授权获取到的code, 换取access token和openid
   *
   * 获取openid之后, 可以调用`wechat.API`来获取更多信息
   *
   * {
   *   "access_token": "ACCESS_TOKEN",
   *   "expires_in": 7200,
   *   "refresh_token": "REFRESH_TOKEN",
   *   "openid": "OPENID",
   *   "scope": "SCOPE"
   * }
   * @param {String} code 授权获取到的code
   * @return {Promise} AccessToken实例
   */
  async getAccessToken(code) {
    const url = 'https://api.weixin.qq.com/sns/oauth2/access_token';
    const params = {
      code,
      appid: this.appid,
      secret: this.appsecret,
      grant_type: 'authorization_code',
    };

    return this.requestAndProcessAccessToken(url, params);
  }

  /**
   * 根据refresh token, 刷新access token, 调用getAccessToken后才有效
   *
   * 结果同getAccessToken
   *
   * @param {String} refreshToken
   * @return {Promise} 新的token
   */
  async refreshAccessToken(refreshToken) {
    const url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token';
    const params = {
      appid: this.appid,
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
    };

    return this.requestAndProcessAccessToken(url, params);
  }

  /**
   * @param {Object} options
   * @param {String} accessToken
   * @return {Promise}
   * @api private
   */
  getUserByToken(options, accessToken) {
    const url = 'https://api.weixin.qq.com/sns/userinfo';
    const { openid, lang = 'en' } = options;
    const params = {
      access_token: accessToken,
      openid,
      lang,
    };
    return this.request(url, params);
  }

  /**
   * 根据openid, 获取用户信息
   *
   * 当access token无效时, 自动通过refresh token获取新的access token, 然后再获取用户信息
   * {
   *  "openid": "OPENID",
   *  "nickname": "NICKNAME",
   *  "sex": "1",
   *  "province": "PROVINCE"
   *  "city": "CITY",
   *  "country": "COUNTRY",
   *  "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
   *  "privilege": [
   *    "PRIVILEGE1"
   *    "PRIVILEGE2"
   *  ]
   * }
   * @param {String} openid
   * @param {String} lang
   * @return {Promise} 用户信息|获取用户信息出现异常时的异常对象
   */
  async getUser(openid, lang) {
    const tokenData = await this.getToken(openid);
    // 没有token数据
    if (!tokenData) {
      const error = new Error(`No token for ${openid}, please authorize first.`);
      error.name = 'NoOAuthTokenError';
      throw error;
    }

    let token = new AccessToken(tokenData);
    if (!token.isValid()) {
      token = await this.refreshAccessToken(token.data.refresh_token);
    }
    const user = await this.getUserByToken(openid, token.data.access_token, lang);
    return user;
  }

  /**
   * 根据code, 获取用户信息
   *
   * 结果同getUser
   *
   * @param {String} code 授权获取到的code
   * @param {String} lang 语言
   * @return {Promise} 用户信息
   */
  async getUserByCode(code, lang) {
    const tokenData = await this.getAccessToken(code);
    const user = await this.getUser(tokenData.data.openid, lang);
    return user;
  }

  /**
   * 检验授权凭证（access_token）是否有效
   *
   * @param {String} openid 传入openid
   * @param {String} accessToken 待校验的access token
   * @param {Promise}
   */
  async verifyToken(openid, accessToken) {
    const url = 'https://api.weixin.qq.com/sns/auth';
    const params = {
      access_token: accessToken,
      openid,
    };

    await this.request(url, params);
    return true;
  }
}

module.exports = OAuth;
<commit_msg>fix bug<commit_after>const querystring = require('querystring');
const AccessToken = require('./AccessToken');
const http = require('./http');

class OAuth {
  /**
   * 根据appid和appsecret创建OAuth接口
   *
   * @param {String} appid 在公众平台上申请得到的appid
   * @param {String} appsecret 在公众平台上申请得到的app secret
   * @param {Function} getToken 用于获取token的方法 异步操作需返回Promise
   * @param {Function} saveToken 用于保存token的方法 异步操作需返回Promise
   */
  constructor(appid, appsecret, getToken, saveToken) {
    this.appid = appid;
    this.appsecret = appsecret;
    // token的获取和存储
    this.store = {};
    this.getToken = getToken || (openid => this.store[openid]);
    if (!saveToken && process.env.NODE_ENV === 'production') {
      console.warn('Please dont save oauth token into memory under production');
    }
    this.saveToken = saveToken || ((openid, token) => {
      this.store[openid] = token;
    });
    // 默认请求参数
    this.defaults = {};
  }

  /**
   * 用于设置node-fetch的默认options
   *
   * @param {Object} options 默认选项
   */
  setOptions(options) {
    this.defaults = options;
  }

  /**
   * 授权请求
   *
   * 返回结果参见：http://mp.weixin.qq.com/wiki/index.php?title=返回码说明
   * @param {String} url 路径
   * @param {Object} opts urllib选项
   * @return {Promise} 对返回结果的一层封装, 如果遇见微信返回的错误, 将返回一个错误
   * @api private
   */
  async request(url, params) {
    try {
      const data = await http.get(`${url}?${querystring.stringify(params)}`, this.defaults);
      if (data.errcode) {
        const error = new Error(data.errmsg);
        error.code = data.errcode;
        throw error;
      }
      return data;
    } catch (e) {
      if (e.name !== 'WeChatAPIError') {
        e.name = `WeChatAPI${e.name}`;
      }
      throw e;
    }
  }

  /**
   * 获取授权页面的URL地址
   *
   * @param {String} redirect 授权后要跳转的地址
   * @param {String} state 开发者可提供的数据
   * @param {String} scope 作用范围, 值为snsapi_userinfo和snsapi_base, 后者静默授权
   * @return {String}
   */
  getAuthorizeURL(redirect, state, scope) {
    const url = 'https://open.weixin.qq.com/connect/oauth2/authorize';
    const info = {
      appid: this.appid,
      redirect_uri: redirect,
      response_type: 'code',
      scope: scope || 'snsapi_base',
      state: state || '',
    };

    return `${url}?${querystring.stringify(info)}#wechat_redirect`;
  }

  /**
   * 获取授权页面的URL地址
   *
   * @param {String} redirect 授权后要跳转的地址
   * @param {String} state 开发者可提供的数据
   * @param {String} scope 作用范围, 值为snsapi_login
   * @return {String}
   */
  getAuthorizeURLForWebsite(redirect, state, scope) {
    const url = 'https://open.weixin.qq.com/connect/qrconnect';
    const info = {
      appid: this.appid,
      redirect_uri: redirect,
      response_type: 'code',
      scope: scope || 'snsapi_login',
      state: state || '',
    };

    return `${url}?${querystring.stringify(info)}#wechat_redirect`;
  }

  /**
   * 请求／刷新token, 并保存, 更新过期时间
   *
   * @param {Object} url
   * @param {Object} params
   * @return {Promise} AccessToken实例
   * @api private
   */
  async requestAndProcessAccessToken(url, params) {
    const createAt = Date.now();
    const data = await this.request(url, params);
    data.create_at = createAt;
    await this.saveToken(data.openid, data);
    return new AccessToken(data);
  }

  /**
   * 根据授权获取到的code, 换取access token和openid
   *
   * 获取openid之后, 可以调用`wechat.API`来获取更多信息
   *
   * {
   *   "access_token": "ACCESS_TOKEN",
   *   "expires_in": 7200,
   *   "refresh_token": "REFRESH_TOKEN",
   *   "openid": "OPENID",
   *   "scope": "SCOPE"
   * }
   * @param {String} code 授权获取到的code
   * @return {Promise} AccessToken实例
   */
  async getAccessToken(code) {
    const url = 'https://api.weixin.qq.com/sns/oauth2/access_token';
    const params = {
      code,
      appid: this.appid,
      secret: this.appsecret,
      grant_type: 'authorization_code',
    };

    return this.requestAndProcessAccessToken(url, params);
  }

  /**
   * 根据refresh token, 刷新access token, 调用getAccessToken后才有效
   *
   * 结果同getAccessToken
   *
   * @param {String} refreshToken
   * @return {Promise} 新的token
   */
  async refreshAccessToken(refreshToken) {
    const url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token';
    const params = {
      appid: this.appid,
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
    };

    return this.requestAndProcessAccessToken(url, params);
  }

  /**
   * @param {Object} options
   * @param {String} accessToken
   * @return {Promise}
   * @api private
   */
  getUserByToken(openid, accessToken, lang = 'en') {
    const url = 'https://api.weixin.qq.com/sns/userinfo';
    const params = {
      access_token: accessToken,
      openid,
      lang,
    };
    return this.request(url, params);
  }

  /**
   * 根据openid, 获取用户信息
   *
   * 当access token无效时, 自动通过refresh token获取新的access token, 然后再获取用户信息
   * {
   *  "openid": "OPENID",
   *  "nickname": "NICKNAME",
   *  "sex": "1",
   *  "province": "PROVINCE"
   *  "city": "CITY",
   *  "country": "COUNTRY",
   *  "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
   *  "privilege": [
   *    "PRIVILEGE1"
   *    "PRIVILEGE2"
   *  ]
   * }
   * @param {String} openid
   * @param {String} lang
   * @return {Promise} 用户信息|获取用户信息出现异常时的异常对象
   */
  async getUser(openid, lang) {
    const tokenData = await this.getToken(openid);
    // 没有token数据
    if (!tokenData) {
      const error = new Error(`No token for ${openid}, please authorize first.`);
      error.name = 'NoOAuthTokenError';
      throw error;
    }

    let token = new AccessToken(tokenData);
    if (!token.isValid()) {
      token = await this.refreshAccessToken(token.data.refresh_token);
    }
    const user = await this.getUserByToken(openid, token.data.access_token, lang);
    return user;
  }

  /**
   * 根据code, 获取用户信息
   *
   * 结果同getUser
   *
   * @param {String} code 授权获取到的code
   * @param {String} lang 语言
   * @return {Promise} 用户信息
   */
  async getUserByCode(code, lang) {
    const tokenData = await this.getAccessToken(code);
    const user = await this.getUser(tokenData.data.openid, lang);
    return user;
  }

  /**
   * 检验授权凭证（access_token）是否有效
   *
   * @param {String} openid 传入openid
   * @param {String} accessToken 待校验的access token
   * @param {Promise}
   */
  async verifyToken(openid, accessToken) {
    const url = 'https://api.weixin.qq.com/sns/auth';
    const params = {
      access_token: accessToken,
      openid,
    };

    await this.request(url, params);
    return true;
  }
}

module.exports = OAuth;
<|endoftext|>


<commit_before>// script that allows the extension to interact with web pages
// ensure script is loaded
console.log("tweet it loaded");

function removeAnchor() {
	var found = false;
	do {
		var existingAnchor = document.getElementById('tweet-anchor');
		if (existingAnchor) {
			existingAnchor.remove();
			found = true;
		}
		else {
			found = false;
		}
	} while (found);
	return false;
}

function selected(ev) {
	console.log(ev.currentTarget)
	var highlighted = window.getSelection();
	var highlightedText = highlighted.toString();
	var currentPage = window.location.href;
	removeAnchor();

	if (highlightedText.length <= 0) {
		return false;
	}
	else {
		var range = window.getSelection().getRangeAt(0);
		var tweetAnchor = document.createElement('span');
		tweetAnchor.setAttribute('id', 'tweet-anchor');
		tweetAnchor.addEventListener('click', tweetIt);
		range.insertNode(tweetAnchor);
		var what = range.getBoundingClientRect();
		var left = what.left, bottom = what.bottom;
		console.log('quote:', highlightedText)
		console.log('page:', currentPage)
		chrome.storage.local.set({'quote': highlightedText, 'url': currentPage}, function(){
			console.log('set quote and url')
		});
	}
	return false;
}

// function to handle creating the Twitter web intent
// this funciton might actually be best done by a seperate pop-up
function tweetIt(ev) {
	console.log('tweettarget', ev.currentTarget);
	console.log('pressed')
	var url = 'https://twitter.com/intent/tweet';

	// Add selected text
	chrome.storage.local.get(['quote', 'url'],  function(result) {
		var quoteText = encodeURIComponent(result.quote);
		console.log('quoteText', quoteText)
		var fullURI = url + '?text=' + quoteText + '&url=' + encodeURIComponent(result.url);
		window.open(fullURI)
	});

	// remove the previous span
	removeAnchor();

	ev.stopPropagation();
	console.log(ev.bubbles);
}

document.body.addEventListener('click' , selected);

<commit_msg>remove console.logs<commit_after>// script that allows the extension to interact with web pages
function removeAnchor() {
	var found = false;
	do {
		var existingAnchor = document.getElementById('tweet-anchor');
		if (existingAnchor) {
			existingAnchor.remove();
			found = true;
		}
		else {
			found = false;
		}
	} while (found);
	return false;
}

function selected(ev) {
	var highlighted = window.getSelection();
	var highlightedText = highlighted.toString();
	var currentPage = window.location.href;
	removeAnchor();

	if (highlightedText.length <= 0) {
		return false;
	}
	else {
		var range = window.getSelection().getRangeAt(0);
		var tweetAnchor = document.createElement('span');
		tweetAnchor.setAttribute('id', 'tweet-anchor');
		tweetAnchor.addEventListener('click', tweetIt);
		range.insertNode(tweetAnchor);
		var what = range.getBoundingClientRect();
		var left = what.left, bottom = what.bottom;
		chrome.storage.local.set({'quote': highlightedText, 'url': currentPage});
	}
	return false;
}

// function to handle creating the Twitter web intent
// this funciton might actually be best done by a seperate pop-up
function tweetIt(ev) {
	var url = 'https://twitter.com/intent/tweet';

	// Add selected text
	chrome.storage.local.get(['quote', 'url'],  function(result) {
		var quoteText = encodeURIComponent(result.quote);
		var fullURI = url + '?text=' + quoteText + '&url=' + encodeURIComponent(result.url);
		window.open(fullURI)
	});

	// remove the previous span
	removeAnchor();

	ev.stopPropagation();
}

document.body.addEventListener('click' , selected);

<|endoftext|>


<commit_before>
findAndReplaceDOMText(document.body, { find: "Venezuela",    replace: 'Chiquitistán'});
findAndReplaceDOMText(document.body, { find: "venezolano",    replace: 'chiquitistaní'});
findAndReplaceDOMText(document.body, { find: "venezolana",    replace: 'chiquitistanita'});
<commit_msg>Add more replacements<commit_after>
replacements = [
    {'find': 'Venezuela',        'replace': 'Chiquitistán'},
    {'find': 'VENEZUELA',        'replace': 'CHIQUITISTÁN'},
    {'find': 'venezuela',        'replace': 'chiquitistán'},

    {'find': 'venezolanos',      'replace': 'chiquitistanies'},
    {'find': 'VENEZOLANOS',      'replace': 'CHIQUITISTANIES'},

    {'find': 'venezolano',       'replace': 'chiquitistaní'},
    {'find': 'VENEZOLANO',       'replace': 'CHIQUITISTANÍ'},

    {'find': 'venezolanas',      'replace': 'chiquitistanitas'},
    {'find': 'VENEZOLANAS',      'replace': 'CHIQUITISTANITAS'},

    {'find': 'venezolana',       'replace': 'chiquitistanita'},
    {'find': 'VENEZOLANA',       'replace': 'CHIQUITISTANITA'},
];

replacements.forEach(function(elem, idx) {
    findAndReplaceDOMText(document.body, {'find': elem.find, 'replace': elem.replace});
});
<|endoftext|>


<commit_before>var currentContent;
function loadContent(page) {
	if (page !== currentContent) {
		$("#content").hide("fade", "fast", function() {
			$("#content").load("html/" + page + ".html", function() {
				$("#content").show("fade", "fast");
			});
		});
	}
}
$(document).ready(function() {
	$("a.load").click(function(event) {
		loadContent(this.href.substr(1));
	});
});
<commit_msg>Fix code<commit_after>var currentContent;
function loadContent(page) {
	if (page !== currentContent) {
		$("#content").hide("fade", "fast", function() {
			$("#content").load("html/" + page + ".html", function() {
				$("#content").show("fade", "fast");
			});
		});
	}
}
$(document).ready(function() {
	$("a.load").click(function(event) {
		loadContent(this.getAttribute("href").substr(1));
	});
});
<|endoftext|>


<commit_before>(function() {

if(/gyazo\.com/.test(location.hostname)){
  document.documentElement.setAttribute("data-extension-installed", true);
}

function changeFixedElementToAbsolute(){
  Array.prototype.slice.apply(document.querySelectorAll('*')).filter(function(item){
    return (window.getComputedStyle(item).position === 'fixed')
  }).forEach(function(item){
    item.classList.add('gyazo-whole-capture-onetime-absolute');
      item.style.position = 'absolute';
  });
}

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
  var actions = {
    gyazoCapture: function() {
      var startX, startY, data = {};
      var tempUserSelect = document.body.style.webkitUserSelect;
      var layer = document.createElement('div');
      layer.style.position = 'fixed';
      layer.style.left = document.body.clientLeft + 'px';
      layer.style.top = document.body.clientTop + 'px';
      layer.style.width = document.body.clientWidth + 'px';
      layer.style.height = document.body.clientHeight + 'px';
      layer.style.zIndex = 2147483647; //Maximun number of 32bit Int
      layer.style.cursor = 'crosshair';
      document.body.style.webkitUserSelect = 'none';
      var selectionElm = document.createElement('div');
      layer.appendChild(selectionElm);
      document.body.appendChild(layer);
      selectionElm.styleUpdate = function(styles) {
        Object.keys(styles).forEach(function(key) {
          selectionElm.style[key] = styles[key];
        });
      };
      selectionElm.styleUpdate({
        background: 'rgba(92, 92, 92, 0.3)',
        position: 'fixed'
      });
      var cancelGyazo = function(){
        document.body.removeChild(layer);
        document.body.style.webkitUserSelect = tempUserSelect;
        document.removeEventListener('keydown', keydownHandler);
        window.removeEventListener('contextmenu', cancelGyazo);
      }
      var keydownHandler = function(e){
        // If press Esc Key, cancel it
        if(e.keyCode === 27){
          cancelGyazo();
        }
      };
      var mousedownHandler = function(e) {
        startX = e.clientX;
        startY = e.clientY;
        selectionElm.styleUpdate({
          border: '1px solid rgba(255, 255, 255, 0.8)',
          left: startX + 'px',
          top: startY + 'px'
        });
        layer.removeEventListener('mousedown', mousedownHandler);
        layer.addEventListener('mousemove', mousemoveHandler);
        layer.addEventListener('mouseup', mouseupHandler);
      };
      var mousemoveHandler = function(e) {
        selectionElm.styleUpdate({
          width: (Math.abs(e.clientX - startX) - 1) + 'px',
          height: (Math.abs(e.clientY - startY) - 1) + 'px',
          left: Math.min(e.clientX, startX) + 'px',
          top: Math.min(e.clientY, startY) + 'px'
        });
      };
      var mouseupHandler = function(e) {
        document.body.style.webkitUserSelect = tempUserSelect;
        document.removeEventListener('keydown', keydownHandler);
        window.addEventListener('contextmenu', function(event){
          cancelGyazo();
          event.preventDefault();
        });
        var zoom = Math.round(window.outerWidth / window.innerWidth * 100) / 100;
        var scale = window.devicePixelRatio / zoom;
        data.w = Math.abs(e.clientX - startX);
        data.h = Math.abs(e.clientY - startY);
        if(data.h < 1 || data.w < 1){
          document.body.removeChild(layer);
          return false;
        }
        data.x = Math.min(e.clientX, startX);
        data.y = Math.min(e.clientY, startY);
        data.t = document.title;
        data.u = location.href;
        data.s = scale;
        data.z = zoom;
        document.body.removeChild(layer);
        //wait for rewrite by removeChild
        window.setTimeout(function() {
          chrome.runtime.sendMessage(chrome.runtime.id,{
            action: 'gyazoCaptureSize',
            data: data
          }, function(){});
        },100);
      };
      layer.addEventListener('mousedown', mousedownHandler);
      document.addEventListener('keydown', keydownHandler);
      window.addEventListener('contextmenu', cancelGyazo);
    },
    wholeCaptureInit: function() {
      var context = request.context;
      context.scrollY = window.scrollY;
      context.overflow = document.documentElement.style.overflow;
      context.overflowY = document.documentElement.style.overflowY;
      document.documentElement.style.overflow = 'hidden';
      document.documentElement.style.overflowY = 'hidden';
      //I want some fixed element not to follow scrolling
      changeFixedElementToAbsolute();
      window.scroll(0, 0);
      var zoom = Math.round(window.outerWidth / window.innerWidth * 100) / 100;
      var data = {
        width: window.outerWidth,
        height: Math.max(document.body.clientHeight, document.body.offsetHeight, document.body.scrollHeight),
        windowInnerHeight: window.innerHeight,
        title: document.title,
        url: location.href,
        captureTop: 0,
        captureButtom: window.innerHeight * zoom,
        scrollPositionY: 0,
        scale: window.devicePixelRatio / zoom,
        zoom: zoom
      };
      //waiting for repaint after scroll
      window.setTimeout(function(){
        chrome.runtime.sendMessage(chrome.runtime.id,{
          action: 'wholeCaptureManager',
          data: data,
          context: context
        });
      }, 50);
    },
    scrollNextPage: function(){
      var data = request.data;
      var captureTop = data.captureButtom;
      var captureButtom = captureTop + data.windowInnerHeight * data.zoom;
      var scrollPositionY = data.scrollPositionY + data.windowInnerHeight;
      window.scroll(0, scrollPositionY);
      data.captureTop = captureTop;
      data.captureButtom = captureButtom;
      data.scrollPositionY = scrollPositionY;
      //I want some fixed element not to follow scrolling
      window.setTimeout(function(){
        changeFixedElementToAbsolute();
        window.setTimeout(function(){
          chrome.runtime.sendMessage(chrome.runtime.id,{
            action: 'wholeCaptureManager',
            canvasData: request.canvasData,
            data: data,
            context: request.context
          });
        },0);
      }, 50);
    },
    wholeCaptureFinish: function(){
      document.documentElement.style.overflow = request.context.overflow;
      document.documentElement.style.overflowY = request.context.overflowY;
      var fixedElms = document.getElementsByClassName('gyazo-whole-capture-onetime-absolute');
      Array.prototype.slice.apply(fixedElms).forEach(function(item){
        item.classList.remove('gyazo-whole-capture-onetime-absolute');
        item.style.position = 'fixed';
      })
      window.scroll(0, request.context.scrollY);
    }
  };
  if(request.action in actions){
    actions[request.action]();
  }
});
})()
<commit_msg>fix inserting gray line on Windows<commit_after>(function() {

if(/gyazo\.com/.test(location.hostname)){
  document.documentElement.setAttribute("data-extension-installed", true);
}

function changeFixedElementToAbsolute(){
  Array.prototype.slice.apply(document.querySelectorAll('*')).filter(function(item){
    return (window.getComputedStyle(item).position === 'fixed')
  }).forEach(function(item){
    item.classList.add('gyazo-whole-capture-onetime-absolute');
      item.style.position = 'absolute';
  });
}

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
  var actions = {
    gyazoCapture: function() {
      var startX, startY, data = {};
      var tempUserSelect = document.body.style.webkitUserSelect;
      var layer = document.createElement('div');
      layer.style.position = 'fixed';
      layer.style.left = document.body.clientLeft + 'px';
      layer.style.top = document.body.clientTop + 'px';
      layer.style.width = document.body.clientWidth + 'px';
      layer.style.height = document.body.clientHeight + 'px';
      layer.style.zIndex = 2147483647; //Maximun number of 32bit Int
      layer.style.cursor = 'crosshair';
      document.body.style.webkitUserSelect = 'none';
      var selectionElm = document.createElement('div');
      layer.appendChild(selectionElm);
      document.body.appendChild(layer);
      selectionElm.styleUpdate = function(styles) {
        Object.keys(styles).forEach(function(key) {
          selectionElm.style[key] = styles[key];
        });
      };
      selectionElm.styleUpdate({
        background: 'rgba(92, 92, 92, 0.3)',
        position: 'fixed'
      });
      var cancelGyazo = function(){
        document.body.removeChild(layer);
        document.body.style.webkitUserSelect = tempUserSelect;
        document.removeEventListener('keydown', keydownHandler);
        window.removeEventListener('contextmenu', cancelGyazo);
      }
      var keydownHandler = function(e){
        // If press Esc Key, cancel it
        if(e.keyCode === 27){
          cancelGyazo();
        }
      };
      var mousedownHandler = function(e) {
        startX = e.clientX;
        startY = e.clientY;
        selectionElm.styleUpdate({
          border: '1px solid rgba(255, 255, 255, 0.8)',
          left: startX + 'px',
          top: startY + 'px'
        });
        layer.removeEventListener('mousedown', mousedownHandler);
        layer.addEventListener('mousemove', mousemoveHandler);
        layer.addEventListener('mouseup', mouseupHandler);
      };
      var mousemoveHandler = function(e) {
        selectionElm.styleUpdate({
          width: (Math.abs(e.clientX - startX) - 1) + 'px',
          height: (Math.abs(e.clientY - startY) - 1) + 'px',
          left: Math.min(e.clientX, startX) + 'px',
          top: Math.min(e.clientY, startY) + 'px'
        });
      };
      var mouseupHandler = function(e) {
        document.body.style.webkitUserSelect = tempUserSelect;
        document.removeEventListener('keydown', keydownHandler);
        window.addEventListener('contextmenu', function(event){
          cancelGyazo();
          event.preventDefault();
        });
        var zoom = Math.round(window.outerWidth / window.innerWidth * 100) / 100;
        var scale = window.devicePixelRatio / zoom;
        data.w = Math.abs(e.clientX - startX);
        data.h = Math.abs(e.clientY - startY);
        if(data.h < 1 || data.w < 1){
          document.body.removeChild(layer);
          return false;
        }
        data.x = Math.min(e.clientX, startX);
        data.y = Math.min(e.clientY, startY);
        data.t = document.title;
        data.u = location.href;
        data.s = scale;
        data.z = zoom;
        document.body.removeChild(layer);
        //wait for rewrite by removeChild
        window.setTimeout(function() {
          chrome.runtime.sendMessage(chrome.runtime.id,{
            action: 'gyazoCaptureSize',
            data: data
          }, function(){});
        },100);
      };
      layer.addEventListener('mousedown', mousedownHandler);
      document.addEventListener('keydown', keydownHandler);
      window.addEventListener('contextmenu', cancelGyazo);
    },
    wholeCaptureInit: function() {
      var context = request.context;
      context.scrollY = window.scrollY;
      context.overflow = document.documentElement.style.overflow;
      context.overflowY = document.documentElement.style.overflowY;
      document.documentElement.style.overflow = 'hidden';
      document.documentElement.style.overflowY = 'hidden';
      //I want some fixed element not to follow scrolling
      changeFixedElementToAbsolute();
      window.scroll(0, 0);
      var zoom = Math.round(window.outerWidth / window.innerWidth * 100) / 100;
	  var windowInnerHeight = window.innerHeight;
	  // XXX: on Windows, when window is not maximum, it should tweak zoom.(Chrome zoom level 1 is 1.10)
	  var isWindows = navigator.platform.match(/^win/i);
	  var isMaximum = (window.outerHeight === screen.availHeight);
	  if( isWindows && !isMaximum && 1.00 < zoom && zoom < 1.05){
	  	zoom = 1.00;
	  };
      var data = {
        width: window.outerWidth,
        height: Math.max(document.body.clientHeight, document.body.offsetHeight, document.body.scrollHeight),
        windowInnerHeight: window.innerHeight,
        title: document.title,
        url: location.href,
        captureTop: 0,
        captureButtom: window.innerHeight * zoom,
        scrollPositionY: 0,
        scale: window.devicePixelRatio / zoom,
        zoom: zoom
      };
      //waiting for repaint after scroll
      window.setTimeout(function(){
        chrome.runtime.sendMessage(chrome.runtime.id,{
          action: 'wholeCaptureManager',
          data: data,
          context: context
        });
      }, 50);
    },
    scrollNextPage: function(){
      var data = request.data;
      var captureTop = data.captureButtom;
      var captureButtom = captureTop + data.windowInnerHeight * data.zoom;
      var scrollPositionY = data.scrollPositionY + data.windowInnerHeight;
      window.scroll(0, scrollPositionY);
      data.captureTop = captureTop;
      data.captureButtom = captureButtom;
      data.scrollPositionY = scrollPositionY;
      //I want some fixed element not to follow scrolling
      window.setTimeout(function(){
        changeFixedElementToAbsolute();
        window.setTimeout(function(){
          chrome.runtime.sendMessage(chrome.runtime.id,{
            action: 'wholeCaptureManager',
            canvasData: request.canvasData,
            data: data,
            context: request.context
          });
        },0);
      }, 50);
    },
    wholeCaptureFinish: function(){
      document.documentElement.style.overflow = request.context.overflow;
      document.documentElement.style.overflowY = request.context.overflowY;
      var fixedElms = document.getElementsByClassName('gyazo-whole-capture-onetime-absolute');
      Array.prototype.slice.apply(fixedElms).forEach(function(item){
        item.classList.remove('gyazo-whole-capture-onetime-absolute');
        item.style.position = 'fixed';
      })
      window.scroll(0, request.context.scrollY);
    }
  };
  if(request.action in actions){
    actions[request.action]();
  }
});
})()
<|endoftext|>