<commit_before>var util = require('util'),
    _ = require('underscore'),
    cssom = require('cssom-papandreou'),
    cssmin = require('cssmin'),
    extendWithGettersAndSetters = require('../util/extendWithGettersAndSetters'),
    errors = require('../errors'),
    Text = require('./Text'),
    propertyWithImageUrlRegExp = /^(?:content|_?cursor|_?background(?:-image)?|(?:-[a-z]+-)?(?:border-image(?:-source)?|mask|mask-image|mask-image-source|mask-box-image|mask-box-image-source))$/,
    urlTokenRegExp = /\burl\((\'|\"|)([^\'\"]+?)\1\)/g,
    alphaImageLoaderSrcRegExp = /AlphaImageLoader\([^\)]*src=([\'\"])(.+?)(\1)[^\)]*\)/gi;

function Css(config) {
    Text.call(this, config);
}

module.exports = Css;

var AssetGraph = require('../AssetGraph');

util.inherits(Css, Text);

function extractEncodingFromText(text) {
    var matchCharset = text.match(/@charset\s*([\'\"])\s*([\w\-]+)\s*\1/mi);
    return matchCharset && matchCharset[2]; // Will be undefined in case of no match
}

extendWithGettersAndSetters(Css.prototype, {
    contentType: 'text/css',

    supportedExtensions: ['.css'],

    isPretty: false,

    get encoding() {
        if (!this._encoding) {
            if ('_text' in this) {
                this._encoding = extractEncodingFromText(this._text) || this.defaultEncoding;
            } else if (this._rawSrc) {
                this._encoding = extractEncodingFromText(this._rawSrc.toString('binary', 0, Math.min(1024, this._rawSrc.length))) || this.defaultEncoding;
            } else {
                this._encoding = this.defaultEncoding;
            }
        }
        return this._encoding;
    },

    set encoding(encoding) {
        if (encoding !== this.encoding) {
            var text = this.text; // Make sure this._text exists so the rawSrc is decoded before the original encoding is thrown away
            delete this._rawSrc;
            this._encoding = encoding;
            this.markDirty();
        }
    },

    get text() {
        if (!('_text' in this)) {
            if (this._parseTree) {
                this._text = this._parseTree.toString();
                if (!this.isPretty) {
                    this._text = cssmin.cssmin(this._text);
                }
            } else {
                this._text = this._getTextFromRawSrc();
            }
        }
        return this._text;
    },

    get parseTree() {
        if (!this._parseTree) {
            // CSSOM gets the @charset declaration mixed up with the first selector:
            try {
                this._parseTree = cssom.parse(this.text.replace(/@charset\s*([\'\"])\s*[\w\-]+\s*\1;/, ""));
            } catch (e) {
                var err = new errors.ParseError({
                    message: 'Parse error in ' + this.urlOrDescription +
                        '(line ' + e.line + ', column ' + e['char'] + '):\n' + e.message +
                        (e.styleSheet ? '\nFalling back to using the ' + e.styleSheet.cssRules.length + ' parsed CSS rules' : ''),
                    styleSheet: e.styleSheet,
                    line: e.line,
                    column: e['char'],
                    asset: this
                });
                if (this.assetGraph) {
                    if (err.styleSheet) {
                        this._parseTree = err.styleSheet;
                    } else {
                        this._parseTree = {cssRules: []};
                    }
                    this.assetGraph.emit('error', err);
                } else {
                    throw err;
                }
            }
        }
        return this._parseTree;
    },

    set parseTree(parseTree) {
        this.unload();
        this._parseTree = parseTree;
        this.markDirty();
    },

    get isEmpty() {
        return this.parseTree.cssRules.length === 0;
    },

    minify: function () {
        this.isPretty = false;
        var parseTree = this.parseTree; // So markDirty removes this._text
        this.markDirty();
        return this;
    },

    prettyPrint: function () {
        this.isPretty = true;
        var parseTree = this.parseTree; // So markDirty removes this._text
        this.markDirty();
        return this;
    },

    findOutgoingRelationsInParseTree: function () {
        var outgoingRelations = [];
        this.eachRuleInParseTree(function (cssRule, parentRuleOrStylesheet) {
            if (cssRule.type === cssom.CSSRule.IMPORT_RULE) {
                outgoingRelations.push(new AssetGraph.CssImport({
                    from: this,
                    to: {
                        url: cssRule.href
                    },
                    parentRule: parentRuleOrStylesheet,
                    cssRule: cssRule
                }));
            } else if (cssRule.type === cssom.CSSRule.FONT_FACE_RULE) {
                var src = cssRule.style.getPropertyValue('src');
                if (src) {
                    var matchUrlToken,
                        tokenNumber = 0;
                    urlTokenRegExp.lastIndex = 0; // Just in case
                    while ((matchUrlToken = urlTokenRegExp.exec(src))) {
                        outgoingRelations.push(new AssetGraph.CssFontFaceSrc({
                            from: this,
                            to: {
                                url: matchUrlToken[2]
                            },
                            tokenNumber: tokenNumber++,
                            parentRule: parentRuleOrStylesheet,
                            cssRule: cssRule
                        }));
                    }
                }
            } else if (cssRule.type === cssom.CSSRule.STYLE_RULE) {
                var style = cssRule.style;
                for (var i = 0 ; i < style.length ; i += 1) {
                    var propertyName = style[i];
                    if (propertyWithImageUrlRegExp.test(style[i])) {
                        var matchUrlToken,
                            tokenNumber = 0,
                            propertyValue = style.getPropertyValue(propertyName);
                        urlTokenRegExp.lastIndex = 0; // Just in case
                        while ((matchUrlToken = urlTokenRegExp.exec(propertyValue))) {
                            outgoingRelations.push(new AssetGraph.CssImage({
                                from: this,
                                to: {
                                    url: matchUrlToken[2]
                                },
                                tokenNumber: tokenNumber++,
                                parentRule: parentRuleOrStylesheet,
                                cssRule: cssRule,
                                propertyName: propertyName
                            }));
                        }
                    }
                }
                ['behavior', '_behavior'].forEach(function (propertyName) {
                    if (propertyName in style) {
                        // Skip behavior properties that have # as the first char in the url so that
                        // stuff like behavior(#default#VML) won't be treated as a relation.
                        var matchUrl = style[propertyName].match(/\burl\((\'|\"|)([^#\'\"][^\'\"]*?)\1\)/);
                        if (matchUrl) {
                            outgoingRelations.push(new AssetGraph.CssBehavior({
                                from: this,
                                to: {
                                    url: matchUrl[2]
                                },
                                parentRule: parentRuleOrStylesheet,
                                cssRule: cssRule,
                                propertyName: propertyName
                            }));
                        }
                    }
                }, this);
                ['filter', '_filter', '-ms-filter'].forEach(function (propertyName) {
                    if (propertyName in style) {
                        var tokenNumber = 0,
                            value = style.getPropertyValue(propertyName),
                            matchSrcToken;
                        alphaImageLoaderSrcRegExp.lastIndex = 0; // Just in case
                        while ((matchSrcToken = alphaImageLoaderSrcRegExp.exec(value))) {
                            outgoingRelations.push(new AssetGraph.CssAlphaImageLoader({
                                from: this,
                                to: {
                                    url: matchSrcToken[2]
                                },
                                tokenNumber: tokenNumber++,
                                parentRule: parentRuleOrStylesheet,
                                cssRule: cssRule,
                                propertyName: propertyName
                            }));
                        }
                    }
                }, this);
            }
        }.bind(this));
        return outgoingRelations;
    }
});

// Grrr...
Css.prototype.__defineSetter__('text', Text.prototype.__lookupSetter__('text'));

// If lambda returns false, subrules won't be traversed
Css.eachRuleInParseTree = function (ruleOrStylesheet, lambda) {
    _.toArray(ruleOrStylesheet.cssRules).forEach(function (cssRule) {
        if (lambda(cssRule, ruleOrStylesheet) !== false && cssRule.cssRules) {
            Css.eachRuleInParseTree(cssRule, lambda);
        }
    });
};

Css.prototype.eachRuleInParseTree = function (lambda) {
    return Css.eachRuleInParseTree(this.parseTree, lambda);
};
<commit_msg>Lower severity level of partially parsed CSS to warning isntead of error<commit_after>var util = require('util'),
    _ = require('underscore'),
    cssom = require('cssom-papandreou'),
    cssmin = require('cssmin'),
    extendWithGettersAndSetters = require('../util/extendWithGettersAndSetters'),
    errors = require('../errors'),
    Text = require('./Text'),
    propertyWithImageUrlRegExp = /^(?:content|_?cursor|_?background(?:-image)?|(?:-[a-z]+-)?(?:border-image(?:-source)?|mask|mask-image|mask-image-source|mask-box-image|mask-box-image-source))$/,
    urlTokenRegExp = /\burl\((\'|\"|)([^\'\"]+?)\1\)/g,
    alphaImageLoaderSrcRegExp = /AlphaImageLoader\([^\)]*src=([\'\"])(.+?)(\1)[^\)]*\)/gi;

function Css(config) {
    Text.call(this, config);
}

module.exports = Css;

var AssetGraph = require('../AssetGraph');

util.inherits(Css, Text);

function extractEncodingFromText(text) {
    var matchCharset = text.match(/@charset\s*([\'\"])\s*([\w\-]+)\s*\1/mi);
    return matchCharset && matchCharset[2]; // Will be undefined in case of no match
}

extendWithGettersAndSetters(Css.prototype, {
    contentType: 'text/css',

    supportedExtensions: ['.css'],

    isPretty: false,

    get encoding() {
        if (!this._encoding) {
            if ('_text' in this) {
                this._encoding = extractEncodingFromText(this._text) || this.defaultEncoding;
            } else if (this._rawSrc) {
                this._encoding = extractEncodingFromText(this._rawSrc.toString('binary', 0, Math.min(1024, this._rawSrc.length))) || this.defaultEncoding;
            } else {
                this._encoding = this.defaultEncoding;
            }
        }
        return this._encoding;
    },

    set encoding(encoding) {
        if (encoding !== this.encoding) {
            var text = this.text; // Make sure this._text exists so the rawSrc is decoded before the original encoding is thrown away
            delete this._rawSrc;
            this._encoding = encoding;
            this.markDirty();
        }
    },

    get text() {
        if (!('_text' in this)) {
            if (this._parseTree) {
                this._text = this._parseTree.toString();
                if (!this.isPretty) {
                    this._text = cssmin.cssmin(this._text);
                }
            } else {
                this._text = this._getTextFromRawSrc();
            }
        }
        return this._text;
    },

    get parseTree() {
        if (!this._parseTree) {
            // CSSOM gets the @charset declaration mixed up with the first selector:
            try {
                this._parseTree = cssom.parse(this.text.replace(/@charset\s*([\'\"])\s*[\w\-]+\s*\1;/, ""));
            } catch (e) {
                var err = new errors.ParseError({
                    message: 'Parse error in ' + this.urlOrDescription +
                        '(line ' + e.line + ', column ' + e['char'] + '):\n' + e.message +
                        (e.styleSheet ? '\nFalling back to using the ' + e.styleSheet.cssRules.length + ' parsed CSS rules' : ''),
                    styleSheet: e.styleSheet,
                    line: e.line,
                    column: e['char'],
                    asset: this
                });
                if (this.assetGraph) {
                    if (err.styleSheet) {
                        this._parseTree = err.styleSheet;
                    } else {
                        this._parseTree = {cssRules: []};
                    }
                    this.assetGraph.emit('warn', err);
                } else {
                    throw err;
                }
            }
        }
        return this._parseTree;
    },

    set parseTree(parseTree) {
        this.unload();
        this._parseTree = parseTree;
        this.markDirty();
    },

    get isEmpty() {
        return this.parseTree.cssRules.length === 0;
    },

    minify: function () {
        this.isPretty = false;
        var parseTree = this.parseTree; // So markDirty removes this._text
        this.markDirty();
        return this;
    },

    prettyPrint: function () {
        this.isPretty = true;
        var parseTree = this.parseTree; // So markDirty removes this._text
        this.markDirty();
        return this;
    },

    findOutgoingRelationsInParseTree: function () {
        var outgoingRelations = [];
        this.eachRuleInParseTree(function (cssRule, parentRuleOrStylesheet) {
            if (cssRule.type === cssom.CSSRule.IMPORT_RULE) {
                outgoingRelations.push(new AssetGraph.CssImport({
                    from: this,
                    to: {
                        url: cssRule.href
                    },
                    parentRule: parentRuleOrStylesheet,
                    cssRule: cssRule
                }));
            } else if (cssRule.type === cssom.CSSRule.FONT_FACE_RULE) {
                var src = cssRule.style.getPropertyValue('src');
                if (src) {
                    var matchUrlToken,
                        tokenNumber = 0;
                    urlTokenRegExp.lastIndex = 0; // Just in case
                    while ((matchUrlToken = urlTokenRegExp.exec(src))) {
                        outgoingRelations.push(new AssetGraph.CssFontFaceSrc({
                            from: this,
                            to: {
                                url: matchUrlToken[2]
                            },
                            tokenNumber: tokenNumber++,
                            parentRule: parentRuleOrStylesheet,
                            cssRule: cssRule
                        }));
                    }
                }
            } else if (cssRule.type === cssom.CSSRule.STYLE_RULE) {
                var style = cssRule.style;
                for (var i = 0 ; i < style.length ; i += 1) {
                    var propertyName = style[i];
                    if (propertyWithImageUrlRegExp.test(style[i])) {
                        var matchUrlToken,
                            tokenNumber = 0,
                            propertyValue = style.getPropertyValue(propertyName);
                        urlTokenRegExp.lastIndex = 0; // Just in case
                        while ((matchUrlToken = urlTokenRegExp.exec(propertyValue))) {
                            outgoingRelations.push(new AssetGraph.CssImage({
                                from: this,
                                to: {
                                    url: matchUrlToken[2]
                                },
                                tokenNumber: tokenNumber++,
                                parentRule: parentRuleOrStylesheet,
                                cssRule: cssRule,
                                propertyName: propertyName
                            }));
                        }
                    }
                }
                ['behavior', '_behavior'].forEach(function (propertyName) {
                    if (propertyName in style) {
                        // Skip behavior properties that have # as the first char in the url so that
                        // stuff like behavior(#default#VML) won't be treated as a relation.
                        var matchUrl = style[propertyName].match(/\burl\((\'|\"|)([^#\'\"][^\'\"]*?)\1\)/);
                        if (matchUrl) {
                            outgoingRelations.push(new AssetGraph.CssBehavior({
                                from: this,
                                to: {
                                    url: matchUrl[2]
                                },
                                parentRule: parentRuleOrStylesheet,
                                cssRule: cssRule,
                                propertyName: propertyName
                            }));
                        }
                    }
                }, this);
                ['filter', '_filter', '-ms-filter'].forEach(function (propertyName) {
                    if (propertyName in style) {
                        var tokenNumber = 0,
                            value = style.getPropertyValue(propertyName),
                            matchSrcToken;
                        alphaImageLoaderSrcRegExp.lastIndex = 0; // Just in case
                        while ((matchSrcToken = alphaImageLoaderSrcRegExp.exec(value))) {
                            outgoingRelations.push(new AssetGraph.CssAlphaImageLoader({
                                from: this,
                                to: {
                                    url: matchSrcToken[2]
                                },
                                tokenNumber: tokenNumber++,
                                parentRule: parentRuleOrStylesheet,
                                cssRule: cssRule,
                                propertyName: propertyName
                            }));
                        }
                    }
                }, this);
            }
        }.bind(this));
        return outgoingRelations;
    }
});

// Grrr...
Css.prototype.__defineSetter__('text', Text.prototype.__lookupSetter__('text'));

// If lambda returns false, subrules won't be traversed
Css.eachRuleInParseTree = function (ruleOrStylesheet, lambda) {
    _.toArray(ruleOrStylesheet.cssRules).forEach(function (cssRule) {
        if (lambda(cssRule, ruleOrStylesheet) !== false && cssRule.cssRules) {
            Css.eachRuleInParseTree(cssRule, lambda);
        }
    });
};

Css.prototype.eachRuleInParseTree = function (lambda) {
    return Css.eachRuleInParseTree(this.parseTree, lambda);
};
<|endoftext|>


<commit_before>var express = require('express');
var bodyParser = require('body-parser');
var expressValidator = require(‘express-validator’);

var app = express();

app.use(bodyParser.json({ type: 'application/json' }));
// We add the middleware after we load the body parser
app.use(expressValidator());

var postgres = require('./lib/postgres');

function lookupPhoto(req, res, next) {
// We access the ID param on the request object
  var photoId = req.params.id;

// Create the express router object for Photos
var photoRouter = express.Router();
photoRouter.get('/', function(req, res) { });
photoRouter.post('/', function(req, res) {

// Build an SQL query to select the resource object by ID
	var sql = 'Insert into photo (description, filepath, album_id) VALEs ($1, $2, $3) RETURNING id';
	var data = [
    req.body.description,
    req.body.filepath,
    req.body.album_id
  ];

	postgres.client.query(sql, data, function(err, result) {
	    if (err) {
	      console.error(err);
	      res.statusCode = 500;
	      return res.json({
	        errors: ['Failed to create photo']
	      });
	    }

	var newPhotoId = result.rows[0].id;
    var sql = 'SELECT * FROM photo WHERE id = $1';
    postgres.client.query(sql, [ newPhotoId ], function(err, result) {
      if (err) {
        // We shield our clients from internal errors, but log them
        console.error(err);
        res.statusCode = 500;
        return res.json({
          errors: ['Could not retrieve photo after create']
        });
      }
      // The request created a new resource object
      res.statusCode = 201;
      // The result of CREATE should be the same as GET
      res.json(result.rows[0]);
  });
});

// A GET to the root of a resource returns a list of that resource
photoRouter.get('/', function(req, res) { });

// A POST to the root of a resource should create a new object
photoRouter.post('/', function(req, res) { });

// We specify a param in our path for the GET of a specific object
photoRouter.get('/:id', function(req, res) {
	res.json(req.photo);
});

// Similar to the GET on an object, to update it we can PATCH
photoRouter.patch('/:id', function(req, res) { });

// Delete a specific object
photoRouter.delete('/:id', function(req, res) { });

// Attach the routers for their respective paths
app.use('/photo', photoRouter);

module.exports = app;<commit_msg>Restarted the tutorial from scratch after reviewing Building Blocks with Express<commit_after>var express = require('express');
var app = express();

//Declared a new express router for Photo path
var photoRouter = express.Router();

//Used the "chaining" feature to refactor code
photoRouter.get(‘/’, function(req, res) { });
photoRouter.post(‘/’, function(req, res) { });
photoRouter.get(‘/:id’, function(req, res) { });
photoRouter.patch(‘/:id’, function(req, res) { });
photoRouter.delete(‘/:id’, function(req, res) { });
app.use(‘/photo’, photoRouter);

//Declared a new express router for Album path
var albumRouter = express.Router();

//Used the "chaining" feature to refactor code
photoRouter.get(‘/’, function(req, res) { });
albumRouter.get(‘/’, function(req, res) { });
albumRouter.post(‘/’, function(req, res) { });
albumRouter.get(‘/:id’, function(req, res) { });
albumRouter.patch(‘/:id’, function(req, res) { });
albumRouter.delete(‘/:id’, function(req, res) { });
app.use(‘/album’, albumRouter);

//Exported Node Module
module.exports = app;<|endoftext|>


<commit_before>/* jshint ignore:start */
'use strict';

const BbPromise = require('bluebird');
const fse = require('fs-extra');
const {addVendorHelper, removeVendorHelper, packRequirements} = require('./lib/zip');
const {installRequirements} = require('./lib/pip');
const {pipfileToRequirements} = require('./lib/pipenv');
const {linkRequirements, unlinkRequirements} = require('./lib/link');
const {cleanup} = require('./lib/clean');

BbPromise.promisifyAll(fse);

/**
 * Plugin for Serverless 1.x that bundles python requirements!
 */
class ServerlessPythonRequirements {
  /**
   * get the custom.pythonRequirements contents, with defaults set
   * @return {Object}
   */
  get options() {
    const options = Object.assign({
      zip: false,
      cleanupZipHelper: true,
      invalidateCaches: false,
      fileName: 'requirements.txt',
      usePipenv: true,
      pythonBin: this.serverless.service.provider.runtime || 'python',
      dockerizePip: false,
      dockerSsh: false,
      dockerImage: null,
      dockerFile: null,
      pipCmdExtraArgs: [],
      noDeploy: [
        'boto3',
        'botocore',
        'docutils',
        'jmespath',
        'python-dateutil',
        's3transfer',
        'six',
        'pip',
        'setuptools',
      ],
    }, this.serverless.service.custom && this.serverless.service.custom.pythonRequirements || {});
    if (options.dockerizePip === 'non-linux') {
      options.dockerizePip = process.platform !== 'linux';
    }
    if (options.dockerImage && options.dockerFile) {
      throw new Error(
        'Python Requirements: you can provide a dockerImage or a dockerFile option, not both.'
      );
    } else if (!options.dockerFile) {
      // If no dockerFile is provided, use default image
      const defaultImage = `lambci/lambda:build-${this.serverless.service.provider.runtime}`;
      options.dockerImage = options.dockerImage || defaultImage;
    }
    if (!options.dockerizePip && (options.dockerSsh||options.dockerImage||options.dockerFile)) {
      if (!this.warningLogged) {
        this.serverless.cli.log(
          'WARNING: You provided a docker related option but dockerizePip is set to false.'
        );
        this.warningLogged = true;
      }
    }
    return options;
  }

  /**
   * The plugin constructor
   * @param {Object} serverless
   * @param {Object} options
   * @return {undefined}
   */
  constructor(serverless, options) {
    this.serverless = serverless;
    this.servicePath = this.serverless.config.servicePath;
    this.warningLogged = false;

    this.commands = {
      requirements: {
        commands: {
          clean: {
            usage: 'Remove .requirements and requirements.zip',
            lifecycleEvents: [
              'clean',
            ],
          },
          install: {
            usage: 'install requirements manually',
            lifecycleEvents: [
              'install',
            ],
          },
        },
      },
    };

    const before = () => BbPromise.bind(this)
      .then(pipfileToRequirements)
      .then(addVendorHelper)
      .then(installRequirements)
      .then(packRequirements)
      .then(linkRequirements);

    const after = () => BbPromise.bind(this)
      .then(removeVendorHelper)
      .then(unlinkRequirements);

    const invalidateCaches = () => {
      if (this.options.invalidateCaches) {
        return BbPromise.bind(this)
          .then(cleanup)
          .then(removeVendorHelper);
      }
      return BbPromise.resolve();
    };

    this.hooks = {
      'after:package:cleanup': invalidateCaches,
      'before:package:createDeploymentArtifacts': before,
      'after:package:createDeploymentArtifacts': after,
      'before:deploy:function:packageFunction': before,
      'after:deploy:function:packageFunction': after,
      'requirements:install:install': () => BbPromise.bind(this)
        .then(pipfileToRequirements)
        .then(addVendorHelper)
        .then(installRequirements)
        .then(packRequirements),
      'requirements:clean:clean': () => BbPromise.bind(this)
        .then(cleanup)
        .then(removeVendorHelper),
    };
  }
}

module.exports = ServerlessPythonRequirements;
<commit_msg>do docker warning check before default image is set<commit_after>/* jshint ignore:start */
'use strict';

const BbPromise = require('bluebird');
const fse = require('fs-extra');
const {addVendorHelper, removeVendorHelper, packRequirements} = require('./lib/zip');
const {installRequirements} = require('./lib/pip');
const {pipfileToRequirements} = require('./lib/pipenv');
const {linkRequirements, unlinkRequirements} = require('./lib/link');
const {cleanup} = require('./lib/clean');

BbPromise.promisifyAll(fse);

/**
 * Plugin for Serverless 1.x that bundles python requirements!
 */
class ServerlessPythonRequirements {
  /**
   * get the custom.pythonRequirements contents, with defaults set
   * @return {Object}
   */
  get options() {
    const options = Object.assign({
      zip: false,
      cleanupZipHelper: true,
      invalidateCaches: false,
      fileName: 'requirements.txt',
      usePipenv: true,
      pythonBin: this.serverless.service.provider.runtime || 'python',
      dockerizePip: false,
      dockerSsh: false,
      dockerImage: null,
      dockerFile: null,
      pipCmdExtraArgs: [],
      noDeploy: [
        'boto3',
        'botocore',
        'docutils',
        'jmespath',
        'python-dateutil',
        's3transfer',
        'six',
        'pip',
        'setuptools',
      ],
    }, this.serverless.service.custom && this.serverless.service.custom.pythonRequirements || {});
    if (options.dockerizePip === 'non-linux') {
      options.dockerizePip = process.platform !== 'linux';
    }
    if (!options.dockerizePip && (options.dockerSsh||options.dockerImage||options.dockerFile)) {
      if (!this.warningLogged) {
        this.serverless.cli.log(
          'WARNING: You provided a docker related option but dockerizePip is set to false.'
        );
        this.warningLogged = true;
      }
    }
    if (options.dockerImage && options.dockerFile) {
      throw new Error(
        'Python Requirements: you can provide a dockerImage or a dockerFile option, not both.'
      );
    } else if (!options.dockerFile) {
      // If no dockerFile is provided, use default image
      const defaultImage = `lambci/lambda:build-${this.serverless.service.provider.runtime}`;
      options.dockerImage = options.dockerImage || defaultImage;
    }
    return options;
  }

  /**
   * The plugin constructor
   * @param {Object} serverless
   * @param {Object} options
   * @return {undefined}
   */
  constructor(serverless, options) {
    this.serverless = serverless;
    this.servicePath = this.serverless.config.servicePath;
    this.warningLogged = false;

    this.commands = {
      requirements: {
        commands: {
          clean: {
            usage: 'Remove .requirements and requirements.zip',
            lifecycleEvents: [
              'clean',
            ],
          },
          install: {
            usage: 'install requirements manually',
            lifecycleEvents: [
              'install',
            ],
          },
        },
      },
    };

    const before = () => BbPromise.bind(this)
      .then(pipfileToRequirements)
      .then(addVendorHelper)
      .then(installRequirements)
      .then(packRequirements)
      .then(linkRequirements);

    const after = () => BbPromise.bind(this)
      .then(removeVendorHelper)
      .then(unlinkRequirements);

    const invalidateCaches = () => {
      if (this.options.invalidateCaches) {
        return BbPromise.bind(this)
          .then(cleanup)
          .then(removeVendorHelper);
      }
      return BbPromise.resolve();
    };

    this.hooks = {
      'after:package:cleanup': invalidateCaches,
      'before:package:createDeploymentArtifacts': before,
      'after:package:createDeploymentArtifacts': after,
      'before:deploy:function:packageFunction': before,
      'after:deploy:function:packageFunction': after,
      'requirements:install:install': () => BbPromise.bind(this)
        .then(pipfileToRequirements)
        .then(addVendorHelper)
        .then(installRequirements)
        .then(packRequirements),
      'requirements:clean:clean': () => BbPromise.bind(this)
        .then(cleanup)
        .then(removeVendorHelper),
    };
  }
}

module.exports = ServerlessPythonRequirements;
<|endoftext|>


<commit_before>'use strict';

module.exports = Attributes;

var node_path = require('path');
var node_url = require('url');

// @param {Object} attrs list of attr(see `this.add`)
// @param {Object} options
// - host: {Object} host object
function Attributes(attrs, options) {
    options = options || {};
    this.host = options.context || this;
    this.__attrs = {};
    // this.origin_attrs = attrs;
    this.origin_values = get_values(attrs);
    this.attr_list = [];

    var key;

    for(key in attrs){
        this.add(key, attrs[key]);
    }
};

function get_values(attrs) {
    var ret = {};
    var key;
    var attr;

    for(key in attrs){
        attr = attrs[key];
        if('value' in attr){
            ret[key] = attr.value;
        }
    }

    return;
}

var TYPES = {
    path: {
        validator: function (v) {
            return v || v === '';
        },

        setter: function (v) {
            return path.resolve( String(v) );
        }
    },

    url: {
        validator: function (v) {
            return !!node_url.parse(v).host;
        }
    }
};

[Number, String, Boolean].forEach(function (constructor) {
    var name = constructor.name.toLowerCase();

    TYPES[name] = {
        setter: function (v) {
            return constructor(v);
        }
    }
});

// Object.defineProperties(Attributes, 'TYPES', {
//     value: TYPES
// });

Attributes.TYPES = TYPES;

// TODO
// [Array, Function, ].

Attributes.prototype = {
    _get: function (key) {
        var attr = this.__attrs[key];

        if(!attr){
            return;
        }

        var getter = attr.type.getter;
        var value = attr.value;

        return getter ?

              // getter could based on the value of the current value
            getter.call(this.host, value, key, this) :
            value;
    },

    get: function (key) {
        if(arguments.length === 0){
            var ret = {};
            var self = this;

            this.attr_list.forEach(function (key) {
                ret[key] = self._get(key);
            });

            return ret;

        }else{
            return this._get(key);
        }
    },

    // Reset to default value.
    // Run this method will execute setup methods
    reset: function () {
        var key;
        // values = values || this.origin_values;
        var values = this.origin_values;

        for( key in values ){
            this._reset(key, values[key], true);
        }
    },

    _reset: function (key, value, attr) {
        attr = attr || this.__attrs[key];
        value = value || attr.value;

        attr.value = value;

        var setup = attr.type.setup;

        if(setup){
            setup.call(this.host, value, key, this);
        }
    },

    getWritable: function () {
        var ret = {};
        var attrs = this.__attrs;
        var self = this;

        this.attr_list.filter(function (key) {
            return !attrs[key].readOnly;

        }).forEach(function (key) {
            ret[key] = self._get(key);
        });

        return ret;
    },

    // @param {boolean=} ghost, ghost set, skip validation
    _set: function (key, value, ghost) {
        var attr = this.__attrs[key];
        var status = {
            err: true
        };

        if(ghost){
            attr.value = value;
            return;
        }

        if(!attr){
            return status;
        }

        if(attr.readOnly){
            return status;
        }

        // reset error status
        this.error(null);
        delete status.err;

        var validator = attr.type.validator;

        if(!validator || validator.call(this.host, value, key, this)){

            // validator returns true, but there might be error messages
            if( !(status.err = this._get_err()) ){
                var setter = attr.type.setter;
                if(setter){
                    value = setter.call(this.host, value, key, this);
                }

                status.err = this._get_err();
            }

        }else{
            // validation fail
            status.err = this._get_err() || true;
        }

        if(!status.err){
            attr.value = value;
        }

        return status;
    },

    set: function (key, value) {
        if(Object(key) === key){
            var list = key;
            var err;
            var errors = {};
            var result;

            for(key in list){
                value = list[key];
                var result = this._set(key, value);

                if(result.err){
                    err = true;
                    errors[key] = result.err;
                }
            }

            if(err){
                return {
                    err: true,
                    errors: errors
                }
            }else{
                return {};
            }

        }else if(typeof key === 'string'){
            var data = {};
            data[key] = value;

            return this.set(data);

        }else{
            return {
                err: true
            }
        }
    },

    // @param {Object} attr
    // - value: {mixed} default value
    // - type:
    add: function (key, attr) {
        if(key in this.__attrs){
            return;
        }

        attr = attr || {};

        var type = attr.type || {};

        if(typeof type === 'string'){
            type = Attributes.TYPES[type];
        }

        if(Object(type) !== type){
            return;
        }

        this.attr_list.push(key);
        attr.type = type;

        this.__attrs[key] = attr;
        this._reset(key, null, attr);

        return true;
    },

    error: function (info) {
        this._err = info;
    },

    _get_err: function () {
        return this._err;
    }
};

// Object.seal(Attributes);
Object.seal(Attributes.TYPES);
Object.preventExtensions(Attributes.TYPES);<commit_msg>add a descriptor to prevent saving to profile.js<commit_after>'use strict';

module.exports = Attributes;

var node_path = require('path');
var node_url = require('url');

// @param {Object} attrs list of attr(see `this.add`)
// @param {Object} options
// - host: {Object} host object
function Attributes(attrs, options) {
    options = options || {};
    this.host = options.context || this;
    this.__attrs = {};
    // this.origin_attrs = attrs;
    this.origin_values = get_values(attrs);
    this.attr_list = [];

    var key;

    for(key in attrs){
        this.add(key, attrs[key]);
    }
};

function get_values(attrs) {
    var ret = {};
    var key;
    var attr;

    for(key in attrs){
        attr = attrs[key];
        if('value' in attr){
            ret[key] = attr.value;
        }
    }

    return;
}

var TYPES = {
    path: {
        validator: function (v) {
            return v || v === '';
        },

        setter: function (v) {
            return path.resolve( String(v) );
        }
    },

    url: {
        validator: function (v) {
            return !!node_url.parse(v).host;
        }
    }
};

[Number, String, Boolean].forEach(function (constructor) {
    var name = constructor.name.toLowerCase();

    TYPES[name] = {
        setter: function (v) {
            return constructor(v);
        }
    }
});

// Object.defineProperties(Attributes, 'TYPES', {
//     value: TYPES
// });

Attributes.TYPES = TYPES;

// TODO
// [Array, Function, ].

Attributes.prototype = {
    _get: function (key) {
        var attr = this.__attrs[key];

        if(!attr){
            return;
        }

        var getter = attr.type.getter;
        var value = attr.value;

        return getter ?

              // getter could based on the value of the current value
            getter.call(this.host, value, key, this) :
            value;
    },

    get: function (key) {
        if(arguments.length === 0){
            var ret = {};
            var self = this;

            this.attr_list.forEach(function (key) {
                ret[key] = self._get(key);
            });

            return ret;

        }else{
            return this._get(key);
        }
    },

    // Reset to default value.
    // Run this method will execute setup methods
    reset: function () {
        var key;
        // values = values || this.origin_values;
        var values = this.origin_values;

        for( key in values ){
            this._reset(key, values[key], true);
        }
    },

    _reset: function (key, value, attr) {
        attr = attr || this.__attrs[key];
        value = value || attr.value;

        attr.value = value;

        var setup = attr.type.setup;

        if(setup){
            setup.call(this.host, value, key, this);
        }
    },

    getWritable: function () {
        var ret = {};
        var attrs = this.__attrs;
        var self = this;

        this.attr_list.filter(function (key) {
            var attr = attrs[key];

            return !attr.readOnly && (

                // `true`
                attrs.enumerable ||

                // Or not specified (default to true)
                !('enumerable' in attr)
            );

        }).forEach(function (key) {
            ret[key] = self._get(key);
        });

        return ret;
    },

    // @param {boolean=} ghost, ghost set, skip validation
    _set: function (key, value, ghost) {
        var attr = this.__attrs[key];
        var status = {
            err: true
        };

        if(ghost){
            attr.value = value;
            return;
        }

        if(!attr){
            return status;
        }

        if(attr.readOnly){
            return status;
        }

        // reset error status
        this.error(null);
        delete status.err;

        var validator = attr.type.validator;

        if(!validator || validator.call(this.host, value, key, this)){

            // validator returns true, but there might be error messages
            if( !(status.err = this._get_err()) ){
                var setter = attr.type.setter;
                if(setter){
                    value = setter.call(this.host, value, key, this);
                }

                status.err = this._get_err();
            }

        }else{
            // validation fail
            status.err = this._get_err() || true;
        }

        if(!status.err){
            attr.value = value;
        }

        return status;
    },

    set: function (key, value) {
        if(Object(key) === key){
            var list = key;
            var err;
            var errors = {};
            var result;

            for(key in list){
                value = list[key];
                var result = this._set(key, value);

                if(result.err){
                    err = true;
                    errors[key] = result.err;
                }
            }

            if(err){
                return {
                    err: true,
                    errors: errors
                }
            }else{
                return {};
            }

        }else if(typeof key === 'string'){
            var data = {};
            data[key] = value;

            return this.set(data);

        }else{
            return {
                err: true
            }
        }
    },

    // @param {Object} attr
    // - value: {mixed} default value
    // - type:
    add: function (key, attr) {
        if(key in this.__attrs){
            return;
        }

        attr = attr || {};

        var type = attr.type || {};

        if(typeof type === 'string'){
            type = Attributes.TYPES[type];
        }

        if(Object(type) !== type){
            return;
        }

        this.attr_list.push(key);
        attr.type = type;

        this.__attrs[key] = attr;
        this._reset(key, null, attr);

        return true;
    },

    error: function (info) {
        this._err = info;
    },

    _get_err: function () {
        return this._err;
    }
};

// Object.seal(Attributes);
Object.seal(Attributes.TYPES);
Object.preventExtensions(Attributes.TYPES);<|endoftext|>


<commit_before>var through = require('through2');
var vm = require('vm');
var Module = require('module');

module.exports = function(context) {
	return through.obj(function(file, enc, next) {
		var fileContent = file.contents.toString(enc);
		file.data = _eval(fileContent, file.relative, context);
		next(null, file);
	});
};

function _eval(content, filename, context) {
    var sandbox = {};

    sandbox.module = new Module(filename, module.parent);
    sandbox.exports = sandbox.module.exports;
    sandbox.require = sandbox.module.require;
	Object.assign(sandbox, context);

    return vm.runInNewContext(content, sandbox, {filename: filename});
}

module.exports.eval = _eval;
<commit_msg>bug fix<commit_after>var through = require('through2');
var vm = require('vm');
var Module = require('module');

module.exports = function(context) {
	return through.obj(function(file, enc, next) {
		var fileContent = file.contents.toString(enc);
		file.data = _eval(fileContent, file.relative, context);
		next(null, file);
	});
};

function _eval(content, filename, context) {
    var sandbox = {};

    sandbox.module = new Module(filename, module.parent);
    sandbox.exports = sandbox.module.exports;
    sandbox.require = sandbox.module.require;
	Object.assign(sandbox, context);

    var res = vm.runInNewContext(content, sandbox, {filename: filename});
    return res || sandbox.module.exports;
}

module.exports.eval = _eval;
<|endoftext|>


<commit_before>var request = require('supertest');

module.exports = {
  register: function(app, machine, endpoint, key, existingToken) {
    return new Promise(function(resolve, reject) {
      var token;

      request(app)
      .post('/register')
      .send({
        token: existingToken,
        machineId: machine,
        endpoint: endpoint,
        key: key,
      })
      .expect(function(res) {
        token = res.body.token;
      })
      .end(function() {
        resolve(token);
      });
    });
  },
};
<commit_msg>Use a global afterEach to test that all nock requests have been made. Fixes #66<commit_after>var request = require('supertest');
var nock = require('nock');
var assert = require('assert');

afterEach(function() {
  assert(nock.isDone(), 'All requests have been made. Pending: ' + nock.pendingMocks());
});

module.exports = {
  register: function(app, machine, endpoint, key, existingToken) {
    return new Promise(function(resolve, reject) {
      var token;

      request(app)
      .post('/register')
      .send({
        token: existingToken,
        machineId: machine,
        endpoint: endpoint,
        key: key,
      })
      .expect(function(res) {
        token = res.body.token;
      })
      .end(function() {
        resolve(token);
      });
    });
  },
};
<|endoftext|>


<commit_before>context('Theme Switcher Shortcut', () => {
    before(() => {
        cy.login();
        cy.visit('/app');
    });
    beforeEach(() => {
        cy.reload();
    });
    it('Check Toggle', () => {
        cy.open_theme_dialog('{ctrl+shift+g}');
        cy.get('.modal-backdrop').should('exist');
        cy.get('.theme-grid > div').first().click();
        cy.close_theme('{ctrl+shift+g}');
        cy.get('.modal-backdrop').should('not.exist');
    });
    it('Check Enter', () => {
        cy.open_theme_dialog('{ctrl+shift+g}');
        cy.get('.theme-grid > div').first().click();
        cy.close_theme('{enter}');
        cy.get('.modal-backdrop').should('not.exist');
    });

});

Cypress.Commands.add('open_theme_dialog', (shortcut_keys) => {
    cy.get('body').type(shortcut_keys);
});
Cypress.Commands.add('close_theme', (shortcut_keys) => {
    cy.get('.modal-header').type(shortcut_keys);
});<commit_msg>chore: sider issues fixed<commit_after>context('Theme Switcher Shortcut', () => {
	before(() => {
		cy.login();
		cy.visit('/app');
	});
	beforeEach(() => {
		cy.reload();
	});
	it('Check Toggle', () => {
		cy.open_theme_dialog('{ctrl+shift+g}');
		cy.get('.modal-backdrop').should('exist');
		cy.get('.theme-grid > div').first().click();
		cy.close_theme('{ctrl+shift+g}');
		cy.get('.modal-backdrop').should('not.exist');
	});
	it('Check Enter', () => {
		cy.open_theme_dialog('{ctrl+shift+g}');
		cy.get('.theme-grid > div').first().click();
		cy.close_theme('{enter}');
		cy.get('.modal-backdrop').should('not.exist');
	});

});

Cypress.Commands.add('open_theme_dialog', (shortcut_keys) => {
	cy.get('body').type(shortcut_keys);
});
Cypress.Commands.add('close_theme', (shortcut_keys) => {
	cy.get('.modal-header').type(shortcut_keys);
});<|endoftext|>


<commit_before>'use strict';
const SpotifyWebApi = require('spotify-web-api-node');
const fs = require('fs');
const got = require('got');
const meow = require('meow');
const chalk = require('chalk');
const ora = require('ora');
const spinner = ora('Loading ...');

const singlespotify = async function singlespotify(inputs, flags) {

	spinner.start();

	// -a "Kanye West"
	const artistName = flags['a'];

	// -a "" evaluates to true
	if (artistName === true){
		spinner.fail('Failed');
		console.log(chalk.red(`
	Oops! That search didn't work. Try again please!
	`))
		return
	}

	// -c path/to/config.json
	const configFile = flags['c'];

	// get bearer token from path to config file
	try {
		var configJSON = JSON.parse(require('fs').readFileSync(configFile, 'utf8'));
	}
	catch(err) {
		spinner.fail('Failed');
		console.log(chalk.red(`
	Oops! That wasn't a valid config path. Try again please!

	See https://github.com/kabirvirji/singlespotify#usage for more information
	`))
		return
	}

	var tracks = [];
	var artists = [];

	const spotifyApi = new SpotifyWebApi();

	// get artist URI
	const artistSearch = await spotifyApi.searchArtists(artistName);
	// error check for invalid search
	if (artistSearch.body.artists.items[0] === undefined) {
		spinner.fail('Failed');
		console.log(chalk.red(`

	Oops! That search didn't work. Try again please!
	`))
		return
	}
	let artistURI = artistSearch.body.artists.items[0].uri;
	artistURI = artistURI.slice(15);

	// get artist top tracks
	let artistTopTracks = await spotifyApi.getArtistTopTracks(artistURI, 'CA');
	artistTopTracks = artistTopTracks.body.tracks;
	for (let artistTrack of artistTopTracks) {
		tracks.push(artistTrack.uri);
	}

	// get three related artists
	let relatedArtists = await spotifyApi.getArtistRelatedArtists(artistURI);
	relatedArtists = relatedArtists.body.artists;
	for (var i=0;i<3;i++){
		var currentArtist = relatedArtists[i].uri;
		artists.push(currentArtist.slice(15));
	}

	// add related artists top songs to tracks array
	let artistOne = await spotifyApi.getArtistTopTracks(artists[0], 'CA');
	artistOne = artistOne.body.tracks;
	for (var i=0;i<3;i++){
		tracks.push(artistOne[i].uri);
	}
	let artistTwo = await spotifyApi.getArtistTopTracks(artists[1], 'CA');
	artistTwo = artistTwo.body.tracks;
	for (var i=0;i<3;i++){
		tracks.push(artistTwo[i].uri);
	}
	let artistThree = await spotifyApi.getArtistTopTracks(artists[2], 'CA');
	artistThree = artistThree.body.tracks;
	for (var i=0;i<3;i++){
		tracks.push(artistThree[i].uri);
	}

	// create an empty public playlist
	var options = {
	  json: true,
	  headers: {
	    'Content-type': 'application/json',
	    'Authorization' : `Bearer ${configJSON.bearer}`,
	    'Accept' : 'application/json'
	  },
	  body: JSON.stringify({ name: `${artistName}: singlespotify`, public : true})
	};

	got.post(`https://api.spotify.com/v1/users/${configJSON.username}/playlists`, options)
	  .then(response => {
	    const playlistID = response.body.id;

			// function to add tracks to playlist
			function populatePlaylist (id, uris) {
				var url = `https://api.spotify.com/v1/users/${configJSON.username}/playlists/${id}/tracks?uris=${uris}`
				var options = {
				  json: true,
				  headers: {
				    'Content-type': 'application/json',
				    'Authorization' : `Bearer ${configJSON.bearer}`,
				  }
				};
				got.post(url, options)
				  .then(response => {
				  	spinner.succeed('Success!');
				    console.log(chalk.green(`
	Your playlist is ready!
	It's called "${artistName}: singlespotify"`));
				  })
				  .catch(err => {
				  	spinner.fail('Failed');
				  	console.log(chalk.red("There was an error adding songs to the playlist. Please try again."));
				  });
			}

			populatePlaylist(playlistID, tracks);

	  })

	  .catch(err => { spinner.fail('Failed');
	  	console.log(chalk.red(`
	ERROR: Please update your bearer token in your config.json

	Generate a new one at https://developer.spotify.com/web-api/console/post-playlists/`));

	  });

}
spinner.stop();
const cli = meow(chalk.cyan(`
    Usage
      $ singlespotify --artist [-a] "artist_name" --config [-c] /path/to/config.json

    Example
      $ singlespotify -a "Kanye West" -c /Users/kabirvirji/config.json

    For more information visit https://github.com/kabirvirji/singlespotify

`), {
    alias: {
        a: 'artist',
        c: 'config'
    }
}, [""]
);

singlespotify(cli.input[0], cli.flags);
<commit_msg>added local<commit_after>#!/usr/bin/env node
'use strict';
const SpotifyWebApi = require('spotify-web-api-node');
const fs = require('fs');
const got = require('got');
const meow = require('meow');
const chalk = require('chalk');
const ora = require('ora');
const spinner = ora('Loading ...');

const singlespotify = async function singlespotify(inputs, flags) {

	spinner.start();

	// -a "Kanye West"
	const artistName = flags['a'];

	// -a "" evaluates to true
	if (artistName === true){
		spinner.fail('Failed');
		console.log(chalk.red(`
	Oops! That search didn't work. Try again please!
	`))
		return
	}

	// -c path/to/config.json
	const configFile = flags['c'];

	// get bearer token from path to config file
	try {
		var configJSON = JSON.parse(require('fs').readFileSync(configFile, 'utf8'));
	}
	catch(err) {
		spinner.fail('Failed');
		console.log(chalk.red(`
	Oops! That wasn't a valid config path. Try again please!

	See https://github.com/kabirvirji/singlespotify#usage for more information
	`))
		return
	}

	var tracks = [];
	var artists = [];

	const spotifyApi = new SpotifyWebApi();

	// get artist URI
	const artistSearch = await spotifyApi.searchArtists(artistName);
	// error check for invalid search
	if (artistSearch.body.artists.items[0] === undefined) {
		spinner.fail('Failed');
		console.log(chalk.red(`

	Oops! That search didn't work. Try again please!
	`))
		return
	}
	let artistURI = artistSearch.body.artists.items[0].uri;
	artistURI = artistURI.slice(15);

	// get artist top tracks
	let artistTopTracks = await spotifyApi.getArtistTopTracks(artistURI, 'CA');
	artistTopTracks = artistTopTracks.body.tracks;
	for (let artistTrack of artistTopTracks) {
		tracks.push(artistTrack.uri);
	}

	// get three related artists
	let relatedArtists = await spotifyApi.getArtistRelatedArtists(artistURI);
	relatedArtists = relatedArtists.body.artists;
	for (var i=0;i<3;i++){
		var currentArtist = relatedArtists[i].uri;
		artists.push(currentArtist.slice(15));
	}

	// add related artists top songs to tracks array
	let artistOne = await spotifyApi.getArtistTopTracks(artists[0], 'CA');
	artistOne = artistOne.body.tracks;
	for (var i=0;i<3;i++){
		tracks.push(artistOne[i].uri);
	}
	let artistTwo = await spotifyApi.getArtistTopTracks(artists[1], 'CA');
	artistTwo = artistTwo.body.tracks;
	for (var i=0;i<3;i++){
		tracks.push(artistTwo[i].uri);
	}
	let artistThree = await spotifyApi.getArtistTopTracks(artists[2], 'CA');
	artistThree = artistThree.body.tracks;
	for (var i=0;i<3;i++){
		tracks.push(artistThree[i].uri);
	}

	// create an empty public playlist
	var options = {
	  json: true,
	  headers: {
	    'Content-type': 'application/json',
	    'Authorization' : `Bearer ${configJSON.bearer}`,
	    'Accept' : 'application/json'
	  },
	  body: JSON.stringify({ name: `${artistName}: singlespotify`, public : true})
	};

	got.post(`https://api.spotify.com/v1/users/${configJSON.username}/playlists`, options)
	  .then(response => {
	    const playlistID = response.body.id;

			// function to add tracks to playlist
			function populatePlaylist (id, uris) {
				var url = `https://api.spotify.com/v1/users/${configJSON.username}/playlists/${id}/tracks?uris=${uris}`
				var options = {
				  json: true,
				  headers: {
				    'Content-type': 'application/json',
				    'Authorization' : `Bearer ${configJSON.bearer}`,
				  }
				};
				got.post(url, options)
				  .then(response => {
				  	spinner.succeed('Success!');
				    console.log(chalk.green(`
	Your playlist is ready!
	It's called "${artistName}: singlespotify"`));
				  })
				  .catch(err => {
				  	spinner.fail('Failed');
				  	console.log(chalk.red("There was an error adding songs to the playlist. Please try again."));
				  });
			}

			populatePlaylist(playlistID, tracks);

	  })

	  .catch(err => { spinner.fail('Failed');
	  	console.log(chalk.red(`
	ERROR: Please update your bearer token in your config.json

	Generate a new one at https://developer.spotify.com/web-api/console/post-playlists/`));

	  });

}
spinner.stop();
const cli = meow(chalk.cyan(`
    Usage
      $ singlespotify --artist [-a] "artist_name" --config [-c] /path/to/config.json

    Example
      $ singlespotify -a "Kanye West" -c /Users/kabirvirji/config.json

    For more information visit https://github.com/kabirvirji/singlespotify

`), {
    alias: {
        a: 'artist',
        c: 'config'
    }
}, [""]
);

singlespotify(cli.input[0], cli.flags);
<|endoftext|>


<commit_before>define([
  'angular',
  'angular-route',
  '../util/index',
  './page/login',
  './directives/camIfLoggedIn',
  './directives/camIfLoggedOut',
  './service/authenticationService'
], function(
  angular,
  angularRoute,
  commonsUtil,
  loginPage,
  ifLoggedInDirective,
  ifLoggedOutDirective,
  authenticationService
) {
  'use strict';

  /**
   * @module cam.commons.auth
   */

  /**
   * @memberof cam.commons
   */

  var ngModule = angular.module('cam.commons.auth', [
    angular.module('ngRoute').name,
    commonsUtil.name
  ]);

  ngModule
    .config(loginPage)

    // redirect after login support
    .run([ '$rootScope', '$location', function($rootScope, $location) {

      var preLoginUrl;

      $rootScope.$on('authentication.login.required', function(event) {

        // skip if login is already in progress
        if (preLoginUrl) {
          return;
        }

        $rootScope.$evalAsync(function() {
          // skip if default got prevented
          if (!event.defaultPrevented) {
            preLoginUrl = $location.url();
            $location.url('/login');
          }
        });
      });

      $rootScope.$on('authentication.login.success', function(event) {

        $rootScope.$evalAsync(function() {
          // skip if default got prevented
          if (!event.defaultPrevented) {
            $location.url(preLoginUrl || '/').replace();
            preLoginUrl = null;
          }
        });
      });
    }])

    // post logout redirect + reload support
    .run([ '$cacheFactory', '$rootScope', '$location', function($cacheFactory, $rootScope, $location) {

      $rootScope.$on('authentication.logout.success', function(event) {

        $rootScope.$evalAsync(function() {
          // skip if default got prevented
          if (!event.defaultPrevented) {
            // clear http cache
            $cacheFactory.get('$http').removeAll();
            $location.url('/');
          }
        });
      });
    }])

    // notification integration
    .run([ '$rootScope', 'Notifications', function($rootScope, Notifications) {

      $rootScope.$on('authentication.login.required', function(event, route) {

        Notifications.addError({
          status: 'Unauthorized',
          message: 'Login is required to access the resource',
          http: true,
          exclusive: [ 'http' ]
        });
      });

    }])

    .run(['AuthenticationService', function(AuthenticationService) { } ])

    .directive('camIfLoggedIn', ifLoggedInDirective)
    .directive('camIfLoggedOut', ifLoggedOutDirective)

    .service('AuthenticationService', authenticationService);

  return ngModule;
});

<commit_msg>fix(auth): check login in progress asynchronously<commit_after>define([
  'angular',
  'angular-route',
  '../util/index',
  './page/login',
  './directives/camIfLoggedIn',
  './directives/camIfLoggedOut',
  './service/authenticationService'
], function(
  angular,
  angularRoute,
  commonsUtil,
  loginPage,
  ifLoggedInDirective,
  ifLoggedOutDirective,
  authenticationService
) {
  'use strict';

  /**
   * @module cam.commons.auth
   */

  /**
   * @memberof cam.commons
   */

  var ngModule = angular.module('cam.commons.auth', [
    angular.module('ngRoute').name,
    commonsUtil.name
  ]);

  ngModule
    .config(loginPage)

    // redirect after login support
    .run([ '$rootScope', '$location', function($rootScope, $location) {

      var preLoginUrl;

      $rootScope.$on('authentication.login.required', function(event) {

        $rootScope.$evalAsync(function() {
          // skip if login is already in progress
          // or default got prevented
          if (preLoginUrl || event.defaultPrevented) {
            return;
          }

          preLoginUrl = $location.url();
          $location.url('/login');
        });
      });

      $rootScope.$on('authentication.login.success', function(event) {

        $rootScope.$evalAsync(function() {
          // skip if default got prevented
          if (!event.defaultPrevented) {
            $location.url(preLoginUrl || '/').replace();
            preLoginUrl = null;
          }
        });
      });
    }])

    // post logout redirect + reload support
    .run([ '$cacheFactory', '$rootScope', '$location', function($cacheFactory, $rootScope, $location) {

      $rootScope.$on('authentication.logout.success', function(event) {

        $rootScope.$evalAsync(function() {
          // skip if default got prevented
          if (!event.defaultPrevented) {
            // clear http cache
            $cacheFactory.get('$http').removeAll();
            $location.url('/');
          }
        });
      });
    }])

    // notification integration
    .run([ '$rootScope', 'Notifications', function($rootScope, Notifications) {

      $rootScope.$on('authentication.login.required', function(event, route) {

        Notifications.addError({
          status: 'Unauthorized',
          message: 'Login is required to access the resource',
          http: true,
          exclusive: [ 'http' ]
        });
      });

    }])

    .run(['AuthenticationService', function(AuthenticationService) { } ])

    .directive('camIfLoggedIn', ifLoggedInDirective)
    .directive('camIfLoggedOut', ifLoggedOutDirective)

    .service('AuthenticationService', authenticationService);

  return ngModule;
});

<|endoftext|>


<commit_before>#! /usr/bin/env node
'use strict';

const program = require('commander');
const spotify = require('spotify-web-api-node');
const prompt = require('prompt');
const parseSearchResults = require('./parsers/');
const printer = require('./printers/');
const spotifyClient = require('./osascripts/');
const nconf = require('nconf');
const path = require('path');
const readlineSync = require('readline-sync');
const fetchLyrics = require('./fetch_lyrics').fetchLyrics;
const version = require('./package.json').version;
const semver = require('semver');
nconf.file(path.join(__dirname, '/config.json'));

// need client access token for genius
let lyricist = require('lyricist/node6');

let GENIUS_API_KEY = nconf.get('GeniusAPIClientKey');
let GENIUS_API_KEY_SET = GENIUS_API_KEY !== 'YOUR_CLIENT_ACCESS_TOKEN_HERE';
if(GENIUS_API_KEY_SET){
	lyricist = new lyricist(GENIUS_API_KEY);
}

let SPOTIFY_CLIENT_ID = nconf.get('spotifyClientID');
let SPOTIFY_CLIENT_ID_SET = SPOTIFY_CLIENT_ID !== 'YOUR_SPOTIFY_CLIENT_ID_HERE';
let SPOTIFY_CLIENT_SECRET = nconf.get('spotifyClientSecret');
let SPOTIFY_CLIENT_SECRET_SET = SPOTIFY_CLIENT_SECRET !== 'YOUR_SPOTIFY_CLIENT_SECRET_HERE';
let spotifyApi = null;

const initSpotifyApi = (client_id, client_secret) => {
	return new spotify({
		clientId : client_id,
		clientSecret : client_secret
	});
};

const setTokens = () => {
	let clientId = readlineSync.question('What is your Spotify Client ID? \n', { hideEchoBack: true });
	let clientSecret = readlineSync.question('What is your Spotify Client Secret? \n', { hideEchoBack: true });
	nconf.set('spotifyClientID', clientId);
	nconf.set('spotifyClientSecret', clientSecret);
	nconf.save();
	printer.printConfig();
};

if(SPOTIFY_CLIENT_ID_SET && SPOTIFY_CLIENT_SECRET_SET) {
	spotifyApi = initSpotifyApi(SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET);
}
else {
	setTokens();
	let SPOTIFY_CLIENT_ID = nconf.get('spotifyClientID');
	let SPOTIFY_CLIENT_SECRET = nconf.get('spotifyClientSecret');
	spotifyApi = initSpotifyApi(SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET);
	if (process.argv[2] === 'token' || process.argv[2] === 'reset' ) {
		 process.exit(0);
	}
}

const SearchOptions = {
	'track': {
		'fn': spotifyApi.searchTracks.bind(spotifyApi),
		'type': 'tracks'
	},
	't': {
		'fn': spotifyApi.searchTracks.bind(spotifyApi),
		'type': 'tracks'
	},
	'artist': {
		'fn': spotifyApi.searchArtists.bind(spotifyApi),
		'type': 'artists'
	},
	'ar': {
		'fn': spotifyApi.searchArtists.bind(spotifyApi),
		'type': 'artists'
	},
	'album': {
		'fn': spotifyApi.searchAlbums.bind(spotifyApi),
		'type': 'albums'
	},
	'al': {
		'fn': spotifyApi.searchAlbums.bind(spotifyApi),
		'type': 'albums'
	},
	'playlist': {
		'fn': spotifyApi.searchPlaylists.bind(spotifyApi),
		'type': 'playlists'
	},
	'p': {
		'fn': spotifyApi.searchPlaylists.bind(spotifyApi),
		'type': 'playlists'
	}
};

program
	.version(version)
	.command('search <type> [query...]')
	.description('Search for a <track (t) | artist (ar) | album (al) | playlist (p) > (searches tracks by default)')
	.alias('s')
	.action((type, query) => {
		// search for tracks by default
		var searchFn = SearchOptions['track'].fn;
		var searchQry = `${type} ${query.join(' ')}`;
		var resultType = SearchOptions['track'].type;

		if (SearchOptions[type]){
			searchFn = SearchOptions[type].fn;
			searchQry = query.join(' ');
			resultType = SearchOptions[type].type;
		}

		// Retrieve an access token.
		spotifyApi.clientCredentialsGrant()
			.then(function(data) {
				spotifyApi.setAccessToken(data.body['access_token']);
				searchFn(searchQry).then((data) => {
					var results = parseSearchResults(resultType, data);
					printer.printSearchResults(resultType, results);
					prompt.start();
					prompt.get(['selection'], function (err, result) {
						if (err) {
							return process.stdout.write('\n');
						}
						if(results[result.selection-1]){
							var selectedSpotifyURI = results[result.selection-1].spotifyURI;
							spotifyClient.play(selectedSpotifyURI).then(() => {
								spotifyClient.status().then((result) => {
									printer.printPlayerStatus(result);
								});
							});
						}
					});
				});
			}, function(err) {
				console.log('Something went wrong when retrieving an access token', err);
			});
	});

program
	.command('info')
	.alias('i')
	.description('Display information about the current track along with player status')
	.action(() => {
		spotifyClient.status().then((result) => {
			printer.printPlayerStatus(result);
		});
	});

program
	.command('play [uri]')
	.description('Continue playing current track or play the track with the provided URI')
	.action((uri) => {
		if(uri){
			spotifyClient.play(uri).then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
		else {
			spotifyClient.play().then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
	});

program
	.command('pause')
	.description('Pause the current track')
	.action(() => {
		spotifyClient.pause().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPlayerStatus(result);
			});
		});
	});

program
	.command('next')
	.alias('n')
	.description('Play the next track in the queue')
	.action(() => {
		spotifyClient.next().then(() => {
			spotifyClient.status().then((result) => {
				printer.printNext(result);
			});
		});
	});

program
	.command('back')
	.alias('b')
	.description('Play the previous track')
	.action(() => {
		spotifyClient.previous().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPrevious(result);
			});
		});
	});

program
	.command('mute')
	.alias('m')
	.description('Mute player')
	.action(() => {
		spotifyClient.mute().then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printMute(result);
			});
		});
	});

program
	.command('unmute')
	.alias('u')
	.description('Unmute player')
	.action(() => {
		spotifyClient.unmute().then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printUnmute(result);
			});
		});
	});

program
	.command('volume [newVolume]')
	.alias('v')
	.description('Display player volume')
	.action((newVolume) => {
		if(newVolume){
			spotifyClient.setVolume(newVolume).then(() => {
				spotifyClient.getVolume().then((result) => {
					printer.printSetVolume(result);
				});
			});
		}
		else {
			spotifyClient.getVolume().then(() => {
				spotifyClient.getVolume().then((result) => {
					printer.printVolume(result);
				});
			});
		}
	});
program
	.command('+ [deltaVolume]')
	.description('Turn the volume up by given amount (0-100), default:10')
	.action((deltaVolume) => {
		var changeInVolume = deltaVolume ? deltaVolume : 10;
		spotifyClient.changeVolume(changeInVolume).then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printVolumeIncrease(changeInVolume, result);
			});
		});
	});

program
	.command('- [deltaVolume]')
	.description('Turn the volume down by given amount (0-100), default:10')
	.action((deltaVolume) => {
		var changeInVolume = deltaVolume ? -deltaVolume : -10 ;
		spotifyClient.changeVolume(changeInVolume).then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printVolumeDecrease(changeInVolume, result);
			});
		});
	});

program
	.command('p')
	.description('Toggle play/pause')
	.action(() => {
		spotifyClient.togglePlayPause().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPlayerStatus(result);
			});
		});
	});

program
	.command('replay')
	.alias('r')
	.description('Replay current track')
	.action(() => {
		spotifyClient.replay().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPlayerStatus(result);
			});
		});
	});

program
	.command('position [newPosition]')
	.alias('pos')
	.description('Get or set player position [mm:ss], e.g: pos 1:23')
	.action((newPosition) => {
		if(newPosition){
			spotifyClient.setPosition(newPosition).then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
		else {
			spotifyClient.getPosition().then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
	});

program
	.command('quit')
	.alias('q')
	.description('Quit Spotify :(')
	.action(() =>{
		spotifyClient.quit();
	});

program
	.command('open')
	.alias('o')
	.description('Open Spotify :)')
	.action(() =>{
		spotifyClient.start();
	});

program
	.command('shuffle')
	.alias('ts')
	.description('Toggle shuffle on/off')
	.action(() => {
		spotifyClient.shuffle().then((status) => {
			printer.printToggleShuffle(status);
		});
	});

program
	.command('repeat')
	.alias('tr')
	.description('Toggle repeat on/off')
	.action(() => {
		spotifyClient.repeat().then((status) => {
			printer.printToggleRepeat(status);
		});
	});

program
	.command('share [type]')
	.alias('sh')
	.description('Display share <uri|url> and copy value to clipboard')
	.action((type) => {
		spotifyClient.share(type);
	});

program
	.command('token')
	.alias('tk')
	.description('Change Client Spotify tokens')
	.action(() => {
		setTokens();
	});
program
	.command('reset')
	.description('reset config back to default settings')
	.action(() => {
		nconf.set('spotifyClientID', 'YOUR_SPOTIFY_CLIENT_ID_HERE');
		nconf.set('spotifyClientSecret', 'YOUR_SPOTIFY_CLIENT_SECRET_HERE');
		nconf.save();
		printer.printConfig();
	});
program
	.command('lyrics')
	.alias('ly')
	.description('Display the lyrics of currently playing track')
	.action(() => {
		spotifyClient.status().then((trackInfo) => {
			if(!GENIUS_API_KEY_SET){
				console.log('You need to set the Client Access Token for Genius API.');
				console.log('Sign up for API access here: https://genius.com/api-clients');
				console.log('Update config.json file with your credentials');
				return;
			}
			fetchLyrics(lyricist, trackInfo.artist, trackInfo.track);
		});
	});

program
	.command('recommend')
	.alias('rec')
	.description('Recommend other songs based on the song currently playing.')
	.action(() => {
		spotifyApi.clientCredentialsGrant()
			.then(function(data) {
				spotifyApi.setAccessToken(data.body['access_token']);
				spotifyClient.getCurrentSongId().then((data) => {
					spotifyApi.getRecommendations({ seed_tracks: [data] }).then((response) => {
						// Assuming Spotify won't start recommending albums, artists, or playlists
						var results = parseSearchResults('tracks', response);
						printer.printSearchResults('tracks', results);
						prompt.start();
						prompt.get(['selection'], function (err, result) {
							if (err) {
								return process.stdout.write('\n');
							}
							if(results[result.selection-1]){
								var selectedSpotifyURI = results[result.selection-1].spotifyURI;
								spotifyClient.play(selectedSpotifyURI).then(() => {
									spotifyClient.status().then((result) => {
										printer.printPlayerStatus(result);
									});
								});
							}
						});
					});
				});
			}, function(err) {
				console.log('Something went wrong when retrieving an access token', err);
			});
	});

program.parse(process.argv);

/* CHECK Installed CLI version
 * */
let publishedVersion = require('child_process').execSync(`npm info spotify-cli-mac version`);
publishedVersion = publishedVersion.toString().trim().replace(/^\n*/, '').replace(/\n*$/, '');
if(semver.lt(version, semver.clean(publishedVersion))){
	console.log(`Your Spotify CLI is outdated. Latest version is ${publishedVersion}, you're on ${version}`);
	console.log(`Reinstall by doing:`);
	console.log(`npm uninstall -g spotify-cli-mac`);
	console.log(`npm install spotify-cli-mac -g\n`);
}
<commit_msg>fixes<commit_after>#! /usr/bin/env node
'use strict';

const program = require('commander');
const spotify = require('spotify-web-api-node');
const prompt = require('prompt');
const parseSearchResults = require('./parsers/');
const printer = require('./printers/');
const spotifyClient = require('./osascripts/');
const nconf = require('nconf');
const path = require('path');
const readlineSync = require('readline-sync');
const fetchLyrics = require('./fetch_lyrics').fetchLyrics;
const version = require('./package.json').version;
const semver = require('semver');
nconf.file(path.join(__dirname, '/config.json'));

// need client access token for genius
let lyricist = require('lyricist/node6');

let GENIUS_API_KEY = nconf.get('GeniusAPIClientKey');
let GENIUS_API_KEY_SET = GENIUS_API_KEY !== 'YOUR_CLIENT_ACCESS_TOKEN_HERE';
if(GENIUS_API_KEY_SET){
	lyricist = new lyricist(GENIUS_API_KEY);
}

let SPOTIFY_CLIENT_ID = nconf.get('spotifyClientID');
let SPOTIFY_CLIENT_ID_SET = SPOTIFY_CLIENT_ID !== 'YOUR_SPOTIFY_CLIENT_ID_HERE';
let SPOTIFY_CLIENT_SECRET = nconf.get('spotifyClientSecret');
let SPOTIFY_CLIENT_SECRET_SET = SPOTIFY_CLIENT_SECRET !== 'YOUR_SPOTIFY_CLIENT_SECRET_HERE';
let spotifyApi = null;

const initSpotifyApi = (client_id, client_secret) => {
	return new spotify({
		clientId : client_id,
		clientSecret : client_secret
	});
};

const setTokens = () => {
	let clientId = readlineSync.question('What is your Spotify Client ID? \n', { hideEchoBack: true });
	let clientSecret = readlineSync.question('What is your Spotify Client Secret? \n', { hideEchoBack: true });
	nconf.set('spotifyClientID', clientId);
	nconf.set('spotifyClientSecret', clientSecret);
	nconf.save();
	printer.printConfig();
};

if(SPOTIFY_CLIENT_ID_SET && SPOTIFY_CLIENT_SECRET_SET) {
	spotifyApi = initSpotifyApi(SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET);
}
else {
	if (process.argv[2] === 'reset') {
		printer.warning('Config file is already in default state.');
		process.exit(0);
	}
	setTokens();
	let SPOTIFY_CLIENT_ID = nconf.get('spotifyClientID');
	let SPOTIFY_CLIENT_SECRET = nconf.get('spotifyClientSecret');
	spotifyApi = initSpotifyApi(SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET);
	if (process.argv[2] === 'token' || process.argv[2] === 'reset') {
		process.exit(0);
	}
}

const SearchOptions = {
	'track': {
		'fn': spotifyApi.searchTracks.bind(spotifyApi),
		'type': 'tracks'
	},
	't': {
		'fn': spotifyApi.searchTracks.bind(spotifyApi),
		'type': 'tracks'
	},
	'artist': {
		'fn': spotifyApi.searchArtists.bind(spotifyApi),
		'type': 'artists'
	},
	'ar': {
		'fn': spotifyApi.searchArtists.bind(spotifyApi),
		'type': 'artists'
	},
	'album': {
		'fn': spotifyApi.searchAlbums.bind(spotifyApi),
		'type': 'albums'
	},
	'al': {
		'fn': spotifyApi.searchAlbums.bind(spotifyApi),
		'type': 'albums'
	},
	'playlist': {
		'fn': spotifyApi.searchPlaylists.bind(spotifyApi),
		'type': 'playlists'
	},
	'p': {
		'fn': spotifyApi.searchPlaylists.bind(spotifyApi),
		'type': 'playlists'
	}
};

program
	.version(version)
	.command('search <type> [query...]')
	.description('Search for a <track (t) | artist (ar) | album (al) | playlist (p) > (searches tracks by default)')
	.alias('s')
	.action((type, query) => {
		// search for tracks by default
		var searchFn = SearchOptions['track'].fn;
		var searchQry = `${type} ${query.join(' ')}`;
		var resultType = SearchOptions['track'].type;

		if (SearchOptions[type]){
			searchFn = SearchOptions[type].fn;
			searchQry = query.join(' ');
			resultType = SearchOptions[type].type;
		}

		// Retrieve an access token.
		spotifyApi.clientCredentialsGrant()
			.then(function(data) {
				spotifyApi.setAccessToken(data.body['access_token']);
				searchFn(searchQry).then((data) => {
					var results = parseSearchResults(resultType, data);
					printer.printSearchResults(resultType, results);
					prompt.start();
					prompt.get(['selection'], function (err, result) {
						if (err) {
							return process.stdout.write('\n');
						}
						if(results[result.selection-1]){
							var selectedSpotifyURI = results[result.selection-1].spotifyURI;
							spotifyClient.play(selectedSpotifyURI).then(() => {
								spotifyClient.status().then((result) => {
									printer.printPlayerStatus(result);
								});
							});
						}
					});
				});
			}, function(err) {
				console.log('Something went wrong when retrieving an access token', err);
			});
	});

program
	.command('info')
	.alias('i')
	.description('Display information about the current track along with player status')
	.action(() => {
		spotifyClient.status().then((result) => {
			printer.printPlayerStatus(result);
		});
	});

program
	.command('play [uri]')
	.description('Continue playing current track or play the track with the provided URI')
	.action((uri) => {
		if(uri){
			spotifyClient.play(uri).then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
		else {
			spotifyClient.play().then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
	});

program
	.command('pause')
	.description('Pause the current track')
	.action(() => {
		spotifyClient.pause().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPlayerStatus(result);
			});
		});
	});

program
	.command('next')
	.alias('n')
	.description('Play the next track in the queue')
	.action(() => {
		spotifyClient.next().then(() => {
			spotifyClient.status().then((result) => {
				printer.printNext(result);
			});
		});
	});

program
	.command('back')
	.alias('b')
	.description('Play the previous track')
	.action(() => {
		spotifyClient.previous().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPrevious(result);
			});
		});
	});

