<commit_before>(function() {
    var app = angular.module('scrumstory', ['ui.bootstrap', 'ui.router']);
    app.run(
        ['$rootScope', '$state',
            function($rootScope, $state) {
               $rootScope.isTemplateSelected = function(template)
                {
                	return $state.includes(template);

                }
                $rootScope.roles = ['user', 'developer', 'end-user', 'admin', 'teacher',
                 'engineer', 'artist', 'PO', 'manager', 'doctor', 'vendor', 'scientist',
                 'contractor','client','customer','geek','hacker','CEO','cashier','journalist'];

            }
        ])
    app.config(function($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/template1")
        $stateProvider.state('template1', {
            url: "/template1",
            templateUrl: "views/template1.html",
            controller: function($scope) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
                $scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.goal && $scope.story.benefit) {
                        $scope.finalText = "As a " + $scope.story.role + ", I want " + $scope.story.goal + ", so that " + $scope.story.benefit;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.role && $scope.story.goal && $scope.story.benefit);
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        }).state('template2', {
            url: "/template2",
            templateUrl: "views/template2.html",
            controller: function($scope) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
              	$scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.goal) {
                        $scope.finalText = "As a " + $scope.story.role + ", I want " + $scope.story.goal;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.role && $scope.story.goal);
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        }).state('template3', {
            url: "/template3",
            templateUrl: "views/template3.html",
            controller: function($scope) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
                $scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.goal && $scope.story.benefit) {
                        $scope.finalText = "In order to " + $scope.story.benefit + " as a " + $scope.story.role + ", I want " + $scope.story.goal;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.benefit && $scope.story.role && $scope.story.goal);
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        }).state('template4', {
            url: "/template4",
            templateUrl: "views/template4.html",
            controller: function($scope) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
                $scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.when && $scope.story.where && $scope.story.what && $scope.story.why ) {
                        $scope.finalText = "As " + $scope.story.role +" " +$scope.story.when +" " + $scope.story.where + ", I " + $scope.story.what + " because " + $scope.story.why;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.role && $scope.story.when && $scope.story.where && $scope.story.what && $scope.story.why );
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        })
    });
    app.directive('autoSelect', function($parse) {
        return {
            link: function(scope, element, attrs) {
                var model = $parse(attrs.autoSelect);
                scope.$watch(model, function(value) {
                    if (value === true) {
                        element[0].select();
                    }
                });
            }
        };
    });
})();<commit_msg>added factory method for roles<commit_after>(function() {
    var app = angular.module('scrumstory', ['ui.bootstrap', 'ui.router']);
    app.run(
        ['$rootScope', '$state',
            function($rootScope, $state) {
               $rootScope.isTemplateSelected = function(template)
                {
                	return $state.includes(template);

                }
              //  $rootScope.roles = ['user', 'developer', 'end-user', 'admin', 'teacher',
              //   'engineer', 'artist', 'PO', 'manager', 'doctor', 'vendor', 'scientist',
              //   'contractor','client','customer','geek','hacker','CEO','cashier','journalist'];

            }
        ]);

    app.factory('Roles',function()
    {
        var Roles = {};
        Roles.roles = ['user', 'developer', 'end-user', 'admin', 'teacher',
                 'engineer', 'artist', 'PO', 'manager', 'doctor', 'vendor', 'scientist',
                 'contractor','client','customer','geek','hacker','CEO','cashier','journalist'];
        return Roles;
    });
    app.config(function($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/template1")
        $stateProvider.state('template1', {
            url: "/template1",
            templateUrl: "views/template1.html",
            controller: function($scope,Roles) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
                $scope.roles = Roles.roles;

                $scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.goal && $scope.story.benefit) {
                        $scope.finalText = "As a " + $scope.story.role + ", I want " + $scope.story.goal + ", so that " + $scope.story.benefit;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.role && $scope.story.goal && $scope.story.benefit);
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        }).state('template2', {
            url: "/template2",
            templateUrl: "views/template2.html",
            controller: function($scope,Roles) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
                $scope.roles = Roles;

              	$scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.goal) {
                        $scope.finalText = "As a " + $scope.story.role + ", I want " + $scope.story.goal;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.role && $scope.story.goal);
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        }).state('template3', {
            url: "/template3",
            templateUrl: "views/template3.html",
            controller: function($scope,Roles) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
                $scope.roles = Roles;

                $scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.goal && $scope.story.benefit) {
                        $scope.finalText = "In order to " + $scope.story.benefit + " as a " + $scope.story.role + ", I want " + $scope.story.goal;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.benefit && $scope.story.role && $scope.story.goal);
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        }).state('template4', {
            url: "/template4",
            templateUrl: "views/template4.html",
            controller: function($scope,Roles) {
                $scope.story = {};
                $scope.blockquoteHide = false;
                $scope.finalText = "";
                $scope.finalTextShow = false;
                $scope.roles = Roles;

                $scope.storyReady = function() {
                    if ($scope.story.role && $scope.story.when && $scope.story.where && $scope.story.what && $scope.story.why ) {
                        $scope.finalText = "As " + $scope.story.role +" " +$scope.story.when +" " + $scope.story.where + ", I " + $scope.story.what + " because " + $scope.story.why;
                        $scope.blockquoteHide = true;
                        $scope.finalTextShow = true;
                    }
                }
                $scope.reset = function() {
                    $scope.story = {};
                    $scope.blockquoteHide = false;
                    $scope.finalText = "";
                    $scope.finalTextShow = false;
                }
                $scope.isDisable = function() {
                    return !($scope.story.role && $scope.story.when && $scope.story.where && $scope.story.what && $scope.story.why );
                }
                $scope.highlightMe = function($event) {
                    $event.target.select();
                }
            }
        })
    });
    app.directive('autoSelect', function($parse) {
        return {
            link: function(scope, element, attrs) {
                var model = $parse(attrs.autoSelect);
                scope.$watch(model, function(value) {
                    if (value === true) {
                        element[0].select();
                    }
                });
            }
        };
    });
})();<|endoftext|>


<commit_before>module.exports = {
	'env': {
		'es6': true
	},

	'parserOptions': {
		'sourceType': 'module',
		'ecmaFeatures': {
			'experimentalObjectRestSpread': true,
			'jsx': true
		}
	},

	'plugins': [
		'react'
	],

	'rules': {
		'jsx-uses-react': 2,
		'jsx-uses-vars': 2,
		'jsx-curly-spacing': [2, 'never'],
		'jsx-indent': [2, 'tab'],
		'jsx-indent-props': [2, 'tab'],
		'jsx-key': 2,
		'jsx-equals-spacing': [2, 'never'],
		'jsx-no-undef': 2,
		'jsx-no-duplicate-props': 2,
		'jsx-no-literals': 2,
		'jsx-closing-bracket-location': 2,
		'jsx-pascal-case': 2,
		'jsx-space-before-closing': [2, 'always'],
		'jsx-sort-props': [2, {'ignoreCase': true}],
		'no-multi-comp': [2, {'ignoreStateless': true}],
		'wrap-multilines': [2/*, {'ignoreStateless': true}*/],
		'no-unknown-property': 2,
		'sort-comp': [0, {
			order: [
				'static-methods',
				'lifecycle',
				'everything-else',
				'render'
			],
			groups: {
				lifecycle: [
					'constructor',
					'displayName',
					'mixins',
					'propTypes',
					'statics',
					'defaultProps',
					'getDefaultProps',
					'getInitialState',
					'state',
					'componentWillMount',
					'componentDidMount',
					'componentWillReceiveProps',
					'componentWillUpdate',
					'componentDidUpdate',
					'componentWillUnmount',
					'shouldComponentUpdate',
					'getChildContext',
					'childContextTypes',
					'contextTypes',
				]
			}
		}],

		'prop-types': 0,
		'display-name': 0,
		'no-danger': 0,
		'no-set-state': 0,
		'no-is-mounted': 0,
		'no-deprecated': 0,
		'no-did-mount-set-state': 0,
		'no-did-update-set-state': 0,
		'react-in-jsx-scope': 0,
		'jsx-handler-names': 0,
		'jsx-boolean-value': 0,
		'require-extension': 0,
		'jsx-max-props-per-line': 0,
		'no-string-refs': 0,
		'prefer-stateless-function': 0,

		'require-render-return': 2,
		'jsx-first-prop-new-line': [2, 'multiline'],
		'self-closing-comp': 2,
		'sort-prop-types': 2,
		'no-direct-mutation-state': 2,

		'forbid-prop-types': 0,
		'jsx-no-bind': 0,
		'prefer-es6-class': 0,

		'arrow-body-style': [0, 'as-needed'],
		'arrow-parens': [2, 'as-needed'],
		'object-shorthand': [2, 'always', {'ignoreConstructors': true}],
		'prefer-arrow-callback': [2, {'allowNamedFunctions': true}],
		'no-new-symbol': 2,
		'prefer-const': 2,
		'prefer-rest-params': 2,
		'prefer-spread': 2,
		'prefer-template': 2
	}
};<commit_msg>Warn when creating functions in the render method<commit_after>module.exports = {
	'env': {
		'es6': true
	},

	'parserOptions': {
		'sourceType': 'module',
		'ecmaFeatures': {
			'experimentalObjectRestSpread': true,
			'jsx': true
		}
	},

	'plugins': [
		'react'
	],

	'rules': {
		'jsx-uses-react': 2,
		'jsx-uses-vars': 2,
		'jsx-curly-spacing': [2, 'never'],
		'jsx-indent': [2, 'tab'],
		'jsx-indent-props': [2, 'tab'],
		'jsx-key': 2,
		'jsx-equals-spacing': [2, 'never'],
		'jsx-no-undef': 2,
		'jsx-no-duplicate-props': 2,
		'jsx-no-literals': 2,
		'jsx-closing-bracket-location': 2,
		'jsx-pascal-case': 2,
		'jsx-space-before-closing': [2, 'always'],
		'jsx-sort-props': [2, {'ignoreCase': true}],
		'no-multi-comp': [2, {'ignoreStateless': true}],
		'wrap-multilines': [2/*, {'ignoreStateless': true}*/],
		'no-unknown-property': 2,
		'sort-comp': [0, {
			order: [
				'static-methods',
				'lifecycle',
				'everything-else',
				'render'
			],
			groups: {
				lifecycle: [
					'constructor',
					'displayName',
					'mixins',
					'propTypes',
					'statics',
					'defaultProps',
					'getDefaultProps',
					'getInitialState',
					'state',
					'componentWillMount',
					'componentDidMount',
					'componentWillReceiveProps',
					'componentWillUpdate',
					'componentDidUpdate',
					'componentWillUnmount',
					'shouldComponentUpdate',
					'getChildContext',
					'childContextTypes',
					'contextTypes',
				]
			}
		}],

		'prop-types': 0,
		'display-name': 0,
		'no-danger': 0,
		'no-set-state': 0,
		'no-is-mounted': 0,
		'no-deprecated': 0,
		'no-did-mount-set-state': 0,
		'no-did-update-set-state': 0,
		'react-in-jsx-scope': 0,
		'jsx-handler-names': 0,
		'jsx-boolean-value': 0,
		'require-extension': 0,
		'jsx-max-props-per-line': 0,
		'no-string-refs': 0,
		'prefer-stateless-function': 0,

		'require-render-return': 2,
		'jsx-first-prop-new-line': [2, 'multiline'],
		'self-closing-comp': 2,
		'sort-prop-types': 2,
		'no-direct-mutation-state': 2,

		'forbid-prop-types': 0,
		'jsx-no-bind': 2,
		'prefer-es6-class': 0,

		'arrow-body-style': [0, 'as-needed'],
		'arrow-parens': [2, 'as-needed'],
		'object-shorthand': [2, 'always', {'ignoreConstructors': true}],
		'prefer-arrow-callback': [2, {'allowNamedFunctions': true}],
		'no-new-symbol': 2,
		'prefer-const': 2,
		'prefer-rest-params': 2,
		'prefer-spread': 2,
		'prefer-template': 2
	}
};<|endoftext|>