program
	.command('mute')
	.alias('m')
	.description('Mute player')
	.action(() => {
		spotifyClient.mute().then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printMute(result);
			});
		});
	});

program
	.command('unmute')
	.alias('u')
	.description('Unmute player')
	.action(() => {
		spotifyClient.unmute().then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printUnmute(result);
			});
		});
	});

program
	.command('volume [newVolume]')
	.alias('v')
	.description('Display player volume')
	.action((newVolume) => {
		if(newVolume){
			spotifyClient.setVolume(newVolume).then(() => {
				spotifyClient.getVolume().then((result) => {
					printer.printSetVolume(result);
				});
			});
		}
		else {
			spotifyClient.getVolume().then(() => {
				spotifyClient.getVolume().then((result) => {
					printer.printVolume(result);
				});
			});
		}
	});
program
	.command('+ [deltaVolume]')
	.description('Turn the volume up by given amount (0-100), default:10')
	.action((deltaVolume) => {
		var changeInVolume = deltaVolume ? deltaVolume : 10;
		spotifyClient.changeVolume(changeInVolume).then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printVolumeIncrease(changeInVolume, result);
			});
		});
	});

program
	.command('- [deltaVolume]')
	.description('Turn the volume down by given amount (0-100), default:10')
	.action((deltaVolume) => {
		var changeInVolume = deltaVolume ? -deltaVolume : -10 ;
		spotifyClient.changeVolume(changeInVolume).then(() => {
			spotifyClient.getVolume().then((result) => {
				printer.printVolumeDecrease(changeInVolume, result);
			});
		});
	});