<commit_before><commit_msg>meetings: shortening meeting time strings<commit_after><|endoftext|>


<commit_before>import http from 'http'
import https from 'https'
import s3 from 's3'
import fs from 'fs'
import path from 'path'
import ProgressBar from 'progress'
import cdnizer from 'cdnizer'
import _ from 'lodash'
import aws from 'aws-sdk'

import {
  addSeperatorToPath,
  getDirectoryFilesRecursive,
  UPLOAD_IGNORES,
  DEFAULT_UPLOAD_OPTIONS,
  DEFAULT_S3_OPTIONS,
  REQUIRED_S3_OPTS,
  REQUIRED_S3_UP_OPTS,
  PATH_SEP,
  DEFAULT_TRANSFORM,
} from './helpers'

http.globalAgent.maxSockets = https.globalAgent.maxSockets = 50

var compileError = function(compilation, error) {
  compilation.errors.push(new Error(error))
}

module.exports = class S3Plugin {
  constructor(options = {}) {
    var {
      include,
      exclude,
      basePath,
      directory,
      htmlFiles,
      basePathTransform = DEFAULT_TRANSFORM,
      s3Options = {},
      cdnizerOptions = {},
      s3UploadOptions = {},
      cloudfrontInvalidateOptions = {}
    } = options

    this.uploadOptions = s3UploadOptions
    this.cloudfrontInvalidateOptions = cloudfrontInvalidateOptions
    this.isConnected = false
    this.cdnizerOptions = cdnizerOptions
    this.urlMappings = []
    this.uploadTotal = 0
    this.uploadProgress = 0
    this.basePathTransform = basePathTransform
    basePath = basePath ? basePath.replace(/\/?(\?|#|$)/, '/$1') : ''

    this.options = {
      directory,
      include,
      exclude,
      basePath,
      htmlFiles: typeof htmlFiles === 'string' ? [htmlFiles] : htmlFiles
    }

    this.clientConfig = {
      maxAsyncS3: 50,
      s3Options: _.merge({}, DEFAULT_S3_OPTIONS, s3Options)
    }

    this.noCdnizer = !Object.keys(this.cdnizerOptions).length

    if (!this.noCdnizer && !this.cdnizerOptions.files)
      this.cdnizerOptions.files = []
  }

  apply(compiler) {
    this.connect()

    var isDirectoryUpload = !!this.options.directory,
        hasRequiredOptions = this.client.s3.config.credentials !== null,
        hasRequiredUploadOpts = _.every(REQUIRED_S3_UP_OPTS, type => this.uploadOptions[type])

    // Set directory to output dir or custom
    this.options.directory = this.options.directory || compiler.options.output.path || compiler.options.output.context || '.'

    compiler.plugin('after-emit', (compilation, cb) => {
      if (!hasRequiredOptions) {
        compileError(compilation, `S3Plugin: Must provide ${REQUIRED_S3_OPTS.join(', ')}`)
        cb()
      }

      if (!hasRequiredUploadOpts) {
        compileError(compilation, `S3Plugin-RequiredS3UploadOpts: ${REQUIRED_S3_UP_OPTS.join(', ')}`)
        cb()
      }

      if (isDirectoryUpload) {
        let dPath = addSeperatorToPath(this.options.directory)

        this.getAllFilesRecursive(dPath)
          .then((files) => this.handleFiles(files))
          .then(() => cb())
          .catch(e => {
            compileError(compilation, `S3Plugin: ${e}`)
            cb()
          })
      } else {
        this.getAssetFiles(compilation)
          .then((files) => this.handleFiles(files))
          .then(() => cb())
          .catch(e => {
            compileError(compilation, `S3Plugin: ${e}`)
            cb()
          })
      }
    })
  }

  handleFiles(files) {
    return this.changeUrls(files)
      .then((files) => this.uploadFiles(files))
      .then(() => this.invalidateCloudfront())
  }

  getAllFilesRecursive(fPath) {
    return getDirectoryFilesRecursive(fPath)
      .then((files) => this.filterAllowedFiles(files))
  }

  addPathToFiles(files, fPath) {
    return files.map(file => ({name: file, path: path.resolve(fPath, file)}))
  }

  getFileName(file = '') {
    return _.includes(file, PATH_SEP) ? file.substring(_.lastIndexOf(file, PATH_SEP) + 1) : file
  }

  getAssetFiles({assets}) {
    var files = _.map(assets, (value, name) => ({name, path: value.existsAt}))

    return Promise.resolve(this.filterAllowedFiles(files))
  }

  cdnizeHtml(file) {
    return new Promise((resolve, reject) => {
      fs.readFile(file.path, (err, data) => {
        if (err)
          return reject(err)

        fs.writeFile(file.path, this.cdnizer(data.toString()), (err) => {
          if (err)
            return reject(err)

          resolve(file)
        })
      })
    })
  }

  changeUrls(files = []) {
    if (this.noCdnizer)
      return Promise.resolve(files)

    var allHtml,
        {directory, htmlFiles = []} = this.options

    allHtml = htmlFiles.length ? this.addPathToFiles(htmlFiles, directory).concat(files) : files
    this.cdnizerOptions.files = allHtml.map(({name}) => `*${name}*`)
    this.cdnizer = cdnizer(this.cdnizerOptions)

    var [cdnizeFiles, otherFiles] = _(allHtml)
      .uniq('name')
      .partition((file) => /\.(html)/.test(file.name)) // |css - Add when cdnize css is done
      .value()

    return Promise.all(cdnizeFiles.map(file => this.cdnizeHtml(file)).concat(otherFiles))
  }

  // For future implimentation
  // changeCssUrls(files = []) {
  //   if (this.noCdnizer)
  //     return Promise.resolve(files)

  //   data.replace(/url\(\/images/g, `url(${imagePath}`)

  //   return this.cdnizeCss(cssFile2, imagePath, files)
  // }

  filterAllowedFiles(files) {
    return files.reduce((res, file) => {
      if (this.isIncludeAndNotExclude(file.name) && !this.isIgnoredFile(file.name))
        res.push(file)

      return res
    }, [])
  }

  isIgnoredFile(file) {
    return _.some(UPLOAD_IGNORES, ignore => new RegExp(ignore).test(file))
  }

  isIncludeAndNotExclude(file) {
    var isExclude,
        isInclude,
        {include, exclude} = this.options

    isInclude = include ? include.test(file) : true
    isExclude = exclude ? exclude.test(file) : false

    return isInclude && !isExclude
  }

  connect() {
    if (this.isConnected)
      return

    this.client = s3.createClient(this.clientConfig)
    this.isConnected = true
  }

  transformBasePath() {
    return Promise.resolve(this.basePathTransform(this.options.basePath))
      .then(nPath => this.options.basePath = addSeperatorToPath(nPath))
  }

  setupProgressBar(uploadFiles) {
    var progressAmount = Array(uploadFiles.length)
    var progressTotal = Array(uploadFiles.length)
    var countUndefined = (array) => _.reduce(array, (res, value) => res += _.isUndefined(value) ? 1 : 0, 0)
    var calculateProgress = () => _.sum(progressAmount) / _.sum(progressTotal)
    var progressTracker = 0

    var progressBar = new ProgressBar('Uploading [:bar] :percent :etas', {
      complete: '>',
      incomplete: '∆',
      total: 100
    })

    uploadFiles.forEach(function({upload}, i) {
      upload.on('progress', function() {
        var definedModifier,
            progressValue

        progressTotal[i] = this.progressTotal
        progressAmount[i] = this.progressAmount
        definedModifier = countUndefined(progressTotal) / 10
        progressValue = calculateProgress() - definedModifier

        if (progressValue !== progressTracker) {
          progressBar.update(progressValue)
          progressTracker = progressValue
        }
      })
    })
  }

  uploadFiles(files = []) {
    return this.transformBasePath()
      .then(() => {
        var uploadFiles = files.map(file => this.uploadFile(file.name, file.path))

        this.setupProgressBar(uploadFiles)

        return Promise.all(uploadFiles.map(({promise}) => promise))
      })
  }

  uploadFile(fileName, file) {
    var upload,
        s3Params = _.merge({Key: this.options.basePath + fileName}, DEFAULT_UPLOAD_OPTIONS, this.uploadOptions)

    // Remove Gzip from encoding if ico
    if (/\.ico/.test(fileName) && s3Params.ContentEncoding === 'gzip')
      delete s3Params.ContentEncoding

    upload = this.client.uploadFile({
      localFile: file,
      s3Params
    })

    if (!this.noCdnizer)
      this.cdnizerOptions.files.push(`*${fileName}*`)

    var promise = new Promise((resolve, reject) => {
      upload.on('error', reject)
      upload.on('end', () => resolve(file))
    })

    return {upload, promise}
  }

  invalidateCloudfront() {
    var {clientConfig, cloudfrontInvalidateOptions} = this

    return new Promise(function(resolve, reject) {
      if (cloudfrontInvalidateOptions.DistributionId) {
        var cloudfront = new aws.CloudFront()

        cloudfront.config.update({
          accessKeyId: clientConfig.s3Options.accessKeyId,
          secretAccessKey: clientConfig.s3Options.secretAccessKey,
        })

        cloudfront.createInvalidation({
          DistributionId: cloudfrontInvalidateOptions.DistributionId,
          InvalidationBatch: {
            CallerReference: Date.now().toString(),
            Paths: {
              Quantity: cloudfrontInvalidateOptions.Items.length,
              Items: cloudfrontInvalidateOptions.Items
            }
          }
        }, (err, res) => err ? reject(err) : resolve(res.Id))
      } else {
        return resolve(null)
      }
    })
  }
}
<commit_msg>fix lint<commit_after>import http from 'http'
import https from 'https'
import s3 from 's3'
import fs from 'fs'
import path from 'path'
import ProgressBar from 'progress'
import cdnizer from 'cdnizer'
import _ from 'lodash'
import aws from 'aws-sdk'

import {
  addSeperatorToPath,
  getDirectoryFilesRecursive,
  UPLOAD_IGNORES,
  DEFAULT_UPLOAD_OPTIONS,
  DEFAULT_S3_OPTIONS,
  REQUIRED_S3_OPTS,
  REQUIRED_S3_UP_OPTS,
  PATH_SEP,
  DEFAULT_TRANSFORM,
} from './helpers'

http.globalAgent.maxSockets = https.globalAgent.maxSockets = 50

var compileError = function(compilation, error) {
  compilation.errors.push(new Error(error))
}

module.exports = class S3Plugin {
  constructor(options = {}) {
    var {
      include,
      exclude,
      basePath,
      directory,
      htmlFiles,
      basePathTransform = DEFAULT_TRANSFORM,
      s3Options = {},
      cdnizerOptions = {},
      s3UploadOptions = {},
      cloudfrontInvalidateOptions = {}
    } = options

    this.uploadOptions = s3UploadOptions
    this.cloudfrontInvalidateOptions = cloudfrontInvalidateOptions
    this.isConnected = false
    this.cdnizerOptions = cdnizerOptions
    this.urlMappings = []
    this.uploadTotal = 0
    this.uploadProgress = 0
    this.basePathTransform = basePathTransform
    basePath = basePath ? basePath.replace(/\/?(\?|#|$)/, '/$1') : ''

    this.options = {
      directory,
      include,
      exclude,
      basePath,
      htmlFiles: typeof htmlFiles === 'string' ? [htmlFiles] : htmlFiles
    }

    this.clientConfig = {
      maxAsyncS3: 50,
      s3Options: _.merge({}, DEFAULT_S3_OPTIONS, s3Options)
    }

    this.noCdnizer = !Object.keys(this.cdnizerOptions).length

    if (!this.noCdnizer && !this.cdnizerOptions.files)
      this.cdnizerOptions.files = []
  }

  apply(compiler) {
    this.connect()

    var isDirectoryUpload = !!this.options.directory,
        hasRequiredOptions = this.client.s3.config.credentials !== null,
        hasRequiredUploadOpts = _.every(REQUIRED_S3_UP_OPTS, type => this.uploadOptions[type])

    // Set directory to output dir or custom
    this.options.directory = this.options.directory || compiler.options.output.path || compiler.options.output.context || '.'

    compiler.plugin('after-emit', (compilation, cb) => {
      if (!hasRequiredOptions) {
        compileError(compilation, `S3Plugin: Must provide ${REQUIRED_S3_OPTS.join(', ')}`)
        cb()
      }

      if (!hasRequiredUploadOpts) {
        compileError(compilation, `S3Plugin-RequiredS3UploadOpts: ${REQUIRED_S3_UP_OPTS.join(', ')}`)
        cb()
      }

      if (isDirectoryUpload) {
        let dPath = addSeperatorToPath(this.options.directory)

        this.getAllFilesRecursive(dPath)
          .then((files) => this.handleFiles(files, cb))
          .then(() => cb())
          .catch(e => this.handleErrors(e, compilation, cb))
      } else {
        this.getAssetFiles(compilation)
          .then((files) => this.handleFiles(files))
          .then(() => cb())
          .catch(e => this.handleErrors(e, compilation, cb))
      }
    })
  }

  handleFiles(files) {
    return this.changeUrls(files)
      .then((files) => this.uploadFiles(files))
      .then(() => this.invalidateCloudfront())
  }

  handleErrors(error, compilation, cb) {
    compileError(compilation, `S3Plugin: ${e}`)
    cb()
  }

  getAllFilesRecursive(fPath) {
    return getDirectoryFilesRecursive(fPath)
      .then((files) => this.filterAllowedFiles(files))
  }

  addPathToFiles(files, fPath) {
    return files.map(file => ({name: file, path: path.resolve(fPath, file)}))
  }

  getFileName(file = '') {
    return _.includes(file, PATH_SEP) ? file.substring(_.lastIndexOf(file, PATH_SEP) + 1) : file
  }

  getAssetFiles({assets}) {
    var files = _.map(assets, (value, name) => ({name, path: value.existsAt}))

    return Promise.resolve(this.filterAllowedFiles(files))
  }

  cdnizeHtml(file) {
    return new Promise((resolve, reject) => {
      fs.readFile(file.path, (err, data) => {
        if (err)
          return reject(err)

        fs.writeFile(file.path, this.cdnizer(data.toString()), (err) => {
          if (err)
            return reject(err)

          resolve(file)
        })
      })
    })
  }

  changeUrls(files = []) {
    if (this.noCdnizer)
      return Promise.resolve(files)

    var allHtml,
        {directory, htmlFiles = []} = this.options

    allHtml = htmlFiles.length ? this.addPathToFiles(htmlFiles, directory).concat(files) : files
    this.cdnizerOptions.files = allHtml.map(({name}) => `*${name}*`)
    this.cdnizer = cdnizer(this.cdnizerOptions)

    var [cdnizeFiles, otherFiles] = _(allHtml)
      .uniq('name')
      .partition((file) => /\.(html)/.test(file.name)) // |css - Add when cdnize css is done
      .value()

    return Promise.all(cdnizeFiles.map(file => this.cdnizeHtml(file)).concat(otherFiles))
  }

  // For future implimentation
  // changeCssUrls(files = []) {
  //   if (this.noCdnizer)
  //     return Promise.resolve(files)

  //   data.replace(/url\(\/images/g, `url(${imagePath}`)

  //   return this.cdnizeCss(cssFile2, imagePath, files)
  // }

  filterAllowedFiles(files) {
    return files.reduce((res, file) => {
      if (this.isIncludeAndNotExclude(file.name) && !this.isIgnoredFile(file.name))
        res.push(file)

      return res
    }, [])
  }

  isIgnoredFile(file) {
    return _.some(UPLOAD_IGNORES, ignore => new RegExp(ignore).test(file))
  }

  isIncludeAndNotExclude(file) {
    var isExclude,
        isInclude,
        {include, exclude} = this.options

    isInclude = include ? include.test(file) : true
    isExclude = exclude ? exclude.test(file) : false

    return isInclude && !isExclude
  }

  connect() {
    if (this.isConnected)
      return

    this.client = s3.createClient(this.clientConfig)
    this.isConnected = true
  }

  transformBasePath() {
    return Promise.resolve(this.basePathTransform(this.options.basePath))
      .then(nPath => this.options.basePath = addSeperatorToPath(nPath))
  }

  setupProgressBar(uploadFiles) {
    var progressAmount = Array(uploadFiles.length)
    var progressTotal = Array(uploadFiles.length)
    var countUndefined = (array) => _.reduce(array, (res, value) => res += _.isUndefined(value) ? 1 : 0, 0)
    var calculateProgress = () => _.sum(progressAmount) / _.sum(progressTotal)
    var progressTracker = 0

    var progressBar = new ProgressBar('Uploading [:bar] :percent :etas', {
      complete: '>',
      incomplete: '∆',
      total: 100
    })

    uploadFiles.forEach(function({upload}, i) {
      upload.on('progress', function() {
        var definedModifier,
            progressValue

        progressTotal[i] = this.progressTotal
        progressAmount[i] = this.progressAmount
        definedModifier = countUndefined(progressTotal) / 10
        progressValue = calculateProgress() - definedModifier

        if (progressValue !== progressTracker) {
          progressBar.update(progressValue)
          progressTracker = progressValue
        }
      })
    })
  }

  uploadFiles(files = []) {
    return this.transformBasePath()
      .then(() => {
        var uploadFiles = files.map(file => this.uploadFile(file.name, file.path))

        this.setupProgressBar(uploadFiles)

        return Promise.all(uploadFiles.map(({promise}) => promise))
      })
  }

  uploadFile(fileName, file) {
    var upload,
        s3Params = _.merge({Key: this.options.basePath + fileName}, DEFAULT_UPLOAD_OPTIONS, this.uploadOptions)

    // Remove Gzip from encoding if ico
    if (/\.ico/.test(fileName) && s3Params.ContentEncoding === 'gzip')
      delete s3Params.ContentEncoding

    upload = this.client.uploadFile({
      localFile: file,
      s3Params
    })

    if (!this.noCdnizer)
      this.cdnizerOptions.files.push(`*${fileName}*`)

    var promise = new Promise((resolve, reject) => {
      upload.on('error', reject)
      upload.on('end', () => resolve(file))
    })

    return {upload, promise}
  }

  invalidateCloudfront() {
    var {clientConfig, cloudfrontInvalidateOptions} = this

    return new Promise(function(resolve, reject) {
      if (cloudfrontInvalidateOptions.DistributionId) {
        var cloudfront = new aws.CloudFront()

        cloudfront.config.update({
          accessKeyId: clientConfig.s3Options.accessKeyId,
          secretAccessKey: clientConfig.s3Options.secretAccessKey,
        })

        cloudfront.createInvalidation({
          DistributionId: cloudfrontInvalidateOptions.DistributionId,
          InvalidationBatch: {
            CallerReference: Date.now().toString(),
            Paths: {
              Quantity: cloudfrontInvalidateOptions.Items.length,
              Items: cloudfrontInvalidateOptions.Items
            }
          }
        }, (err, res) => err ? reject(err) : resolve(res.Id))
      } else {
        return resolve(null)
      }
    })
  }
}
<|endoftext|>


<commit_before>'use strict';

var User = require('../models/user');
var restify = require('restify');
var secrets = require('../config/secrets');

// show user page

exports.getProfile = function(req, res, next){
  var form = {},
  error = null,
  formFlash = req.flash('form'),
  errorFlash = req.flash('error');

  if (formFlash.length) {
    form.email = formFlash[0].email;
  }
  if (errorFlash.length) {
    error = errorFlash[0];
  }
  res.render(req.render, {user: req.user, form: form, error: error});
};

// Updates generic profile information

exports.postProfile = function(req, res, next){
  req.assert('email', 'Email is not valid').isEmail();
  req.assert('name', 'Name is required').notEmpty();

  var errors = req.validationErrors();

  if (errors) {
    req.flash('errors', errors);
    return res.redirect(req.redirect.failure);
  }

  if(req.body.email != req.user.email){
    User.findOne({ email: req.body.email }, function(err, existingUser) {
      if (existingUser) {
        req.flash('errors', { msg: 'An account with that email address already exists.' });
        return res.redirect(req.redirect.failure);
      } else {
        User.findById(req.user.id, function(err, user) {
          if (err) return next(err);
          user.email = req.body.email || '';
          user.profile.name = req.body.name || '';
          user.profile.gender = req.body.gender || '';
          user.profile.location = req.body.location || '';
          user.profile.website = req.body.website || '';

          user.save(function(err) {
            if (err) return next(err);
            user.updateStripeEmail(function(err){
              if (err) return next(err);
              req.flash('success', { msg: 'Profile information updated.' });
              res.redirect(req.redirect.success);
            });
          });
        });
      }
    });
  } else {
    User.findById(req.user.id, function(err, user) {
      if (err) return next(err);
      user.profile.name = req.body.name || '';
      user.profile.gender = req.body.gender || '';
      user.profile.location = req.body.location || '';
      user.profile.website = req.body.website || '';

      user.save(function(err) {
        if (err) return next(err);
        user.updateStripeEmail(function(err){
          if (err) return next(err);
          req.flash('success', { msg: 'Profile information updated.' });
          res.redirect(req.redirect.success);
        });
      });
    });
  }
};

exports.postCoupon = function(req, res, next){
    User.findById(req.user.id, function(err, user) {
      if (err) return next(err);
        user.setCoupon(req.body.coupon, function(err){

          if (err) {
              req.flash('errors', { msg: err.message.toString() || 'Invalid coupon' });
              res.redirect(req.redirect.failure);
          } else {
            req.flash('success', { msg: 'Coupon updated.' });
            res.redirect(req.redirect.success);
          }
        });

    });
};

// Removes account

exports.deleteAccount = function(req, res, next){
  User.findById(req.user.id, function(err, user) {
    if (err) return next(err);

    var client = restify.createStringClient({
      url: secrets.vpnht.url,
    });
    client.basicAuth(secrets.vpnht.key, secrets.vpnht.secret);
    client.del('/username/' + user.username, function (err, req2, res2, obj) {

        user.remove(function (err, user) {
          if (err) return next(err);
          user.cancelStripe(function(err){
            if (err) return next(err);

            req.logout();
            req.flash('info', { msg: 'Your account has been deleted.' });
            res.redirect(req.redirect.success);
          });
        });
    });
  });
};

// Adds or updates a users card.

exports.postBilling = function(req, res, next){
  var stripeToken = req.body.stripeToken;

  if(!stripeToken){
    req.flash('errors', { msg: 'Please provide a valid card.' });
    return res.redirect(req.redirect.failure);
  }

  User.findById(req.user.id, function(err, user) {
    if (err) return next(err);

    user.setCard(stripeToken, function (err) {
      if (err) {
        if(err.code && err.code == 'card_declined'){
          req.flash('errors', { msg: 'Your card was declined. Please provide a valid card.' });
          return res.redirect(req.redirect.failure);
        }
        req.flash('errors', { msg: 'An unexpected error occurred.' });
        return res.redirect(req.redirect.failure);
      }
      req.flash('success', { msg: 'Billing has been updated.' });
      res.redirect(req.redirect.success);
    });
  });
};

exports.postPlan = function(req, res, next){
  var plan = req.body.plan;
  var stripeToken = null;

  if(plan){
    plan = plan.toLowerCase();
  }

  if(req.user.stripe.plan == plan){
    req.flash('info', {msg: 'The selected plan is the same as the current plan.'});
    return res.redirect(req.redirect.success);
  }

  if(req.body.stripeToken){
    stripeToken = req.body.stripeToken;
  }

  if(!req.user.stripe.last4 && !req.body.stripeToken){
    req.flash('errors', {msg: 'Please add a card to your account before choosing a plan.'});
    return res.redirect(req.redirect.failure);
  }

  User.findById(req.user.id, function(err, user) {
    if (err) return next(err);

    user.setPlan(plan, stripeToken, function (err) {
      var msg;

      if (err) {
        if(err.code && err.code == 'card_declined'){
          msg = 'Your card was declined. Please provide a valid card.';
        } else if(err && err.message) {
          msg = err.message;
        } else {
          msg = 'An unexpected error occurred.';
        }

        req.flash('errors', { msg:  msg});
        return res.redirect(req.redirect.failure);
      }
      req.flash('success', { msg: 'Plan has been updated.' });
      res.redirect(req.redirect.success);
    });
  });
};
<commit_msg>Fix delete<commit_after>'use strict';

var User = require('../models/user');
var restify = require('restify');
var secrets = require('../config/secrets');

// show user page

exports.getProfile = function(req, res, next){
  var form = {},
  error = null,
  formFlash = req.flash('form'),
  errorFlash = req.flash('error');

  if (formFlash.length) {
    form.email = formFlash[0].email;
  }
  if (errorFlash.length) {
    error = errorFlash[0];
  }
  res.render(req.render, {user: req.user, form: form, error: error});
};

// Updates generic profile information

exports.postProfile = function(req, res, next){
  req.assert('email', 'Email is not valid').isEmail();
  req.assert('name', 'Name is required').notEmpty();

  var errors = req.validationErrors();

  if (errors) {
    req.flash('errors', errors);
    return res.redirect(req.redirect.failure);
  }

  if(req.body.email != req.user.email){
    User.findOne({ email: req.body.email }, function(err, existingUser) {
      if (existingUser) {
        req.flash('errors', { msg: 'An account with that email address already exists.' });
        return res.redirect(req.redirect.failure);
      } else {
        User.findById(req.user.id, function(err, user) {
          if (err) return next(err);
          user.email = req.body.email || '';
          user.profile.name = req.body.name || '';
          user.profile.gender = req.body.gender || '';
          user.profile.location = req.body.location || '';
          user.profile.website = req.body.website || '';

          user.save(function(err) {
            if (err) return next(err);
            user.updateStripeEmail(function(err){
              if (err) return next(err);
              req.flash('success', { msg: 'Profile information updated.' });
              res.redirect(req.redirect.success);
            });
          });
        });
      }
    });
  } else {
    User.findById(req.user.id, function(err, user) {
      if (err) return next(err);
      user.profile.name = req.body.name || '';
      user.profile.gender = req.body.gender || '';
      user.profile.location = req.body.location || '';
      user.profile.website = req.body.website || '';

      user.save(function(err) {
        if (err) return next(err);
        user.updateStripeEmail(function(err){
          if (err) return next(err);
          req.flash('success', { msg: 'Profile information updated.' });
          res.redirect(req.redirect.success);
        });
      });
    });
  }
};

exports.postCoupon = function(req, res, next){
    User.findById(req.user.id, function(err, user) {
      if (err) return next(err);
        user.setCoupon(req.body.coupon, function(err){

          if (err) {
              req.flash('errors', { msg: err.message.toString() || 'Invalid coupon' });
              res.redirect(req.redirect.failure);
          } else {
            req.flash('success', { msg: 'Coupon updated.' });
            res.redirect(req.redirect.success);
          }
        });

    });
};

// Removes account

exports.deleteAccount = function(req, res, next){
  User.findById(req.user.id, function(err, user) {
    if (err) return next(err);

    var client = restify.createStringClient({
      url: secrets.vpnht.url,
    });
    client.basicAuth(secrets.vpnht.key, secrets.vpnht.secret);
    client.del('/user/' + user.username, function (err, req2, res2, obj) {
        user.remove(function (err, user) {
          if (err) return next(err);
          user.cancelStripe(function(err){
            if (err) return next(err);

            req.logout();
            req.flash('info', { msg: 'Your account has been deleted.' });
            res.redirect(req.redirect.success);
          });
        });
    });
  });
};

// Adds or updates a users card.

exports.postBilling = function(req, res, next){
  var stripeToken = req.body.stripeToken;

  if(!stripeToken){
    req.flash('errors', { msg: 'Please provide a valid card.' });
    return res.redirect(req.redirect.failure);
  }

  User.findById(req.user.id, function(err, user) {
    if (err) return next(err);

    user.setCard(stripeToken, function (err) {
      if (err) {
        if(err.code && err.code == 'card_declined'){
          req.flash('errors', { msg: 'Your card was declined. Please provide a valid card.' });
          return res.redirect(req.redirect.failure);
        }
        req.flash('errors', { msg: 'An unexpected error occurred.' });
        return res.redirect(req.redirect.failure);
      }
      req.flash('success', { msg: 'Billing has been updated.' });
      res.redirect(req.redirect.success);
    });
  });
};

exports.postPlan = function(req, res, next){
  var plan = req.body.plan;
  var stripeToken = null;

  if(plan){
    plan = plan.toLowerCase();
  }

  if(req.user.stripe.plan == plan){
    req.flash('info', {msg: 'The selected plan is the same as the current plan.'});
    return res.redirect(req.redirect.success);
  }

  if(req.body.stripeToken){
    stripeToken = req.body.stripeToken;
  }

  if(!req.user.stripe.last4 && !req.body.stripeToken){
    req.flash('errors', {msg: 'Please add a card to your account before choosing a plan.'});
    return res.redirect(req.redirect.failure);
  }

  User.findById(req.user.id, function(err, user) {
    if (err) return next(err);

    user.setPlan(plan, stripeToken, function (err) {
      var msg;

      if (err) {
        if(err.code && err.code == 'card_declined'){
          msg = 'Your card was declined. Please provide a valid card.';
        } else if(err && err.message) {
          msg = err.message;
        } else {
          msg = 'An unexpected error occurred.';
        }

        req.flash('errors', { msg:  msg});
        return res.redirect(req.redirect.failure);
      }
      req.flash('success', { msg: 'Plan has been updated.' });
      res.redirect(req.redirect.success);
    });
  });
};
<|endoftext|>


<commit_before>/* global describe, it */
import { expect } from 'chai'
import Vue from 'vue'
import Vuex from 'vuex'
import sinon from 'sinon'
import Home from 'renderer/components/Home.vue'

Vue.use(Vuex)

function getMockStore () {
  return {
    actions: { loadProtocol: sinon.spy() },
    state: {}
  }
}

const mockStore = getMockStore()

function getRenderedVm (Component, store) {
  const Ctor = Vue.extend(Component)
  const vm = new Ctor({store: new Vuex.Store(store)}).$mount()
  return vm
}

describe('Home.vue', (done) => {
  it('has 6 btn-homes', () => {
    let home = getRenderedVm(Home, mockStore)
    expect(home.$el.querySelectorAll('.btn-home').length).to.equal(6)
  })
})
<commit_msg>test button clicks calling actions<commit_after>/* global describe, it */
import { expect } from 'chai'
import Vue from 'vue'
import Vuex from 'vuex'
import sinon from 'sinon'
import Home from 'renderer/components/Home.vue'

Vue.use(Vuex)

function getMockStore () {
  return {
    actions: { home: sinon.spy() }
  }
}

const mockStore = getMockStore()
const home = getRenderedVm(Home, mockStore)

function getRenderedVm (Component, store) {
  const Ctor = Vue.extend(Component)
  const vm = new Ctor({store: new Vuex.Store(store)}).$mount()
  return vm
}

describe('Home.vue', (done) => {
  it('has 6 btn-home classes', () => {
    expect(home.$el.querySelectorAll('.btn-home').length).to.equal(6)
  })

  it('has each button send a home dispatch with the correct axis', () => {
    let buttons = [].slice.call(home.$el.querySelectorAll('.btn-home'))
    expect(mockStore.actions.home.called).to.be.false
    buttons.map((button, i) => {
      button.click()
      let homeArgs = mockStore.actions.home.getCall(i).args.slice(-2)[0]
      expect(homeArgs.axis).to.equal(button.innerHTML.toLowerCase())
    })
    expect(mockStore.actions.home.callCount).to.equal(6)
  })
})
<|endoftext|>


<commit_before><commit_msg>minor async fix<commit_after><|endoftext|>


<commit_before>(function () {
  angular
    .module("viewpoint.controllers")
    .controller("signinCtrl", signinCtrl);

  signinCtrl.$inject = ["errorsService", "$auth", "$state"];

  function signinCtrl (errorsService, $auth, $state) {
    var vm = this;

    vm.user = {};

    vm.fieldErrors      = fieldErrors;
    vm.signinFormSubmit = signinFormSubmit;

    function signinFormSubmit (user) {
      return $auth.login({ "user": user })
        .then(authCompleted)
        .catch(authFailed)
        .finally(clearPassword);
    }

    function authCompleted (response) {
      $state.go("dashboard");
    }

    function authFailed (error) {
      vm.user.errors = errorsService.parse(error.data);
    }

    function clearPassword () {
      vm.user.password = "";
      vm.signinForm.$setPristine();
    }

    function fieldErrors (field) {
      return errorsService.normalize(vm.signinForm, vm.user, field);
    }
  }
})();
<commit_msg>Salva chave da api<commit_after>(function () {
  angular
    .module("viewpoint.controllers")
    .controller("signinCtrl", signinCtrl);

  signinCtrl.$inject = ["userService", "errorsService", "$auth", "$state"];

  function signinCtrl (userService, errorsService, $auth, $state) {
    var vm = this;

    vm.user = {};

    vm.fieldErrors      = fieldErrors;
    vm.signinFormSubmit = signinFormSubmit;

    function signinFormSubmit (user) {
      return $auth.login({ "user": user })
        .then(authCompleted)
        .catch(authFailed)
        .finally(clearPassword);
    }

    function authCompleted (response) {
      userService.saveApiKey(response.data.key);

      $state.go("dashboard");
    }

    function authFailed (error) {
      vm.user.errors = errorsService.parse(error.data);
    }

    function clearPassword () {
      vm.user.password = "";
      vm.signinForm.$setPristine();
    }

    function fieldErrors (field) {
      return errorsService.normalize(vm.signinForm, vm.user, field);
    }
  }
})();
<|endoftext|>


<commit_before>'use strict';

var engine = null,
  options = null,
  config = require('../../../src/lib/config'),
  path = require('path'),
  composr = require('composr-core'),
  https = require('https'),
  nock = require('nock'),
  chai = require('chai'),
  chaiAsPromised = require('chai-as-promised'),
  expect = chai.expect,
  assert = chai.assert,
  fs = require('fs'),
  sinon = require('sinon'),
  engine = require('../../../src/lib/engine.js');

chai.use(chaiAsPromised);

describe('Engine', function() {
  this.timeout(10 * 1000);

  var baseUrl = config('corbel.driver.options').urlBase;
  var retries = config('services.retries');
  var time = config('services.time');
  var domain = baseUrl.substring(0, baseUrl.indexOf("{") - 1);
  var engineAbsPath = null;
  var mySandbox = sinon.sandbox.create();
  var modules = ['iam', 'resources'];

  describe('Services checking', function() {

    before(function() {
      options = {
        allowUnmocked: true
      };
      engineAbsPath = path.resolve(__dirname + '../../../../src/lib/engine.js');
    });

    beforeEach(function() {
      engine = require(engineAbsPath);
    });

    afterEach(function() {
      mySandbox.restore();
      // Required to allow to create a new instance of 'engine'
      // Every time a 'require' is made, is saved into a local 'require' cache, so to create a new instance every time,
      // we need to replace cache
      delete require.cache[engineAbsPath];
      });

    describe('Engine', function() {

      it('initialize engine on first time', function(done) {
        var stubOnComposrInit = mySandbox.stub(engine, 'initComposrCore');
        var stubInitServiceChecking = mySandbox.stub(engine, 'initServiceCheckingRequests');

        stubOnComposrInit.returns(Promise.resolve());
        stubInitServiceChecking.returns([Promise.resolve()]);

        engine.launchTries()
          .should.be.fulfilled
          .then(function() {
            engine.initComposrCore(null, true);
          })
          .then(function() {
            expect(stubOnComposrInit.calledOnce).to.be.true;
            expect(stubOnComposrInit.lastCall.args[1] === true).to.be.true;
          })
          .should.notify(done);
      });

      it('not initialize engine when core is not available', function(done) {

        var stubOnComposrInit = mySandbox.stub(engine, 'initComposrCore');
        var stubInitServiceChecking = mySandbox.stub(engine, 'initServiceCheckingRequests');
        var spyWaitTilServicesUp = mySandbox.spy(engine, 'waitTilServicesUp');
        stubOnComposrInit.returns(Promise.reject());
        stubInitServiceChecking.returns([Promise.reject()])

        engine.launchTries(50,3)
          .should.be.rejected
          .then(function() {
            engine.initComposrCore(null, false)
              .should.be.rejected
          })
          .then(function() {
            expect(spyWaitTilServicesUp.callCount === 3).to.be.true;
            expect(stubOnComposrInit.calledOnce).to.be.true;
            expect(stubOnComposrInit.lastCall.args[1] === false).to.be.true;
          })
          .should.notify(done);
      });

      it('initializes engine without data when one endpoint does not work on first time and retries ' + retries + ' times and finally login', function(done) {

        var stubOnComposrInit = mySandbox.stub(engine, 'initComposrCore');
        var stubInitServiceChecking = mySandbox.stub(engine, 'initServiceCheckingRequests');
        var spyWaitTilServicesUp = mySandbox.spy(engine, 'waitTilServicesUp');

        stubInitServiceChecking.onCall(0).returns([Promise.reject()]);
        stubInitServiceChecking.onCall(1).returns([Promise.reject()]);
        stubInitServiceChecking.onCall(2).returns([Promise.reject()]);
        stubInitServiceChecking.onCall(3).returns([Promise.resolve()]);
        stubOnComposrInit.returns(Promise.resolve());

        engine.launchTries(50,3)
          .should.be.rejected
          .then(function() {
            engine.initComposrCore(null, false)
              .should.be.fulfilled
          })
          .then(function() {
            engine.launchTries(50,3)
              .should.be.fulfilled;
          })
          .then(function() {
            engine.initComposrCore(null, true)
              .should.be.fulfilled
          })
          .then(function() {
            expect(stubInitServiceChecking.callCount === 4).to.be.true;
            expect(spyWaitTilServicesUp.callCount === 4).to.be.true;
            expect(stubOnComposrInit.calledTwice).to.be.true;
            expect(stubOnComposrInit.firstCall.args[1] === false).to.be.true;
            expect(stubOnComposrInit.secondCall.args[1] === true).to.be.true;
          })
          .should.notify(done);
      });
    });

    describe('Engine requests', function() {

      it('when request timeout is fired promise should be rejected', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .delayConnection(time)
          .reply(200)
          .get('/resources/version')
          .delayConnection(time)
          .reply(200);

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
           .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
          .should.notify(done);
      });

      it('when connection error event is fired promise should be rejected', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .replyWithError('An awful error')
          .get('/resources/version')
          .replyWithError('An awful error');

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
            .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
         .should.notify(done);
      });

      it('when request is replied and no body exists promise should be resolved', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .reply(200)
          .get('/resources/version')
          .reply(200);

        Promise.all(engine.initServiceCheckingRequests(modules, 5000))
          .should.be.fulfilled
             .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
        .should.notify(done);
      });

      it('when request is replied and JSON body without error is sent promise should be resolved', function(done) {

        var jsonResponse = {'result': 'ok'};

        nock(domain, options)
          .get('/iam/version')
          .reply(200, jsonResponse)
          .get('/resources/version')
          .reply(200, jsonResponse);

        Promise.all(engine.initServiceCheckingRequests(modules, 5000))
          .should.be.fulfilled
              .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
       .should.notify(done);
      });

      it('when response status code is !== 200 and no body error is sent promise should be rejected', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .reply(400)
          .get('/resources/version')
          .reply(400);

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
               .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
      .should.notify(done);
      });

      it('when response status code !== 200 and response body contains a JSON error promise should be rejected', function(done) {

        var bodyError = JSON.stringify({
          err: new Error('Undefined error').toString()
        });

        nock(domain, options)
          .get('/iam/version')
          .reply(400, bodyError, {
            'Content-Type': 'application/json'
          })
          .get('/resources/version')
          .reply(400, bodyError, {
            'Content-Type': 'application/json'
          });

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
                .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
     .should.notify(done);
      });

      it('when response status code === 200 && response body contains an error promise should be rejected', function(done) {

        var bodyError = new Error('Undefined error').toString();
        nock(domain, options)
         .get('/iam/version')
          .reply(200, bodyError, {
            'Content-Type': 'application/html'
          })
          .get('/resources/version')
          .reply(200, bodyError, {
            'Content-Type': 'application/html'
          });

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
         .should.be.rejected
          .then(function(){
            expect(nock.isDone()).to.be.true;
            // cleanAll must be called here, because 'afterEach' || 'after' hooks are called immediately, buy promise resolves before, so, there's a time fraction where nock is still loaded and further calls hit it, that means, no interceptor is defined for arbitrary endpoints ---> nock reject request
            nock.cleanAll();
          })
          .should.notify(done);
      });
    });

  });
});
<commit_msg>- Fix nock restore interceptor<commit_after>'use strict';

var engine = null,
  options = null,
  config = require('../../../src/lib/config'),
  path = require('path'),
  composr = require('composr-core'),
  https = require('https'),
  nock = require('nock'),
  chai = require('chai'),
  chaiAsPromised = require('chai-as-promised'),
  expect = chai.expect,
  assert = chai.assert,
  fs = require('fs'),
  sinon = require('sinon'),
  engine = require('../../../src/lib/engine.js');

chai.use(chaiAsPromised);

describe('Engine', function() {
  this.timeout(10 * 1000);

  var baseUrl = config('corbel.driver.options').urlBase;
  var retries = config('services.retries');
  var time = config('services.time');
  var domain = baseUrl.substring(0, baseUrl.indexOf("{") - 1);
  var engineAbsPath = null;
  var mySandbox = sinon.sandbox.create();
  var modules = ['iam', 'resources'];

  describe('Services checking', function() {

    before(function() {
      options = {
        allowUnmocked: true
      };
      engineAbsPath = path.resolve(__dirname + '../../../../src/lib/engine.js');
    });

    beforeEach(function() {
      engine = require(engineAbsPath);
    });

    afterEach(function() {
      mySandbox.restore();
      // Required to allow to create a new instance of 'engine'
      // Every time a 'require' is made, is saved into a local 'require' cache, so to create a new instance every time,
      // we need to replace cache
      delete require.cache[engineAbsPath];
      });

    describe('Engine', function() {

      it('initialize engine on first time', function(done) {
        var stubOnComposrInit = mySandbox.stub(engine, 'initComposrCore');
        var stubInitServiceChecking = mySandbox.stub(engine, 'initServiceCheckingRequests');

        stubOnComposrInit.returns(Promise.resolve());
        stubInitServiceChecking.returns([Promise.resolve()]);

        engine.launchTries()
          .should.be.fulfilled
          .then(function() {
            engine.initComposrCore(null, true);
          })
          .then(function() {
            expect(stubOnComposrInit.calledOnce).to.be.true;
            expect(stubOnComposrInit.lastCall.args[1] === true).to.be.true;
          })
          .should.notify(done);
      });

      it('not initialize engine when core is not available', function(done) {

        var stubOnComposrInit = mySandbox.stub(engine, 'initComposrCore');
        var stubInitServiceChecking = mySandbox.stub(engine, 'initServiceCheckingRequests');
        var spyWaitTilServicesUp = mySandbox.spy(engine, 'waitTilServicesUp');
        stubOnComposrInit.returns(Promise.reject());
        stubInitServiceChecking.returns([Promise.reject()])

        engine.launchTries(50,3)
          .should.be.rejected
          .then(function() {
            engine.initComposrCore(null, false)
              .should.be.rejected
          })
          .then(function() {
            expect(spyWaitTilServicesUp.callCount === 3).to.be.true;
            expect(stubOnComposrInit.calledOnce).to.be.true;
            expect(stubOnComposrInit.lastCall.args[1] === false).to.be.true;
          })
          .should.notify(done);
      });

      it('initializes engine without data when one endpoint does not work on first time and retries ' + retries + ' times and finally login', function(done) {

        var stubOnComposrInit = mySandbox.stub(engine, 'initComposrCore');
        var stubInitServiceChecking = mySandbox.stub(engine, 'initServiceCheckingRequests');
        var spyWaitTilServicesUp = mySandbox.spy(engine, 'waitTilServicesUp');

        stubInitServiceChecking.onCall(0).returns([Promise.reject()]);
        stubInitServiceChecking.onCall(1).returns([Promise.reject()]);
        stubInitServiceChecking.onCall(2).returns([Promise.reject()]);
        stubInitServiceChecking.onCall(3).returns([Promise.resolve()]);
        stubOnComposrInit.returns(Promise.resolve());

        engine.launchTries(50,3)
          .should.be.rejected
          .then(function() {
            engine.initComposrCore(null, false)
              .should.be.fulfilled
          })
          .then(function() {
            engine.launchTries(50,3)
              .should.be.fulfilled;
          })
          .then(function() {
            engine.initComposrCore(null, true)
              .should.be.fulfilled
          })
          .then(function() {
            expect(stubInitServiceChecking.callCount === 4).to.be.true;
            expect(spyWaitTilServicesUp.callCount === 4).to.be.true;
            expect(stubOnComposrInit.calledTwice).to.be.true;
            expect(stubOnComposrInit.firstCall.args[1] === false).to.be.true;
            expect(stubOnComposrInit.secondCall.args[1] === true).to.be.true;
          })
          .should.notify(done);
      });
    });

    describe('Engine requests', function() {

      it('when request timeout is fired promise should be rejected', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .delayConnection(time)
          .reply(200)
          .get('/resources/version')
          .delayConnection(time)
          .reply(200);

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
           .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
          .should.notify(done);
      });

      it('when connection error event is fired promise should be rejected', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .replyWithError('An awful error')
          .get('/resources/version')
          .replyWithError('An awful error');

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
            .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
         .should.notify(done);
      });

      it('when request is replied and no body exists promise should be resolved', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .reply(200)
          .get('/resources/version')
          .reply(200);

        Promise.all(engine.initServiceCheckingRequests(modules, 5000))
          .should.be.fulfilled
             .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
        .should.notify(done);
      });

      it('when request is replied and JSON body without error is sent promise should be resolved', function(done) {

        var jsonResponse = {'result': 'ok'};

        nock(domain, options)
          .get('/iam/version')
          .reply(200, jsonResponse)
          .get('/resources/version')
          .reply(200, jsonResponse);

        Promise.all(engine.initServiceCheckingRequests(modules, 5000))
          .should.be.fulfilled
              .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
       .should.notify(done);
      });

      it('when response status code is !== 200 and no body error is sent promise should be rejected', function(done) {

        nock(domain, options)
          .get('/iam/version')
          .reply(400)
          .get('/resources/version')
          .reply(400);

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
               .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
      .should.notify(done);
      });

      it('when response status code !== 200 and response body contains a JSON error promise should be rejected', function(done) {

        var bodyError = JSON.stringify({
          err: new Error('Undefined error').toString()
        });

        nock(domain, options)
          .get('/iam/version')
          .reply(400, bodyError, {
            'Content-Type': 'application/json'
          })
          .get('/resources/version')
          .reply(400, bodyError, {
            'Content-Type': 'application/json'
          });

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
          .should.be.rejected
                .then(function(){
            expect(nock.isDone()).to.be.true;
            nock.cleanAll();
          })
     .should.notify(done);
      });

      it('when response status code === 200 && response body contains an error promise should be rejected', function(done) {

        var bodyError = new Error('Undefined error').toString();
        nock(domain, options)
         .get('/iam/version')
          .reply(200, bodyError, {
            'Content-Type': 'application/html'
          })
          .get('/resources/version')
          .reply(200, bodyError, {
            'Content-Type': 'application/html'
          });

        Promise.all(engine.initServiceCheckingRequests(modules, 0))
         .should.be.rejected
          .then(function(){
            expect(nock.isDone()).to.be.true;
            // cleanAll must be called here, because 'afterEach' || 'after' hooks are called immediately, but promise resolves before, so, there's a time fraction where nock is still loaded and further calls hit it, that means, no interceptor is defined for arbitrary endpoints ---> nock reject request
            nock.cleanAll();
            nock.restore();
          })
          .should.notify(done);
      });
    });

  });
});
<|endoftext|>