program
	.command('p')
	.description('Toggle play/pause')
	.action(() => {
		spotifyClient.togglePlayPause().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPlayerStatus(result);
			});
		});
	});

program
	.command('replay')
	.alias('r')
	.description('Replay current track')
	.action(() => {
		spotifyClient.replay().then(() => {
			spotifyClient.status().then((result) => {
				printer.printPlayerStatus(result);
			});
		});
	});

program
	.command('position [newPosition]')
	.alias('pos')
	.description('Get or set player position [mm:ss], e.g: pos 1:23')
	.action((newPosition) => {
		if(newPosition){
			spotifyClient.setPosition(newPosition).then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
		else {
			spotifyClient.getPosition().then(() => {
				spotifyClient.status().then((result) => {
					printer.printPlayerStatus(result);
				});
			});
		}
	});

program
	.command('quit')
	.alias('q')
	.description('Quit Spotify :(')
	.action(() =>{
		spotifyClient.quit();
	});

program
	.command('open')
	.alias('o')
	.description('Open Spotify :)')
	.action(() =>{
		spotifyClient.start();
	});

program
	.command('shuffle')
	.alias('ts')
	.description('Toggle shuffle on/off')
	.action(() => {
		spotifyClient.shuffle().then((status) => {
			printer.printToggleShuffle(status);
		});
	});

program
	.command('repeat')
	.alias('tr')
	.description('Toggle repeat on/off')
	.action(() => {
		spotifyClient.repeat().then((status) => {
			printer.printToggleRepeat(status);
		});
	});

program
	.command('share [type]')
	.alias('sh')
	.description('Display share <uri|url> and copy value to clipboard')
	.action((type) => {
		spotifyClient.share(type);
	});

program
	.command('token')
	.alias('tk')
	.description('Change Client Spotify tokens')
	.action(() => {
		setTokens();
	});

program
	.command('reset')
	.description('reset config back to default settings')
	.action(() => {
		nconf.set('spotifyClientID', 'YOUR_SPOTIFY_CLIENT_ID_HERE');
		nconf.set('spotifyClientSecret', 'YOUR_SPOTIFY_CLIENT_SECRET_HERE');
		nconf.save();
		printer.printConfig();
	});

program
	.command('lyrics')
	.alias('ly')
	.description('Display the lyrics of currently playing track')
	.action(() => {
		spotifyClient.status().then((trackInfo) => {
			if(!GENIUS_API_KEY_SET){
				console.log('You need to set the Client Access Token for Genius API.');
				console.log('Sign up for API access here: https://genius.com/api-clients');
				console.log('Update config.json file with your credentials');
				return;
			}
			fetchLyrics(lyricist, trackInfo.artist, trackInfo.track);
		});
	});

program
	.command('recommend')
	.alias('rec')
	.description('Recommend other songs based on the song currently playing.')
	.action(() => {
		spotifyApi.clientCredentialsGrant()
			.then(function(data) {
				spotifyApi.setAccessToken(data.body['access_token']);
				spotifyClient.getCurrentSongId().then((data) => {
					spotifyApi.getRecommendations({ seed_tracks: [data] }).then((response) => {
						// Assuming Spotify won't start recommending albums, artists, or playlists
						var results = parseSearchResults('tracks', response);
						printer.printSearchResults('tracks', results);
						prompt.start();
						prompt.get(['selection'], function (err, result) {
							if (err) {
								return process.stdout.write('\n');
							}
							if(results[result.selection-1]){
								var selectedSpotifyURI = results[result.selection-1].spotifyURI;
								spotifyClient.play(selectedSpotifyURI).then(() => {
									spotifyClient.status().then((result) => {
										printer.printPlayerStatus(result);
									});
								});
							}
						});
					});
				});
			}, function(err) {
				console.log('Something went wrong when retrieving an access token', err);
			});
	});

program.parse(process.argv);

/* CHECK Installed CLI version
 * */
let publishedVersion = require('child_process').execSync(`npm info spotify-cli-mac version`);
publishedVersion = publishedVersion.toString().trim().replace(/^\n*/, '').replace(/\n*$/, '');
if(semver.lt(version, semver.clean(publishedVersion))){
	console.log(`Your Spotify CLI is outdated. Latest version is ${publishedVersion}, you're on ${version}`);
	console.log(`Reinstall by doing:`);
	console.log(`npm uninstall -g spotify-cli-mac`);
	console.log(`npm install spotify-cli-mac -g\n`);
}
<|endoftext|>


<commit_before>// START HEROKU SETUP
var express = require("express");
var app = express();
app.get('/', function(req, res) {
  res.send('
The robot is anxiously running.
');
});
app.listen(process.env.PORT || 5000);
// END HEROKU SETUP

// LISTBOT

// Config.keys uses environment variables so sensitive info is not in the repo.
var config = {
  me: 'itmepinkbathrom', // The authorized account with a list to retweet.
  myList: 'beef', // The list we want to retweet.
  regexFilter: '(elinabloom||allieegraham)', // Accept only tweets matching this regex pattern.
  regexReject: 'RT', // AND reject any tweets matching this regex pattern.

  keys: {
    consumer_key: process.env.TWITTER_CONSUMER_KEY,
    consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
    access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
    access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
  }
};

// Get the members of our list, and pass them into a callback function.
function getListMembers(callback) {
  var memberIDs = [];

  tu.listMembers(
    {
      owner_screen_name: config.me,
      slug: config.myList
    },

    function(error, data){
      if (!error) {
        for (var i = 0; i < data.users.length; i++) {
          memberIDs.push(data.users[i].id_str);
        };

        // This callback is designed to run listen(memberIDs).
        callback(memberIDs);
      } else {
        console.log(error);
        console.log(data);
      };
    };
  );
};

// What to do after we retweet something.
function onReTweet(err) {
    if(err) {
        console.error("retweeting failed :(");
        console.error(err);
    }
}

// What to do when we get a tweet.
function onTweet(tweet) {
    // Reject the tweet if:
    //  1. it's flagged as a retweet
    //  2. it matches our regex rejection criteria
    //  3. it doesn't match our regex acceptance filter
    var regexReject = new RegExp(config.regexReject, 'i');
    var regexFilter = new RegExp(config.regexFilter, 'i');
    if (tweet.retweeted) {
        return;
    }
    if (config.regexReject !== '' && regexReject.test(tweet.text)) {
        return;
    }
    if (regexFilter.test(tweet.text)) {
        console.log(tweet);
        console.log("RT: " + tweet.text);
        // Note we're using the id_str property since javascript is not accurate
        // for 64bit ints.
        tu.retweet({
            id: tweet.id_str
        }, onReTweet);
    }
}

// Function for listening to twitter streams and retweeting on demand.
function listen(listMembers) {
    tu.filter({
        follow: listMembers
    }, function(stream) {
        console.log("listening to stream");
        stream.on('tweet', onTweet);
    });
}

// The application itself.
// Use the tuiter node module to get access to twitter.
var tu = require('tuiter')(config.keys);

// Run the application. The callback in getListMembers ensures we get our list
// of twitter streams before we attempt to listen to them via the twitter API.
getListMembers(listen);
<commit_msg>Fix semicolon<commit_after>// START HEROKU SETUP
var express = require("express");
var app = express();
app.get('/', function(req, res) {
  res.send('
The robot is anxiously running.
');
});
app.listen(process.env.PORT || 5000);
// END HEROKU SETUP

// LISTBOT

// Config.keys uses environment variables so sensitive info is not in the repo.
var config = {
  me: 'itmepinkbathrom', // The authorized account with a list to retweet.
  myList: 'beef', // The list we want to retweet.
  regexFilter: '(elinabloom||allieegraham)', // Accept only tweets matching this regex pattern.
  regexReject: 'RT', // AND reject any tweets matching this regex pattern.

  keys: {
    consumer_key: process.env.TWITTER_CONSUMER_KEY,
    consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
    access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
    access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
  }
};

// Get the members of our list, and pass them into a callback function.
function getListMembers(callback) {
  var memberIDs = [];

  tu.listMembers(
    {
      owner_screen_name: config.me,
      slug: config.myList
    },

    function(error, data){
      if (!error) {
        for (var i = 0; i < data.users.length; i++) {
          memberIDs.push(data.users[i].id_str);
        };

        // This callback is designed to run listen(memberIDs).
        callback(memberIDs);
      } else {
        console.log(error);
        console.log(data);
      };
    }
  );
};

// What to do after we retweet something.
function onReTweet(err) {
    if(err) {
        console.error("retweeting failed :(");
        console.error(err);
    }
}

// What to do when we get a tweet.
function onTweet(tweet) {
    // Reject the tweet if:
    //  1. it's flagged as a retweet
    //  2. it matches our regex rejection criteria
    //  3. it doesn't match our regex acceptance filter
    var regexReject = new RegExp(config.regexReject, 'i');
    var regexFilter = new RegExp(config.regexFilter, 'i');
    if (tweet.retweeted) {
        return;
    }
    if (config.regexReject !== '' && regexReject.test(tweet.text)) {
        return;
    }
    if (regexFilter.test(tweet.text)) {
        console.log(tweet);
        console.log("RT: " + tweet.text);
        // Note we're using the id_str property since javascript is not accurate
        // for 64bit ints.
        tu.retweet({
            id: tweet.id_str
        }, onReTweet);
    }
}

// Function for listening to twitter streams and retweeting on demand.
function listen(listMembers) {
    tu.filter({
        follow: listMembers
    }, function(stream) {
        console.log("listening to stream");
        stream.on('tweet', onTweet);
    });
}

// The application itself.
// Use the tuiter node module to get access to twitter.
var tu = require('tuiter')(config.keys);

// Run the application. The callback in getListMembers ensures we get our list
// of twitter streams before we attempt to listen to them via the twitter API.
getListMembers(listen);
<|endoftext|>