<commit_before>/*
 * YouPlay (v1.3)
 * https://github.com/esquivias/YouPlay
 */
var YouPlay = (function($, undefined){
	'use strict';
	function YouPlay(element){
		this.youtube = {
			api_key: $(element).data('youplay-api-key'),
			playlist_id: $(element).data('youplay-playlist-id'),
			uid: (Math.random().toString(16).substr(2,8)),
			url: {
				playlists: 'https://www.googleapis.com/youtube/v3/playlists?part=snippet&id={{PLAYLIST_ID}}&key={{API_KEY}}',
				playlist_items: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults={{MAX_RESULTS}}&playlistId={{PLAYLIST_ID}}&key={{API_KEY}}'
			}
		}
		this.option = $.extend({
			autoplay: false,
			autonext: true,
			loop: true,
			mute: false,
			max_results: 50,
			thumbnail_quality: 'high',
			active_class: 'active',
			player_class: 'embed-responsive-item',
			callback: null,
			debug: false
		},{
			autoplay: $(element).data('youplay-autoplay'),
			autonext: $(element).data('youplay-autonext'),
			loop: $(element).data('youplay-loop'),
			mute: $(element).data('youplay-mute'),
			max_results: $(element).data('youplay-max-results'),
			thumbnail_quality: $(element).data('youplay-thumbnail-quality'),
			active_class: $(element).data('youplay-active-class'),
			player_class: $(element).data('youplay-player-class'),
			callback: $(element).data('youplay-callback'),
			debug: $(element).data('youplay-debug')
		});
		this.object = {
			player: $(element).find("[data-youplay-player]"),
			playlist_title: $(element).find("[data-youplay-playlist-title]"),
			playlist_description: $(element).find("[data-youplay-playlist-description]"),
			playlist_items: $(element).find("[data-youplay-playlist-items]"),
			playlist_item: $(element).find("[data-youplay-playlist-item]")
		}
		this.init(element);
	}
	YouPlay.prototype = {
		init: function(element){
			if(typeof this.youtube.api_key === 'undefined' || typeof this.youtube.playlist_id === 'undefined'){
				if(this.option.debug){
					if(typeof this.youtube.api_key === 'undefined'){
						console.error("Missing required data-youplay-api-key attribute.\nhttps://developers.google.com/youtube/v3/getting-started");
					}else if(typeof this.youtube.playlist_id === 'undefined'){
						console.error("Missing required data-youplay-playlist-id attribute.");
					}
				}
				return false;
			}
			if(typeof YT === 'undefined'){
				var tag = document.createElement('script'), htag = document.getElementsByTagName('head')[0];
				tag.src = 'https://www.youtube.com/player_api';
				htag.appendChild(tag);
			}
			if(typeof $(element).data('youplay-autoplay') !== 'undefined'){
				if(typeof $(element).data('youplay-mute') === 'undefined'){
					this.option.mute = true;
					if(this.option.debug){
						console.log("YouPlay will automatically mute audio when autoplay is enabled.");
					}
				}
			}
		},
		onYouTubeIframeAPIReady: function(){
			this.populatePlaylist();
			this.populatePlaylistItems();
		},
		requestYouTubeURL: function(name){
			return this.youtube.url[name].replace('{{PLAYLIST_ID}}', this.youtube.playlist_id).replace('{{API_KEY}}', this.youtube.api_key).replace('{{MAX_RESULTS}}', this.option.max_results);
		},
		logError: function(data){
			var this_ = this, data = $.parseJSON(data.responseText);
			if(typeof data.error !== 'undefined'){
				if(typeof data.error.errors !== 'undefined'){
					$.each(data.error.errors, function(index, error){
						if(this_.option.debug){
							if(typeof error.message !== 'undefined'){
								if(typeof error.reason !== 'undefined'){
									console.log(error.reason + ": " + error.message);
								}else{
									console.log(error.message);
								}
							}
							if(typeof error.extendedHelp !== 'undefined'){
								console.log(error.extendedHelp);
							}
						}
					});
				}
			}
		},
		prepareCallback: function(method, data){
			if(this.option.callback !== null){
				if(typeof window[this.option.callback] !== 'undefined'){
					if(typeof window[this.option.callback][method] !== 'undefined'){
						window[this.option.callback][method](data);
					}else{
						if(this.option.debug){
							console.log('YouPlay callback ' + this.option.callback + '.' + method + ' not found.');
						}
					}
				}else{
					if(this.option.debug){
						console.error('YouPlay callback ' + this.option.callback + ' not found.');
					}
				}
			}
		},
		prepareValueFormat: function(attribute, data){
			if(this.option.callback !== null){
				if(typeof window[this.option.callback] !== 'undefined'){
					if(typeof window[this.option.callback]['onFormat'] !== 'undefined'){
						if(typeof window[this.option.callback]['onFormat'][attribute] !== 'undefined'){
							data = window[this.option.callback]['onFormat'][attribute](data);
						}
					}
				}
			}
			return data;
		},
		populatePlaylist: function(){
			var this_ = this, url = this.requestYouTubeURL('playlists');
			$.ajaxSetup({cache: false});
			$.ajax(url, {
				context: this,
				dataType: 'json',
				crossDomain: true,
				error: function(data){
					this_.logError(data);
				},
				success: function(data){
					if(typeof data.items !== 'undefined'){
						if(typeof data.items[0] !== 'undefined'){
							if(typeof data.items[0].snippet !== 'undefined'){
								if(typeof data.items[0].snippet.title !== 'undefined'){
									this.object.playlist_title.html(this.prepareValueFormat('playlistTitle', data.items[0].snippet.title));
								}
								if(typeof data.items[0].snippet.description !== 'undefined'){
									this.object.playlist_description.html(this.prepareValueFormat('playlistDescription', data.items[0].snippet.description));
								}
							}
						}
					}
				}
			});
		},
		populatePlaylistItems: function(){
			var this_ = this, url = this.requestYouTubeURL('playlist_items');
			this.object.playlist_items.html('');
			$.ajaxSetup ({cache: false});
			$.ajax(url, {
				context: this,
				dataType: 'json',
				crossDomain: true,
				error: function(data){
					this_.logError(data);
				},
				success: function(data){
					if(data.kind === 'youtube#playlistItemListResponse'){
						$.each(data.items, function(index, item){
							this_.populatePlaylistItem(item, this_.object.playlist_item);
						});
						this.populateYouTubePlayer();
					}
				}
			});
		},
		populatePlaylistItem: function(item, element){
			var this_ = this, template = element.clone();
			if(typeof item.status === 'undefined' || $.inArray(item.status.uploadStatus, ['rejected', 'deleted', 'failed']) === -1 && typeof item.snippet.thumbnails !== 'undefined'){
				if(typeof item.snippet.thumbnails === 'undefined'){
					if(this.option.debug){
						console.log("YouPlay is not able to load " + item.snippet.resourceId.videoId + ", a private video.");
					}
				}else{
					var data = $.extend({
						id: item.snippet.resourceId.videoId,
						thumbnail: item.snippet.thumbnails[this.option.thumbnail_quality].url
					},
						item.snippet
					);
					if(this.option.debug){
						console.log(data);
					}
					$.each(data, function(attribute, value){
						value = this_.prepareValueFormat(attribute, value);
						var tag = $(template).find('[data-youplay-playlist-item-'+attribute+']');
						if(tag.prop('tagName') != "IMG"){
							tag.html(value);
						}else{
							var titleFormat = this_.prepareValueFormat('title', data.title);
							tag.attr('src', value).attr('alt', titleFormat).attr('title', titleFormat);
						}
					});
					template.attr('data-youplay-video-id', data.id).appendTo(this.object.playlist_items);
				}
			}
		},
		populateYouTubePlayer: function(){
			var this_ = this;
			this.object.player.attr('id', 'YouPlay' + this.youtube.uid).addClass(this.option.player_class);
			this.object.YT_player = new YT.Player(this.object.player.attr('id'), {
				playerVars: {
					enablejsapi: 1,
					modestbranding: 1,
					rel: 0,
					wmode: 'transparent'
				},
				events: {
					'onReady': function(){
						this_.onYouTubePlayerReady();
					},
					'onStateChange': function(e){
						this_.onYouTubePlayerStateChange(e);
					},
					'onError': function(e){
						if(this_.option.debug){
							console.log(e);
						}
						this_.prepareCallback('onError', e);
					}
				}
			});
		},
		onYouTubePlayerReady: function(){
			var this_ = this;
			this.object.playlist_items.find('[data-youplay-playlist-item]').bind('click', function(e){
				e.preventDefault();
				this_.object.playlist_items.find('[data-youplay-playlist-item]').removeClass(this_.option.active_class);
				$(this).addClass(this_.option.active_class);
				this_.object.YT_player.loadVideoById($(this).data('youplay-video-id'));
				this_.prepareCallback('onPlaylistItem', this);
			});
			if(this.option.autoplay){
				if(this.object.playlist_items.find('.' + this.option.active_class).length === 0){
					this.object.playlist_items.find('[data-youplay-playlist-item]').first().click();
				}
				this.prepareCallback('onReady', true);
			}else{
				this.object.YT_player.cueVideoById(this.object.playlist_items.find('[data-youplay-playlist-item]').first().addClass(this.option.active_class).data('youplay-video-id'));
			}
			this.prepareCallback('onReady', false);
		},
		onYouTubePlayerStateChange: function(e){
			if (typeof e !== 'undefined'){
				if(this.option.mute){
					this.object.YT_player.mute();
				}
				var next = null;
				if(e.data === 0 && this.option.autonext){
					next = this.object.playlist_items.find('[data-youplay-playlist-item].' + this.option.active_class).next()
					if(next.length === 0 && this.option.loop){
						next = this.object.playlist_items.find('[data-youplay-playlist-item]').first();
						this.prepareCallback('onLoop', true);
					}else{
						this.prepareCallback('onAutonext', next);
					}
					next.click();
				}
			}
		}
	}
	return YouPlay;
}(jQuery));
$.fn.YouPlay = function(){
	return this.each(function(){
		this.youplay_object = new YouPlay(this);
	});
};
$(document).ready(function(){
	$('[data-youplay-playlist-id]').each(function(index, element){
		if(typeof element.youplay_object === 'undefined'){
			$(this).YouPlay();
		}
	});
});
function onYouTubeIframeAPIReady(){
	$('[data-youplay-playlist-id]').each(function(index, element){
		if(typeof element.youplay_object === 'undefined'){
			console.error('YouPlay cannot initialize playlist ' + $(this).data('youplay-playlist-id'));
		}else{
			element.youplay_object.onYouTubeIframeAPIReady();
		}
	});
}<commit_msg>Bug Fix<commit_after>/*
 * YouPlay (v1.4)
 * https://github.com/esquivias/YouPlay
 */
var YouPlay = (function($, undefined){
	'use strict';
	function YouPlay(element){
		this.youtube = {
			api_key: $(element).data('youplay-api-key'),
			playlist_id: $(element).data('youplay-playlist-id'),
			uid: (Math.random().toString(16).substr(2,8)),
			url: {
				playlists: 'https://www.googleapis.com/youtube/v3/playlists?part=snippet&id={{PLAYLIST_ID}}&key={{API_KEY}}',
				playlist_items: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults={{MAX_RESULTS}}&playlistId={{PLAYLIST_ID}}&key={{API_KEY}}'
			}
		}
		this.option = $.extend({
			autoplay: false,
			autonext: true,
			loop: true,
			mute: false,
			max_results: 50,
			thumbnail_quality: 'high',
			active_class: 'active',
			player_class: 'embed-responsive-item',
			callback: null,
			debug: false
		},{
			autoplay: $(element).data('youplay-autoplay'),
			autonext: $(element).data('youplay-autonext'),
			loop: $(element).data('youplay-loop'),
			mute: $(element).data('youplay-mute'),
			max_results: $(element).data('youplay-max-results'),
			thumbnail_quality: $(element).data('youplay-thumbnail-quality'),
			active_class: $(element).data('youplay-active-class'),
			player_class: $(element).data('youplay-player-class'),
			callback: $(element).data('youplay-callback'),
			debug: $(element).data('youplay-debug')
		});
		this.object = {
			player: $(element).find("[data-youplay-player]"),
			playlist_title: $(element).find("[data-youplay-playlist-title]"),
			playlist_description: $(element).find("[data-youplay-playlist-description]"),
			playlist_items: $(element).find("[data-youplay-playlist-items]"),
			playlist_item: $(element).find("[data-youplay-playlist-item]")
		}
		this.init(element);
	}
	YouPlay.prototype = {
		init: function(element){
			if(typeof this.youtube.api_key === 'undefined' || typeof this.youtube.playlist_id === 'undefined'){
				if(this.option.debug){
					if(typeof this.youtube.api_key === 'undefined'){
						console.error("Missing required data-youplay-api-key attribute.\nhttps://developers.google.com/youtube/v3/getting-started");
					}else if(typeof this.youtube.playlist_id === 'undefined'){
						console.error("Missing required data-youplay-playlist-id attribute.");
					}
				}
				return false;
			}
			if(typeof YT === 'undefined'){
				var tag = document.createElement('script'), htag = document.getElementsByTagName('head')[0];
				tag.src = 'https://www.youtube.com/player_api';
				htag.appendChild(tag);
			}
			if(typeof $(element).data('youplay-autoplay') !== 'undefined'){
				if(typeof $(element).data('youplay-mute') === 'undefined'){
					this.option.mute = true;
					if(this.option.debug){
						console.log("YouPlay will automatically mute audio when autoplay is enabled.");
					}
				}
			}
		},
		onYouTubeIframeAPIReady: function(){
			this.populatePlaylist();
			this.populatePlaylistItems();
		},
		requestYouTubeURL: function(name){
			return this.youtube.url[name].replace('{{PLAYLIST_ID}}', this.youtube.playlist_id).replace('{{API_KEY}}', this.youtube.api_key).replace('{{MAX_RESULTS}}', this.option.max_results);
		},
		logError: function(data){
			if(this.option.debug){
				var this_ = this, data = $.parseJSON(data.responseText);
				if(typeof data.error !== 'undefined'){
					if(typeof data.error.errors !== 'undefined'){
						$.each(data.error.errors, function(index, error){
							if(typeof error.message !== 'undefined'){
								if(typeof error.reason !== 'undefined'){
									console.log(error.reason + ": " + error.message);
								}else{
									console.log(error.message);
								}
							}
							if(typeof error.extendedHelp !== 'undefined'){
								console.log(error.extendedHelp);
							}
						});
					}
				}
			}
		},
		prepareCallback: function(method, data){
			if(this.option.callback !== null){
				if(typeof window[this.option.callback] !== 'undefined'){
					if(typeof window[this.option.callback][method] !== 'undefined'){
						window[this.option.callback][method](data);
					}else{
						if(this.option.debug){
							console.log('YouPlay callback ' + this.option.callback + '.' + method + ' not found.');
						}
					}
				}else{
					if(this.option.debug){
						console.error('YouPlay callback ' + this.option.callback + ' not found.');
					}
				}
			}
		},
		prepareValueFormat: function(attribute, data){
			if(this.option.callback !== null){
				if(typeof window[this.option.callback] !== 'undefined'){
					if(typeof window[this.option.callback]['onFormat'] !== 'undefined'){
						if(typeof window[this.option.callback]['onFormat'][attribute] !== 'undefined'){
							data = window[this.option.callback]['onFormat'][attribute](data);
						}
					}
				}
			}
			return data;
		},
		populatePlaylist: function(){
			var this_ = this, url = this.requestYouTubeURL('playlists');
			$.ajaxSetup({cache: false});
			$.ajax(url, {
				context: this,
				dataType: 'json',
				crossDomain: true,
				error: function(data){
					this_.logError(data);
				},
				success: function(data){
					if(typeof data.items !== 'undefined'){
						if(typeof data.items[0] !== 'undefined'){
							if(typeof data.items[0].snippet !== 'undefined'){
								if(typeof data.items[0].snippet.title !== 'undefined'){
									this.object.playlist_title.html(this.prepareValueFormat('playlistTitle', data.items[0].snippet.title));
								}
								if(typeof data.items[0].snippet.description !== 'undefined'){
									this.object.playlist_description.html(this.prepareValueFormat('playlistDescription', data.items[0].snippet.description));
								}
							}
						}
					}
				}
			});
		},
		populatePlaylistItems: function(){
			var this_ = this, url = this.requestYouTubeURL('playlist_items');
			this.object.playlist_items.html('');
			$.ajaxSetup ({cache: false});
			$.ajax(url, {
				context: this,
				dataType: 'json',
				crossDomain: true,
				error: function(data){
					this_.logError(data);
				},
				success: function(data){
					if(data.kind === 'youtube#playlistItemListResponse'){
						$.each(data.items, function(index, item){
							this_.populatePlaylistItem(item, this_.object.playlist_item);
						});
						this.populateYouTubePlayer();
					}
				}
			});
		},
		populatePlaylistItem: function(item, element){
			var this_ = this, template = element.clone();
			if(typeof item.status === 'undefined' || $.inArray(item.status.uploadStatus, ['rejected', 'deleted', 'failed']) === -1 && typeof item.snippet.thumbnails !== 'undefined'){
				if(typeof item.snippet.thumbnails === 'undefined'){
					if(this.option.debug){
						console.log("YouPlay is not able to load " + item.snippet.resourceId.videoId + ", a private video.");
					}
				}else{
					var data = $.extend({
						id: item.snippet.resourceId.videoId,
						thumbnail: item.snippet.thumbnails[this.option.thumbnail_quality].url
					},
						item.snippet
					);
					if(this.option.debug){
						console.log(data);
					}
					$.each(data, function(attribute, value){
						value = this_.prepareValueFormat(attribute, value);
						var tag = $(template).find('[data-youplay-playlist-item-'+attribute+']');
						if(tag.prop('tagName') != "IMG"){
							tag.html(value);
						}else{
							var titleFormat = this_.prepareValueFormat('title', data.title);
							tag.attr('src', value).attr('alt', titleFormat).attr('title', titleFormat);
						}
					});
					template.attr('data-youplay-video-id', data.id).appendTo(this.object.playlist_items);
				}
			}
		},
		populateYouTubePlayer: function(){
			var this_ = this;
			this.object.player.attr('id', 'YouPlay' + this.youtube.uid).addClass(this.option.player_class);
			this.object.YT_player = new YT.Player(this.object.player.attr('id'), {
				playerVars: {
					enablejsapi: 1,
					modestbranding: 1,
					rel: 0,
					wmode: 'transparent'
				},
				events: {
					'onReady': function(){
						this_.onYouTubePlayerReady();
					},
					'onStateChange': function(e){
						this_.onYouTubePlayerStateChange(e);
					},
					'onError': function(e){
						if(this_.option.debug){
							console.log(e);
						}
						this_.prepareCallback('onError', e);
					}
				}
			});
		},
		onYouTubePlayerReady: function(){
			var this_ = this;
			this.object.playlist_items.find('[data-youplay-playlist-item]').bind('click', function(e){
				e.preventDefault();
				this_.object.playlist_items.find('[data-youplay-playlist-item]').removeClass(this_.option.active_class);
				$(this).addClass(this_.option.active_class);
				this_.object.YT_player.loadVideoById($(this).data('youplay-video-id'));
				this_.prepareCallback('onPlaylistItem', this);
			});
			if(this.option.autoplay){
				if(this.object.playlist_items.find('.' + this.option.active_class).length === 0){
					this.object.playlist_items.find('[data-youplay-playlist-item]').first().click();
				}
				this.prepareCallback('onReady', true);
			}else{
				this.object.YT_player.cueVideoById(this.object.playlist_items.find('[data-youplay-playlist-item]').first().addClass(this.option.active_class).data('youplay-video-id'));
			}
			this.prepareCallback('onReady', false);
		},
		onYouTubePlayerStateChange: function(e){
			if (typeof e !== 'undefined'){
				if(this.option.mute){
					this.object.YT_player.mute();
				}
				var next = null;
				if(e.data === 0 && this.option.autonext){
					next = this.object.playlist_items.find('[data-youplay-playlist-item].' + this.option.active_class).next()
					if(next.length === 0 && this.option.loop){
						next = this.object.playlist_items.find('[data-youplay-playlist-item]').first();
						this.prepareCallback('onLoop', true);
					}else{
						this.prepareCallback('onAutonext', next);
					}
					next.click();
				}
			}
		}
	}
	return YouPlay;
}(jQuery));
$.fn.YouPlay = function(){
	return this.each(function(){
		this.youplay_object = new YouPlay(this);
	});
};
$(document).ready(function(){
	$('[data-youplay-playlist-id]').each(function(index, element){
		if(typeof element.youplay_object === 'undefined'){
			$(this).YouPlay();
		}
	});
});
function onYouTubeIframeAPIReady(){
	$('[data-youplay-playlist-id]').each(function(index, element){
		if(typeof element.youplay_object === 'undefined'){
			console.error('YouPlay cannot initialize playlist ' + $(this).data('youplay-playlist-id'));
		}else{
			element.youplay_object.onYouTubeIframeAPIReady();
		}
	});
}<|endoftext|>


<commit_before><commit_msg>improved boolean handling<commit_after><|endoftext|>