<commit_before>/** @babel */

import _ from 'lodash'
import { shell } from 'electron'
import fs from 'fs-plus'
import path from 'path'
import { getEditorDetails, heredoc, replacePropertiesInString } from './werkzeug'
import minimatch from 'minimatch'
import glob from 'glob'
import { CompositeDisposable, Disposable } from 'atom'

export default class Composer extends Disposable {
  disposables = new CompositeDisposable()
  outputLookup = new Map()

  constructor () {
    super(() => this.disposables.dispose())
    this.disposables.add(atom.config.onDidChange('latex', () => {
      this.rebuildCompleted = new Set()
    }))
    this.checkEnvironment()
  }

  initializeBuild (filePath) {
    let state = {
      rootFilePath: this.resolveRootFilePath(filePath)
    }

    state.builder = latex.builderRegistry.getBuilder(state.rootFilePath)
    if (!state.builder) {
      latex.log.warning(`No registered LaTeX builder can process ${filePath}.`)
      return state
    }

    if (Object.getPrototypeOf(state.builder).constructor.name === 'TexifyBuilder') {
      // -------------------------------------------------------------
      // TODO: Remove this whole block when texify support is removed.
      // -------------------------------------------------------------
      const message = `LaTeX: The texify builder has been deprecated`
      const description = heredoc(`
        Support for the \`texify\` builder has been deprecated in favor of \`latexmk\`, and will be
        removed soon.`)

      const title = 'How to use latexmk with MiKTeX'
      const url = 'https://github.com/thomasjo/atom-latex/wiki/Using-latexmk-with-MiKTeX'
      const openUrl = (event) => {
        // NOTE: Horrible hack due to a bug in atom/notifications module...
        const element = event.target.parentElement.parentElement.parentElement.parentElement
        const notification = element.getModel()
        notification.dismiss()

        shell.openExternal(url)
      }

      atom.notifications.addWarning(message, {
        dismissable: true, description, buttons: [{ text: title, onDidClick: openUrl }]
      })
    }

    state.jobnames = state.builder.getJobNamesFromMagic(state.rootFilePath)

    return state
  }

  async build (shouldRebuild) {
    latex.process.killChildProcesses()

    const { editor, filePath } = getEditorDetails()

    if (!filePath) {
      latex.log.warning('File needs to be saved to disk before it can be TeXified.')
      return false
    }

    if (editor.isModified()) {
      editor.save() // TODO: Make this configurable?
    }

    const { builder, rootFilePath, jobnames } = this.initializeBuild(filePath)
    if (!builder) return false

    if (this.rebuildCompleted && !this.rebuildCompleted.has(rootFilePath)) {
      shouldRebuild = true
      this.rebuildCompleted.add(rootFilePath)
    }

    const label = shouldRebuild ? 'LaTeX Rebuild' : 'LaTeX Build'

    latex.status.show(label, 'highlight', 'sync', true, 'Click to kill LaTeX build.', () => latex.process.killChildProcesses())
    latex.log.group(label)

    const jobs = jobnames.map(jobname => this.buildJob(builder, rootFilePath, jobname, shouldRebuild))

    await Promise.all(jobs)

    latex.log.groupEnd()
  }

  async buildJob (builder, rootFilePath, jobname, shouldRebuild) {
    try {
      const statusCode = await builder.run(rootFilePath, jobname, shouldRebuild)
      const rootPath = path.dirname(rootFilePath)
      const result = builder.parseLogAndFdbFiles(rootPath, rootFilePath, jobname)

      if (result) {
        for (const message of result.messages) {
          latex.log.showMessage(message)
        }
      }

      if (statusCode > 0 || !result || !result.outputFilePath) {
        this.showError(result)
      } else {
        if (this.shouldMoveResult(builder, rootFilePath)) {
          this.moveResult(result, rootFilePath)
        }
        // Cache the output file path for sync
        this.outputLookup.set({ rootFilePath, jobname }, result.outputFilePath)
        this.showResult(result)
      }
    } catch (error) {
      latex.log.error(error.message)
    }
  }

  async sync () {
    const { filePath, lineNumber } = getEditorDetails()
    if (!filePath || !this.isTexFile(filePath)) {
      return
    }

    const { builder, rootFilePath, jobnames } = this.initializeBuild(filePath)
    if (!builder) return false

    const jobs = jobnames.map(jobname => this.syncJob(filePath, lineNumber, builder, rootFilePath, jobname))

    await Promise.all(jobs)
  }

  async syncJob (filePath, lineNumber, builder, rootFilePath, jobname) {
    const outputFilePath = this.resolveOutputFilePath(builder, rootFilePath, jobname)
    if (!outputFilePath) {
      latex.log.warning('Could not resolve path to output file associated with the current file.')
      return
    }

    await latex.opener.open(outputFilePath, filePath, lineNumber)
  }

  async clean () {
    const { filePath } = getEditorDetails()
    if (!filePath || !this.isTexFile(filePath)) {
      return false
    }

    latex.log.group('LaTeX Clean')

    const { builder, rootFilePath, jobnames } = this.initializeBuild(filePath)
    if (!builder) return false

    const jobs = jobnames.map(jobname => this.cleanJob(builder, rootFilePath, jobname))

    await Promise.all(jobs)

    latex.log.groupEnd()
  }

  async cleanJob (builder, rootFilePath, jobname) {
    const rootPath = path.dirname(rootFilePath)
    const generatedFiles = this.getGeneratedFileList(builder, rootFilePath, jobname)
    let files = new Set()

    const patterns = this.getCleanPatterns(builder, rootFilePath, jobname)

    for (const pattern of patterns) {
      const absolutePattern = path.join(rootPath, pattern)
      // If the original pattern is absolute then we use it as a globbing pattern
      // after we join it to the root, otherwise we use it against the list of
      // generated files.
      if (pattern[0] === path.sep) {
        for (const file of glob.sync(absolutePattern)) {
          files.add(path.normalize(file))
        }
      } else {
        for (const file of generatedFiles.values()) {
          if (minimatch(file, absolutePattern)) {
            files.add(file)
          }
        }
      }
    }

    const fileNames = Array.from(files.values()).map(file => path.basename(file)).join(', ')
    latex.log.info('Cleaned: ' + fileNames)

    for (const file of files.values()) {
      fs.removeSync(file)
    }
  }

  getCleanPatterns (builder, rootFilePath, jobname) {
    const { name, ext } = path.parse(rootFilePath)
    const outputDirectory = builder.getOutputDirectory()
    const properties = {
      output_dir: outputDirectory ? outputDirectory + path.sep : '',
      jobname: jobname || name,
      name,
      ext
    }
    const patterns = atom.config.get('latex.cleanPatterns')

    return _.map(patterns, pattern => path.normalize(replacePropertiesInString(pattern, properties)))
  }

  getGeneratedFileList (builder, rootFilePath, jobname) {
    const { dir, name } = path.parse(rootFilePath)
    const fdb = builder.parseFdbFile(rootFilePath, jobname)

    const outputDirectory = builder.getOutputDirectory()
    const pattern = path.join(dir, outputDirectory, `${jobname || name}*`)
    const files = new Set(glob.sync(pattern))

    if (fdb) {
      for (const file of _.flatten(_.values(fdb))) {
        files.add(path.resolve(dir, file))
      }
    }

    return files
  }

  moveResult (result, filePath) {
    const originalOutputFilePath = result.outputFilePath
    result.outputFilePath = this.alterParentPath(filePath, originalOutputFilePath)
    if (fs.existsSync(originalOutputFilePath)) {
      fs.removeSync(result.outputFilePath)
      fs.moveSync(originalOutputFilePath, result.outputFilePath)
    }

    const originalSyncFilePath = originalOutputFilePath.replace(/\.pdf$/, '.synctex.gz')
    if (fs.existsSync(originalSyncFilePath)) {
      const syncFilePath = this.alterParentPath(filePath, originalSyncFilePath)
      fs.removeSync(syncFilePath)
      fs.moveSync(originalSyncFilePath, syncFilePath)
    }
  }

  resolveRootFilePath (filePath) {
    const MasterTexFinder = require('./master-tex-finder')
    const finder = new MasterTexFinder(filePath)
    return finder.getMasterTexPath()
  }

  resolveOutputFilePath (builder, rootFilePath, jobname) {
    const label = { rootFilePath, jobname }

    if (this.outputLookup.has(label)) {
      return this.outputLookup.get(label)
    }

    const rootPath = path.dirname(rootFilePath)
    const result = builder.parseLogAndFdbFiles(rootPath, rootFilePath, jobname)
    if (!result || !result.outputFilePath) {
      latex.log.warning('Log file parsing failed!')
      return null
    }

    let outputFilePath = result.outputFilePath
    if (this.shouldMoveResult(builder, rootFilePath)) {
      outputFilePath = this.alterParentPath(rootFilePath, outputFilePath)
    }
    this.outputLookup.set(label, outputFilePath)

    return outputFilePath
  }

  async showResult (result) {
    if (!this.shouldOpenResult()) { return }

    const { filePath, lineNumber } = getEditorDetails()
    await latex.opener.open(result.outputFilePath, filePath, lineNumber)
  }

  showError (result) {
    if (!result) {
      latex.log.error('Parsing of log files failed.')
    } else if (!result.outputFilePath) {
      latex.log.error('No output file detected.')
    }
  }

  isTexFile (filePath) {
    // TODO: Improve will suffice for the time being.
    return !filePath || filePath.search(/\.(tex|lhs|[rs]nw)$/i) > 0
  }

  alterParentPath (targetPath, originalPath) {
    const targetDir = path.dirname(targetPath)
    return path.join(targetDir, path.basename(originalPath))
  }

  shouldMoveResult (builder, rootFilePath) {
    const moveResult = atom.config.get('latex.moveResultToSourceDirectory')
    const outputDirectory = builder.getOutputDirectory(rootFilePath)
    return moveResult && outputDirectory.length > 0
  }

  shouldOpenResult () { return atom.config.get('latex.openResultAfterBuild') }

  async checkEnvironment () {
    latex.log.group('LaTeX Check')
    // TODO: remove after grace period
    this.checkCleanExtensions()
    this.checkOpenerSetting()
    await this.builderRegistry.checkEnvironment()
    latex.opener.checkEnvironment()
    latex.log.groupEnd()
  }

  checkCleanExtensions () {
    const cleanExtensions = atom.config.get('latex.cleanExtensions')
    if (!cleanExtensions) return

    let cleanPatterns = atom.config.get('latex.cleanPatterns')
    const defaultExtensions = [
      '.aux', '.bbl', '.blg', '.fdb_latexmk', '.fls', '.lof', '.log',
      '.lol', '.lot', '.nav', '.out', '.pdf', '.snm', '.synctex.gz', '.toc'
    ]

    atom.config.unset('latex.cleanExtensions')

    const removedExtensions = _.difference(defaultExtensions, cleanExtensions)
    cleanPatterns = _.difference(cleanPatterns, removedExtensions.map(extension => `**/*${extension}`))

    const addedExtensions = _.difference(cleanExtensions, defaultExtensions)
    cleanPatterns = _.union(cleanPatterns, addedExtensions.map(extension => `**/*${extension}`))

    atom.config.set('latex.cleanPatterns', cleanPatterns)
    const message = 'LaTeX: The "latex:clean" command has changed'
    const description = heredoc(`
      Your custom extensions in the \`Clean Extensions\` settings have
      been migrated to the new setting \`Clean Patterns\`.`)
    atom.notifications.addInfo(message, { description })
  }

  checkOpenerSetting () {
    const alwaysOpenResultInAtom = atom.config.get('latex.alwaysOpenResultInAtom')
    if (!alwaysOpenResultInAtom) return

    atom.config.unset('latex.alwaysOpenResultInAtom')
    atom.config.set('latex.opener', 'pdf-view')
  }
}
<commit_msg>Add spec guard for checkEnvironment<commit_after>/** @babel */

import _ from 'lodash'
import { shell } from 'electron'
import fs from 'fs-plus'
import path from 'path'
import { getEditorDetails, heredoc, replacePropertiesInString } from './werkzeug'
import minimatch from 'minimatch'
import glob from 'glob'
import { CompositeDisposable, Disposable } from 'atom'

export default class Composer extends Disposable {
  disposables = new CompositeDisposable()
  outputLookup = new Map()

  constructor () {
    super(() => this.disposables.dispose())
    this.disposables.add(atom.config.onDidChange('latex', () => {
      this.rebuildCompleted = new Set()
    })
    if (!atom.inSpecMode()) this.checkEnvironment()
  }

  initializeBuild (filePath) {
    let state = {
      rootFilePath: this.resolveRootFilePath(filePath)
    }

    state.builder = latex.builderRegistry.getBuilder(state.rootFilePath)
    if (!state.builder) {
      latex.log.warning(`No registered LaTeX builder can process ${filePath}.`)
      return state
    }

    if (Object.getPrototypeOf(state.builder).constructor.name === 'TexifyBuilder') {
      // -------------------------------------------------------------
      // TODO: Remove this whole block when texify support is removed.
      // -------------------------------------------------------------
      const message = `LaTeX: The texify builder has been deprecated`
      const description = heredoc(`
        Support for the \`texify\` builder has been deprecated in favor of \`latexmk\`, and will be
        removed soon.`)

      const title = 'How to use latexmk with MiKTeX'
      const url = 'https://github.com/thomasjo/atom-latex/wiki/Using-latexmk-with-MiKTeX'
      const openUrl = (event) => {
        // NOTE: Horrible hack due to a bug in atom/notifications module...
        const element = event.target.parentElement.parentElement.parentElement.parentElement
        const notification = element.getModel()
        notification.dismiss()

        shell.openExternal(url)
      }

      atom.notifications.addWarning(message, {
        dismissable: true, description, buttons: [{ text: title, onDidClick: openUrl }]
      })
    }

    state.jobnames = state.builder.getJobNamesFromMagic(state.rootFilePath)

    return state
  }

  async build (shouldRebuild) {
    latex.process.killChildProcesses()

    const { editor, filePath } = getEditorDetails()

    if (!filePath) {
      latex.log.warning('File needs to be saved to disk before it can be TeXified.')
      return false
    }

    if (editor.isModified()) {
      editor.save() // TODO: Make this configurable?
    }

    const { builder, rootFilePath, jobnames } = this.initializeBuild(filePath)
    if (!builder) return false

    if (this.rebuildCompleted && !this.rebuildCompleted.has(rootFilePath)) {
      shouldRebuild = true
      this.rebuildCompleted.add(rootFilePath)
    }

    const label = shouldRebuild ? 'LaTeX Rebuild' : 'LaTeX Build'

    latex.status.show(label, 'highlight', 'sync', true, 'Click to kill LaTeX build.', () => latex.process.killChildProcesses())
    latex.log.group(label)

    const jobs = jobnames.map(jobname => this.buildJob(builder, rootFilePath, jobname, shouldRebuild))

    await Promise.all(jobs)

    latex.log.groupEnd()
  }

  async buildJob (builder, rootFilePath, jobname, shouldRebuild) {
    try {
      const statusCode = await builder.run(rootFilePath, jobname, shouldRebuild)
      const rootPath = path.dirname(rootFilePath)
      const result = builder.parseLogAndFdbFiles(rootPath, rootFilePath, jobname)

      if (result) {
        for (const message of result.messages) {
          latex.log.showMessage(message)
        }
      }

      if (statusCode > 0 || !result || !result.outputFilePath) {
        this.showError(result)
      } else {
        if (this.shouldMoveResult(builder, rootFilePath)) {
          this.moveResult(result, rootFilePath)
        }
        // Cache the output file path for sync
        this.outputLookup.set({ rootFilePath, jobname }, result.outputFilePath)
        this.showResult(result)
      }
    } catch (error) {
      latex.log.error(error.message)
    }
  }

  async sync () {
    const { filePath, lineNumber } = getEditorDetails()
    if (!filePath || !this.isTexFile(filePath)) {
      return
    }

    const { builder, rootFilePath, jobnames } = this.initializeBuild(filePath)
    if (!builder) return false

    const jobs = jobnames.map(jobname => this.syncJob(filePath, lineNumber, builder, rootFilePath, jobname))

    await Promise.all(jobs)
  }

  async syncJob (filePath, lineNumber, builder, rootFilePath, jobname) {
    const outputFilePath = this.resolveOutputFilePath(builder, rootFilePath, jobname)
    if (!outputFilePath) {
      latex.log.warning('Could not resolve path to output file associated with the current file.')
      return
    }

    await latex.opener.open(outputFilePath, filePath, lineNumber)
  }

  async clean () {
    const { filePath } = getEditorDetails()
    if (!filePath || !this.isTexFile(filePath)) {
      return false
    }

    latex.log.group('LaTeX Clean')

    const { builder, rootFilePath, jobnames } = this.initializeBuild(filePath)
    if (!builder) return false

    const jobs = jobnames.map(jobname => this.cleanJob(builder, rootFilePath, jobname))

    await Promise.all(jobs)

    latex.log.groupEnd()
  }

  async cleanJob (builder, rootFilePath, jobname) {
    const rootPath = path.dirname(rootFilePath)
    const generatedFiles = this.getGeneratedFileList(builder, rootFilePath, jobname)
    let files = new Set()

    const patterns = this.getCleanPatterns(builder, rootFilePath, jobname)

    for (const pattern of patterns) {
      const absolutePattern = path.join(rootPath, pattern)
      // If the original pattern is absolute then we use it as a globbing pattern
      // after we join it to the root, otherwise we use it against the list of
      // generated files.
      if (pattern[0] === path.sep) {
        for (const file of glob.sync(absolutePattern)) {
          files.add(path.normalize(file))
        }
      } else {
        for (const file of generatedFiles.values()) {
          if (minimatch(file, absolutePattern)) {
            files.add(file)
          }
        }
      }
    }

    const fileNames = Array.from(files.values()).map(file => path.basename(file)).join(', ')
    latex.log.info('Cleaned: ' + fileNames)

    for (const file of files.values()) {
      fs.removeSync(file)
    }
  }

  getCleanPatterns (builder, rootFilePath, jobname) {
    const { name, ext } = path.parse(rootFilePath)
    const outputDirectory = builder.getOutputDirectory()
    const properties = {
      output_dir: outputDirectory ? outputDirectory + path.sep : '',
      jobname: jobname || name,
      name,
      ext
    }
    const patterns = atom.config.get('latex.cleanPatterns')

    return _.map(patterns, pattern => path.normalize(replacePropertiesInString(pattern, properties)))
  }

  getGeneratedFileList (builder, rootFilePath, jobname) {
    const { dir, name } = path.parse(rootFilePath)
    const fdb = builder.parseFdbFile(rootFilePath, jobname)

    const outputDirectory = builder.getOutputDirectory()
    const pattern = path.join(dir, outputDirectory, `${jobname || name}*`)
    const files = new Set(glob.sync(pattern))

    if (fdb) {
      for (const file of _.flatten(_.values(fdb))) {
        files.add(path.resolve(dir, file))
      }
    }

    return files
  }

  moveResult (result, filePath) {
    const originalOutputFilePath = result.outputFilePath
    result.outputFilePath = this.alterParentPath(filePath, originalOutputFilePath)
    if (fs.existsSync(originalOutputFilePath)) {
      fs.removeSync(result.outputFilePath)
      fs.moveSync(originalOutputFilePath, result.outputFilePath)
    }

    const originalSyncFilePath = originalOutputFilePath.replace(/\.pdf$/, '.synctex.gz')
    if (fs.existsSync(originalSyncFilePath)) {
      const syncFilePath = this.alterParentPath(filePath, originalSyncFilePath)
      fs.removeSync(syncFilePath)
      fs.moveSync(originalSyncFilePath, syncFilePath)
    }
  }

  resolveRootFilePath (filePath) {
    const MasterTexFinder = require('./master-tex-finder')
    const finder = new MasterTexFinder(filePath)
    return finder.getMasterTexPath()
  }

  resolveOutputFilePath (builder, rootFilePath, jobname) {
    const label = { rootFilePath, jobname }

    if (this.outputLookup.has(label)) {
      return this.outputLookup.get(label)
    }

    const rootPath = path.dirname(rootFilePath)
    const result = builder.parseLogAndFdbFiles(rootPath, rootFilePath, jobname)
    if (!result || !result.outputFilePath) {
      latex.log.warning('Log file parsing failed!')
      return null
    }

    let outputFilePath = result.outputFilePath
    if (this.shouldMoveResult(builder, rootFilePath)) {
      outputFilePath = this.alterParentPath(rootFilePath, outputFilePath)
    }
    this.outputLookup.set(label, outputFilePath)

    return outputFilePath
  }

  async showResult (result) {
    if (!this.shouldOpenResult()) { return }

    const { filePath, lineNumber } = getEditorDetails()
    await latex.opener.open(result.outputFilePath, filePath, lineNumber)
  }

  showError (result) {
    if (!result) {
      latex.log.error('Parsing of log files failed.')
    } else if (!result.outputFilePath) {
      latex.log.error('No output file detected.')
    }
  }

  isTexFile (filePath) {
    // TODO: Improve will suffice for the time being.
    return !filePath || filePath.search(/\.(tex|lhs|[rs]nw)$/i) > 0
  }

  alterParentPath (targetPath, originalPath) {
    const targetDir = path.dirname(targetPath)
    return path.join(targetDir, path.basename(originalPath))
  }

  shouldMoveResult (builder, rootFilePath) {
    const moveResult = atom.config.get('latex.moveResultToSourceDirectory')
    const outputDirectory = builder.getOutputDirectory(rootFilePath)
    return moveResult && outputDirectory.length > 0
  }

  shouldOpenResult () { return atom.config.get('latex.openResultAfterBuild') }

  async checkEnvironment () {
    latex.log.group('LaTeX Check')
    // TODO: remove after grace period
    this.checkCleanExtensions()
    this.checkOpenerSetting()
    await this.builderRegistry.checkEnvironment()
    latex.opener.checkEnvironment()
    latex.log.groupEnd()
  }

  checkCleanExtensions () {
    const cleanExtensions = atom.config.get('latex.cleanExtensions')
    if (!cleanExtensions) return

    let cleanPatterns = atom.config.get('latex.cleanPatterns')
    const defaultExtensions = [
      '.aux', '.bbl', '.blg', '.fdb_latexmk', '.fls', '.lof', '.log',
      '.lol', '.lot', '.nav', '.out', '.pdf', '.snm', '.synctex.gz', '.toc'
    ]

    atom.config.unset('latex.cleanExtensions')

    const removedExtensions = _.difference(defaultExtensions, cleanExtensions)
    cleanPatterns = _.difference(cleanPatterns, removedExtensions.map(extension => `**/*${extension}`))

    const addedExtensions = _.difference(cleanExtensions, defaultExtensions)
    cleanPatterns = _.union(cleanPatterns, addedExtensions.map(extension => `**/*${extension}`))

    atom.config.set('latex.cleanPatterns', cleanPatterns)
    const message = 'LaTeX: The "latex:clean" command has changed'
    const description = heredoc(`
      Your custom extensions in the \`Clean Extensions\` settings have
      been migrated to the new setting \`Clean Patterns\`.`)
    atom.notifications.addInfo(message, { description })
  }

  checkOpenerSetting () {
    const alwaysOpenResultInAtom = atom.config.get('latex.alwaysOpenResultInAtom')
    if (!alwaysOpenResultInAtom) return

    atom.config.unset('latex.alwaysOpenResultInAtom')
    atom.config.set('latex.opener', 'pdf-view')
  }
}
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');
var hirschUtils = require('./../util');
var generators = yeoman.generators;

var HirschGenerator = yeoman.generators.Base.extend({

  constructor: function () {
    // arguments and options should be
    // defined in the constructor.
    generators.Base.apply(this, arguments);
    this.appname = arguments['0'][0] || path.basename(process.cwd());
    this.askAppname = arguments['0'][0] ? false : true;
    this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

    if (!this.askAppname) {
      if (this.appname !== path.basename(process.cwd())) {
        this.destinationRoot(this.appname);
      }
    }
  },

  initializing: function () {
    this.projectConfig = require('./templates/_project.config.js')(true);
    this.projectConfig.date = hirschUtils.getCreationDate();
  },

  welcome: function () {
    this.log(yosay(
      'Welcome to the marvelous ' + chalk.red('Hirsch') + ' generator!'
    ));
  },

  prompting: function () {
    var done = this.async();
    var prompts = [];

    if (this.askAppname) {
      prompts.push({
        name:    'appname',
        message: 'What would you like to name the app?',
        default: this.appname || path.basename(process.cwd())
      });
    }

    prompts.push({
      name:    'prefix',
      message: 'Angular app prefix (2 chars):',
      default: 'my'
    });

    prompts.push({
      name:    'description',
      message: 'Describe your application:'
    });

    prompts.push({
      name: 'author',
      message: 'Who is the author?'
    });

    prompts.push({
      type: 'confirm',
      name: 'useTypescript',
      message: 'Do you want to use TypeScript?',
      default: false
    });

    prompts.push({
      when: function (props) {
        return props.useTypescript;
      },
      name: 'typingsPath',
      message: 'Where do you want to store the type definitions (path relative to root)?',
      default: 'typings'
    });

    this.prompt(prompts, function (props) {
      if (this.askAppname) {
        this.appname = props.appname;
        if (this.appname !== path.basename(process.cwd())) {
          this.destinationRoot(this.appname);
        }
      }

      this.prefix = props.prefix;
      this.description = props.description;
      this.author = props.author;
      this.useTypescript = props.useTypescript;
      this.typingsPath = props.typingsPath;

      done();
    }.bind(this));
  },

  /**
    * INIT
    * Declare some helper functions
    */
  init: function() {
    var _this = this;
    var copyBase = function(copyFunc) {
      var rest = Array.prototype.slice.call(arguments, 1);
      return function () {
        var args = Array.prototype.slice.call(arguments);
        var newRest = rest.slice(0);
        if (typeof args[0] === 'object') {
          newRest.push(args.shift());
        }

        var tgtSegs = args.map(function (s) {
          return (_this.useTypescript ? s.replace(/\.js$/, '.ts') : s).replace(/\.js!$/, '.js');
        });

        var srcSegs = tgtSegs.map(function (s) {
          var replaces = [
            { p: /^app$/, r: 'app-ts' },
            { p: /^app\//, r: 'app-ts/' },
            { p: /^test$/, r: 'test-ts' },
            { p: /^test\//, r: 'test-ts/' }
          ];

          var copiesScripts = args.some(function(s) {
            return /\.js$/.test(s);
          });

          return _this.useTypescript && copiesScripts
            ? replaces.reduce(function (prev, curr) { return prev.replace(curr.p, curr.r); }, s)
            : s;
        }).map(function (s) { return s.replace(/!$/, ''); });

        // filter out globs from target path
        tgtSegs = tgtSegs.filter(function(s) {
          return s.indexOf('*') < 0 && !/!$/.test(s);
        });

        var srcPath = path.join.apply(null, srcSegs);
        var tgtPath = path.join.apply(null, tgtSegs);
        console.log(srcPath + ' -> ' + tgtPath);
        copyFunc.apply(null, [_this.templatePath(srcPath), _this.destinationPath(tgtPath)].concat(newRest));
      };
    }

    this.copyFile = copyBase(this.fs.copy.bind(this.fs));
    this.copyTpl = copyBase(this.fs.copyTpl.bind(this.fs), this.projectConfig);
    this.copyDir = copyBase(this.directory.bind(this));
  },

  addToProjectConfig: function () {
    this.projectConfig.prompts = {};
    this.projectConfig.prompts.appname = this.appname;
    this.projectConfig.prompts.prefix = this.prefix;
    this.projectConfig.prompts.description = this.description;
    this.projectConfig.prompts.author = this.author;
    this.projectConfig.prompts.useTypescript = this.useTypescript;
    this.projectConfig.prompts.typingsPath = this.typingsPath;
  },

  displayName: function () {
    this.log('Creating ' + this.appname + ' app based on Hirsch.');
  },

  scaffoldFolders: function () {
    this.mkdir('src');
    this.mkdir('src/app');
    this.mkdir('src/app/common/services');
    this.mkdir('src/app/common/directives');
    this.mkdir('src/app/common/templates');
    this.mkdir('src/app/common/decorators');
    this.mkdir('src/app/common/filters');
    this.mkdir('src/app/common/views');
    this.mkdir('src/app/core');
    this.mkdir('src/assets');
    this.mkdir('src/assets/medias');
    this.mkdir('src/assets/fonts');
    this.mkdir('src/assets/less');
    this.mkdir('src/assets/i18n');
    this.mkdir('src/lib');
    this.mkdir('test');
    this.mkdir('test/lib');
    this.mkdir('test/unit');
    this.mkdir('test/midway');
    this.mkdir('test/e2e');
  },

  packageFiles: function () {
    this.template('_package.json', 'package.json', this.projectConfig);
    this.template('_bower.json', 'bower.json', this.projectConfig);
    this.template('_bowerrc', '.bowerrc', this.projectConfig);
  },

  taskRunner: function () {
    this.template('_gulpfile.js', 'gulpfile.js', this.projectConfig);
    this.copyTpl(this.projectConfig.path.taskDir, '*.js!');

    if (this.projectConfig.prompts.useTypescript) {
      this.copyTpl(this.projectConfig.path.taskDir, 'ts!', '*.js!');
    } else {
      this.copyTpl(this.projectConfig.path.taskDir, 'js!', '*.js!');
    }
  },

  projectfiles: function () {
    this.copy('_project.config.js', 'project.config.js');
    this.copy('_editorconfig', '.editorconfig');
    this.copy('_gitignore', '.gitignore');

    if (this.projectConfig.prompts.useTypescript) {
      this.fs.copyTpl(this.templatePath('_tsd.json'), this.destinationPath('tsd.json'), this.projectConfig);
      this.fs.copy(this.templatePath('_tsconfig.json'), this.destinationPath('tsconfig.json'));
      this.fs.copy(this.templatePath('_tslint.json'), this.destinationPath('tslint.json'));
    } else {
      this.fs.copy(this.templatePath('_jshintrc'), this.destinationPath('.jshintrc'));
    }
  },

  assets: function () {
    this.copyDir(this.projectConfig.path.srcDir, this.projectConfig.path.assetsDir);
  },

  testRunnerFiles: function () {
    this.template('_karma-midway.config.js', 'karma-midway.config.js', this.projectConfig);
    this.template('_karma-shared.config.js', 'karma-shared.config.js', this.projectConfig);
    this.template('_karma-unit.config.js', 'karma-unit.config.js', this.projectConfig);

    this.copyTpl(this.projectConfig.path.testDir, '**', '*.js');
  },

  appFiles: function () {
    // Index
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.main);

    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.main);
  },

  coreFiles: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.coreDir, '**', '*.js');
  },

  commonFiles: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.commonDir, '**', '*.js');
  },

  layoutFiles: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.layoutDir, '**', '*.js');
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.layoutDir, '**', '*.html');
  },

  homeExample: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.appDir, 'home', '**', '*.js');
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.appDir, 'home', '**', '*.html');
  },

  runNpm: function () {
    this.npmInstall();
    this.bowerInstall();
  },

  installTypeDefs: function () {
    // download type definitions if TypeScript was enabled
    if (this.useTypescript) {
      this.env.runLoop.add('install', function (done) {
        this.emit('tsdReinstall');

        this.log('Running ' + chalk.yellow.bold('tsd reinstall --save') + '. If this fails run the commands yourself after running `npm install -g tsd`.');

        this.spawnCommand('node', ['node_modules/tsd/build/cli.js', 'reinstall', '--save'])
          .on('exit', function (err) {
            if (err === 127) {
              this.log.error('Could not find tsd. Please install with `npm install -g tsd`.');
            }
            this.emit('tsdReinstall:end');
            done();
          }.bind(this));
      }.bind(this), { once: 'tsd reinstall', run: false });
    }
  },

  end: function () {
    this.log('');
    this.log(hirschUtils.hirschSay());
    this.log('Go to your project folder and run ' + chalk.bold.yellow('gulp serve'));
    this.log('Then visit your app on ' + chalk.bold.yellow('http://localhost:3000'));
    this.log('');
  }
});

module.exports = HirschGenerator;
<commit_msg>fix(app): gitignore<commit_after>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');
var hirschUtils = require('./../util');
var generators = yeoman.generators;

var HirschGenerator = yeoman.generators.Base.extend({

  constructor: function () {
    // arguments and options should be
    // defined in the constructor.
    generators.Base.apply(this, arguments);
    this.appname = arguments['0'][0] || path.basename(process.cwd());
    this.askAppname = arguments['0'][0] ? false : true;
    this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

    if (!this.askAppname) {
      if (this.appname !== path.basename(process.cwd())) {
        this.destinationRoot(this.appname);
      }
    }
  },

  initializing: function () {
    this.projectConfig = require('./templates/_project.config.js')(true);
    this.projectConfig.date = hirschUtils.getCreationDate();
  },

  welcome: function () {
    this.log(yosay(
      'Welcome to the marvelous ' + chalk.red('Hirsch') + ' generator!'
    ));
  },

  prompting: function () {
    var done = this.async();
    var prompts = [];

    if (this.askAppname) {
      prompts.push({
        name:    'appname',
        message: 'What would you like to name the app?',
        default: this.appname || path.basename(process.cwd())
      });
    }

    prompts.push({
      name:    'prefix',
      message: 'Angular app prefix (2 chars):',
      default: 'my'
    });

    prompts.push({
      name:    'description',
      message: 'Describe your application:'
    });

    prompts.push({
      name:    'author',
      message: 'Who is the author?'
    });

    prompts.push({
      type:    'confirm',
      name:    'useTypescript',
      message: 'Do you want to use TypeScript?',
      default: false
    });

    prompts.push({
      when:    function (props) {
        return props.useTypescript;
      },
      name:    'typingsPath',
      message: 'Where do you want to store the type definitions (path relative to root)?',
      default: 'typings'
    });

    this.prompt(prompts, function (props) {
      if (this.askAppname) {
        this.appname = props.appname;
        if (this.appname !== path.basename(process.cwd())) {
          this.destinationRoot(this.appname);
        }
      }

      this.prefix = props.prefix;
      this.description = props.description;
      this.author = props.author;
      this.useTypescript = props.useTypescript;
      this.typingsPath = props.typingsPath;

      done();
    }.bind(this));
  },

  /**
   * INIT
   * Declare some helper functions
   */
  init: function () {
    var _this = this;
    var copyBase = function (copyFunc) {
      var rest = Array.prototype.slice.call(arguments, 1);
      return function () {
        var args = Array.prototype.slice.call(arguments);
        var newRest = rest.slice(0);
        if (typeof args[0] === 'object') {
          newRest.push(args.shift());
        }

        var tgtSegs = args.map(function (s) {
          return (_this.useTypescript ? s.replace(/\.js$/, '.ts') : s).replace(/\.js!$/, '.js');
        });

        var srcSegs = tgtSegs.map(function (s) {
          var replaces = [
            {p: /^app$/, r: 'app-ts'},
            {p: /^app\//, r: 'app-ts/'},
            {p: /^test$/, r: 'test-ts'},
            {p: /^test\//, r: 'test-ts/'}
          ];

          var copiesScripts = args.some(function (s) {
            return /\.js$/.test(s);
          });

          return _this.useTypescript && copiesScripts
            ? replaces.reduce(function (prev, curr) {
            return prev.replace(curr.p, curr.r);
          }, s)
            : s;
        }).map(function (s) {
          return s.replace(/!$/, '');
        });

        // filter out globs from target path
        tgtSegs = tgtSegs.filter(function (s) {
          return s.indexOf('*') < 0 && !/!$/.test(s);
        });

        var srcPath = path.join.apply(null, srcSegs);
        var tgtPath = path.join.apply(null, tgtSegs);
        console.log(srcPath + ' -> ' + tgtPath);
        copyFunc.apply(null, [_this.templatePath(srcPath), _this.destinationPath(tgtPath)].concat(newRest));
      };
    };

    this.copyFile = copyBase(this.fs.copy.bind(this.fs));
    this.copyTpl = copyBase(this.fs.copyTpl.bind(this.fs), this.projectConfig);
    this.copyDir = copyBase(this.directory.bind(this));
  },

  addToProjectConfig: function () {
    this.projectConfig.prompts = {};
    this.projectConfig.prompts.appname = this.appname;
    this.projectConfig.prompts.prefix = this.prefix;
    this.projectConfig.prompts.description = this.description;
    this.projectConfig.prompts.author = this.author;
    this.projectConfig.prompts.useTypescript = this.useTypescript;
    this.projectConfig.prompts.typingsPath = this.typingsPath;
  },

  displayName: function () {
    this.log('Creating ' + this.appname + ' app based on Hirsch.');
  },

  scaffoldFolders: function () {
    this.mkdir('src');
    this.mkdir('src/app');
    this.mkdir('src/app/common/services');
    this.mkdir('src/app/common/directives');
    this.mkdir('src/app/common/templates');
    this.mkdir('src/app/common/decorators');
    this.mkdir('src/app/common/filters');
    this.mkdir('src/app/common/views');
    this.mkdir('src/app/core');
    this.mkdir('src/assets');
    this.mkdir('src/assets/medias');
    this.mkdir('src/assets/fonts');
    this.mkdir('src/assets/less');
    this.mkdir('src/assets/i18n');
    this.mkdir('src/lib');
    this.mkdir('test');
    this.mkdir('test/lib');
    this.mkdir('test/unit');
    this.mkdir('test/midway');
    this.mkdir('test/e2e');
  },

  packageFiles: function () {
    this.template('_package.json', 'package.json', this.projectConfig);
    this.template('_bower.json', 'bower.json', this.projectConfig);
    this.template('_bowerrc', '.bowerrc', this.projectConfig);
  },

  taskRunner: function () {
    this.template('_gulpfile.js', 'gulpfile.js', this.projectConfig);
    this.copyTpl(this.projectConfig.path.taskDir, '*.js!');

    if (this.projectConfig.prompts.useTypescript) {
      this.copyTpl(this.projectConfig.path.taskDir, 'ts!', '*.js!');
    } else {
      this.copyTpl(this.projectConfig.path.taskDir, 'js!', '*.js!');
    }
  },

  projectfiles: function () {
    this.copy('_project.config.js', 'project.config.js');
    this.copy('_editorconfig', '.editorconfig');
    this.template('_gitignore', '.gitignore', this.projectConfig);

    if (this.projectConfig.prompts.useTypescript) {
      this.fs.copyTpl(this.templatePath('_tsd.json'), this.destinationPath('tsd.json'), this.projectConfig);
      this.fs.copy(this.templatePath('_tsconfig.json'), this.destinationPath('tsconfig.json'));
      this.fs.copy(this.templatePath('_tslint.json'), this.destinationPath('tslint.json'));
    } else {
      this.fs.copy(this.templatePath('_jshintrc'), this.destinationPath('.jshintrc'));
    }
  },

  assets: function () {
    this.copyDir(this.projectConfig.path.srcDir, this.projectConfig.path.assetsDir);
  },

  testRunnerFiles: function () {
    this.template('_karma-midway.config.js', 'karma-midway.config.js', this.projectConfig);
    this.template('_karma-shared.config.js', 'karma-shared.config.js', this.projectConfig);
    this.template('_karma-unit.config.js', 'karma-unit.config.js', this.projectConfig);

    this.copyTpl(this.projectConfig.path.testDir, '**', '*.js');
  },

  appFiles: function () {
    // Index
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.main);

    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.main);
  },

  coreFiles: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.coreDir, '**', '*.js');
  },

  commonFiles: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.commonDir, '**', '*.js');
  },

  layoutFiles: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.layoutDir, '**', '*.js');
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.app.layoutDir, '**', '*.html');
  },

  homeExample: function () {
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.appDir, 'home', '**', '*.js');
    this.copyTpl(this.projectConfig.path.srcDir, this.projectConfig.path.appDir, 'home', '**', '*.html');
  },

  runNpm: function () {
    this.npmInstall();
    this.bowerInstall();
  },

  installTypeDefs: function () {
    // download type definitions if TypeScript was enabled
    if (this.useTypescript) {
      this.env.runLoop.add('install', function (done) {
        this.emit('tsdReinstall');

        this.log('Running ' + chalk.yellow.bold('tsd reinstall --save') + '. If this fails run the commands yourself after running `npm install -g tsd`.');

        this.spawnCommand('node', ['node_modules/tsd/build/cli.js', 'reinstall', '--save'])
          .on('exit', function (err) {
            if (err === 127) {
              this.log.error('Could not find tsd. Please install with `npm install -g tsd`.');
            }
            this.emit('tsdReinstall:end');
            done();
          }.bind(this));
      }.bind(this), {once: 'tsd reinstall', run: false});
    }
  },

  end: function () {
    this.log('');
    this.log(hirschUtils.hirschSay());
    this.log('Go to your project folder and run ' + chalk.bold.yellow('gulp serve'));
    this.log('Then visit your app on ' + chalk.bold.yellow('http://localhost:3000'));
    this.log('');
  }
});

module.exports = HirschGenerator;
<|endoftext|>


<commit_before>import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';

import createHistory from 'history/createBrowserHistory';
import 'sanitize.css/sanitize.css';

import { IS_DEV_ENV, IS_PROD_ENV } from 'common/constants';
import { PersistGate } from 'redux-persist/lib/integration/react';

// Import default LoadingComponent provider and LoadingIndicator that will be used as a loading component
import DefaultLoadingComponentProvider from 'common/components/Loadable/DefaultLoadingComponentProvider';
import ErrorBoundary from 'common/components/ErrorBoundary';

// Load the favicon, the manifest.json file and the .htaccess file
/* eslint-disable import/no-unresolved, import/extensions */
import '!file-loader?name=[name].[ext]!./favicon.ico';
import '!file-loader?name=[name].[ext]!./favicon.png';
import '!file-loader?name=[name].[ext]!./manifest.json';
import 'file-loader?name=[name].[ext]!./.htaccess'; // eslint-disable-line import/extensions
/* eslint-enable import/no-webpack-loader-syntax */

// Import CSS reset and Global Styles
import 'common/styles/global';

import configureStore from './store/configureStore';

// Create redux store with history
const initialState = {};
const history = createHistory();
const { persistor, store } = configureStore(initialState, history);
const MOUNT_NODE = document.getElementById('app');

const render = () => {
  // Dynamically import our main App component, and render it
  const App = require('pages/App').default;

  ReactDOM.render(
    <ErrorBoundary>
      <DefaultLoadingComponentProvider component={null}>
        <Provider store={store}>
          <PersistGate persistor={persistor}>
            <ConnectedRouter history={history}>
              <App />
            </ConnectedRouter>
          </PersistGate>
        </Provider>
      </DefaultLoadingComponentProvider>
    </ErrorBoundary>,
    MOUNT_NODE
  );
};

if (module.hot) {
  module.hot.accept('pages/App', () => {
    ReactDOM.unmountComponentAtNode(MOUNT_NODE);
    render();
  });
}

render();

// Install ServiceWorker and AppCache in the end since
// it's not most important operation and if main code fails,
// we do not want it installed
if (IS_PROD_ENV) {
  const runtime = require('offline-plugin/runtime');
  runtime.install({
    onUpdating: () => {
      console.log('SW Event:', 'updating');
    },
    onUpdateReady: () => {
      // Tell new SW to take control immediately
      runtime.applyUpdate();
      window.alert('Kaniwani has been updated and will reload shortly.');
    },
    onUpdated: () => {
      console.log('SW Event:', 'update successful');
      // TODO: set sessionStorage item to inform user after refresh
      // Reload the webpage to load into the new version
      window.location.reload();
    },

    onUpdateFailed: () => {
      console.warn('SW Event:', 'update failed');
    },
  });
}

/* eslint-disable */
// Trace component updates to determine any necessary perf optimizations
if (IS_DEV_ENV) {
  // From devtools console:
  // To enable temporarily: Why();
  // To enable until disabled (even after refresh): Why(true);
  // To disable: Why(false);
  const Why = (enabled) => {
    if (enabled) {
      console.debug('why-did-you-update always');
      window.localStorage.setItem('why-did-you-update', true);
    } else if (enabled === false) {
      console.debug('why-did-you-update never');
      window.localStorage.removeItem('why-did-you-update');
      React.__WHY_DID_YOU_UPDATE_RESTORE_FN__ && React.__WHY_DID_YOU_UPDATE_RESTORE_FN__();
      return;
    }
    console.debug('why-did-you-update enabled');
    const { whyDidYouUpdate } = require('why-did-you-update');
    whyDidYouUpdate(React);
  };

  window.Why = Why;
  if (window.localStorage.getItem('why-did-you-update')) {
    Why();
  }
}
/* eslint-enable */
<commit_msg>feat: add serviceworker update alert<commit_after>import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';

import createHistory from 'history/createBrowserHistory';
import 'sanitize.css/sanitize.css';

import { VERSION, IS_PROD_ENV } from 'common/constants';
import { PersistGate } from 'redux-persist/lib/integration/react';

// Import default LoadingComponent provider and LoadingIndicator that will be used as a loading component
import DefaultLoadingComponentProvider from 'common/components/Loadable/DefaultLoadingComponentProvider';
import ErrorBoundary from 'common/components/ErrorBoundary';

// Load the favicon, the manifest.json file and the .htaccess file
/* eslint-disable import/no-unresolved, import/extensions */
import '!file-loader?name=[name].[ext]!./favicon.ico';
import '!file-loader?name=[name].[ext]!./favicon.png';
import '!file-loader?name=[name].[ext]!./manifest.json';
/* eslint-enable import/no-webpack-loader-syntax */

// Import CSS reset and Global Styles
import 'common/styles/global';

import configureStore from './store/configureStore';

// Create redux store with history
const initialState = {};
const history = createHistory();
const { persistor, store } = configureStore(initialState, history);
const MOUNT_NODE = document.getElementById('app');

const render = () => {
  // Dynamically import our main App component, and render it
  const App = require('pages/App').default;

  ReactDOM.render(
    <ErrorBoundary>
      <DefaultLoadingComponentProvider component={null}>
        <Provider store={store}>
          <PersistGate persistor={persistor}>
            <ConnectedRouter history={history}>
              <App />
            </ConnectedRouter>
          </PersistGate>
        </Provider>
      </DefaultLoadingComponentProvider>
    </ErrorBoundary>,
    MOUNT_NODE
  );
};

if (module.hot) {
  module.hot.accept('pages/App', () => {
    ReactDOM.unmountComponentAtNode(MOUNT_NODE);
    render();
  });
}

render();

// Install ServiceWorker and AppCache in the end since
// it's not most important operation and if main code fails,
// we do not want it installed
if (IS_PROD_ENV) {
  const runtime = require('offline-plugin/runtime');
  runtime.install({
    onUpdateReady: () => {
      console.info(`Kaniwani ${VERSION}: update ready`);
      // Tell new SW to take control immediately
      runtime.applyUpdate();
    },
    onUpdating: () => {
      console.info(`Kaniwani ${VERSION}: updating`);
    },
    onUpdated: () => {
      console.info(`Kaniwani ${VERSION}: update successful`);
      window.alert(`Kaniwani has been updated to ${VERSION} and will now reload.`);
      window.location.reload();
    },

    onUpdateFailed: () => {
      console.warn(`Kaniwani ${VERSION}: update failed`);
    },
  });
}

/* eslint-disable */
// Trace component updates to determine any necessary perf optimizations
//   // From devtools console:
//   // To enable temporarily: Why();
//   // To enable until disabled (even after refresh): Why(true);
//   // To disable: Why(false);
//   const Why = (enabled) => {
//     if (enabled) {
//       console.debug('why-did-you-update always');
//       window.localStorage.setItem('why-did-you-update', true);
//     } else if (enabled === false) {
//       console.debug('why-did-you-update never');
//       window.localStorage.removeItem('why-did-you-update');
//       React.__WHY_DID_YOU_UPDATE_RESTORE_FN__ && React.__WHY_DID_YOU_UPDATE_RESTORE_FN__();
//       return;
//     }
//     console.debug('why-did-you-update enabled');
//     const { whyDidYouUpdate } = require('why-did-you-update');
//     whyDidYouUpdate(React);
//   };

//   window.Why = Why;
//   if (window.localStorage.getItem('why-did-you-update')) {
//     Why();
//   }
/* eslint-enable */
<|endoftext|>


<commit_before>'use strict';

const cheerio = require('cheerio');
const Promise = require('bluebird');
// const minimatch = require('minimatch');

function concatJS(data) {
  const hexo = this;
  const options = hexo.config.js_concator;
  // Reture if disabled.
  if (options.enable === false) return;

  const log = hexo.log || console;
  const route = hexo.route;
  const routeList = route.list();

  // let include = options.include;
  // if (include && !Array.isArray(include)) include = [include];

  // 1. get all local scripts
  const htmls = {};
  const bundlePath = options.bundle_path;
  const front = options.front;
  return Promise.all(routeList.filter(path => path.endsWith('.html')).map(path => {
    // 1. get the htmls that has local scripts
    return new Promise((resolve, reject) => {
      const html = route.get(path);
      let htmlTxt = '';
      html.on('data', (chunk) => (htmlTxt += chunk));
      html.on('end', () => {
        const $ = cheerio.load(htmlTxt, { decodeEntities: false });
        const $scripts = {};
        const srcs = [];
        $('script[src]').each((idx, ele) => {
          const $script = $(ele);
          let src = $script.attr('src');
          if (src && src.length) {
            // local script
            if (!src.startsWith('//') && !src.startsWith('http')) {
              src = route.format(src);
              // ignore and remove duplicated
              if (srcs.indexOf(src) === -1) {
                srcs.push(src);
                $scripts[src] = $script;
              } else {
                $script.remove();
              }
            }
          }
        });
        if (srcs.length) {
          htmls[path] = { path, $, srcs, $scripts };
        }
        resolve();
      });
    });
  }))
    // 2. extract common scripts
    .then(() => {
      const htmlPaths = Object.keys(htmls);
      const scripts = [];
      // collect the scripts
      for (const path of htmlPaths) {
        const html = htmls[path];
        const srcs = html.srcs;
        for (let i = srcs.length - 1; i >= 0; --i) { // reverse for deletion
          const src = srcs[i];
          if (scripts.indexOf(src) === -1) {
            // if a script exists in more than one htmls,
            // TODO, or match the pattern in exclude array
            const count = htmlPaths.reduce((sum, path) => (htmls[path].srcs.indexOf(src) !== -1 ? ++sum : sum), 0);
            if (count > 1) {
              // remove
              log[options.silent ? 'debug' : 'info']('update Concate JS: remove %s from %s', src, path);
              html.$scripts[src].remove();
              delete html.$scripts[src];
              srcs.splice(srcs.indexOf(src), 1);
              scripts.push(src);
            }
            // if (htmlPaths.every(path => htmls[path].srcs.indexOf(src) !== -1) ||
            //   include.some(pattern => minimatch(src, pattern, { matchBase: true }))) {
            // }
          } else {
            // remove
            log[options.silent ? 'debug' : 'info']('update Concate JS: remove %s from %s', src, path);
            html.$scripts[src].remove();
            delete html.$scripts[src];
            srcs.splice(srcs.indexOf(src), 1);
          }
        }
        html.srcs = srcs;
      }

      if (scripts.length > 1) {
        // add the bundle script to all html
        for (const path of htmlPaths) {
          const html = htmls[path];
          if (front) {
            html.$(`<script type="text/javascript" src="${route.format(bundlePath)}"></script>`).insertBefore(html.$('body>script').first());
          } else {
            html.$('body').append(`<script type="text/javascript" src="/${route.format(bundlePath)}"></script>`);
          }
          route.set(path, html.$.html());
          log[options.silent ? 'debug' : 'info']('update Concate JS: add /%s to %s', route.format(bundlePath), path);
        }
      }
      return scripts.reverse();
    })
    // 3. concat the script
    .then((scripts) => {
      if (scripts.length < 1) return;
      log[options.silent ? 'debug' : 'info']('update Concate JS: try to concat %s scripts', scripts.length);
      return Promise.all(scripts.map(path => {
        return new Promise((resolve, reject) => {
          const script = route.get(path);
          let scriptTxt = '';
          script.on('data', chunk => (scriptTxt += chunk));
          script.on('end', () => {
            route.remove(path);
            log[options.silent ? 'debug' : 'info']('update Concate JS: concat script %s', path);
            resolve(scriptTxt);
          });
        });
      })).then(results => {
        const bundleScript = results.reduce((txt, script) => (txt += script), '');
        route.set(route.format(bundlePath), bundleScript);
        log[options.silent ? 'debug' : 'info']('update Concate JS: finish concat js script');
      });
    });
}

module.exports = concatJS;
<commit_msg>fix: script could be undefined<commit_after>'use strict';

const cheerio = require('cheerio');
const Promise = require('bluebird');
// const minimatch = require('minimatch');

function concatJS(data) {
  const hexo = this;
  const options = hexo.config.js_concator;
  // Reture if disabled.
  if (options.enable === false) return;

  const log = hexo.log || console;
  const route = hexo.route;
  const routeList = route.list();

  // let include = options.include;
  // if (include && !Array.isArray(include)) include = [include];

  // 1. get all local scripts
  const htmls = {};
  const bundlePath = options.bundle_path;
  const front = options.front;
  return Promise.all(routeList.filter(path => path.endsWith('.html')).map(path => {
    // 1. get the htmls that has local scripts
    return new Promise((resolve, reject) => {
      const html = route.get(path);
      let htmlTxt = '';
      html.on('data', (chunk) => (htmlTxt += chunk));
      html.on('end', () => {
        const $ = cheerio.load(htmlTxt, { decodeEntities: false });
        const $scripts = {};
        const srcs = [];
        $('script[src]').each((idx, ele) => {
          const $script = $(ele);
          let src = $script.attr('src');
          if (src && src.length) {
            // local script
            if (!src.startsWith('//') && !src.startsWith('http')) {
              src = route.format(src);
              // ignore and remove duplicated
              if (srcs.indexOf(src) === -1) {
                srcs.push(src);
                $scripts[src] = $script;
              } else {
                $script.remove();
              }
            }
          }
        });
        if (srcs.length) {
          htmls[path] = { path, $, srcs, $scripts };
        }
        resolve();
      });
    });
  }))
    // 2. extract common scripts
    .then(() => {
      const htmlPaths = Object.keys(htmls);
      const scripts = [];
      // collect the scripts
      for (const path of htmlPaths) {
        const html = htmls[path];
        const srcs = html.srcs;
        for (let i = srcs.length - 1; i >= 0; --i) { // reverse for deletion
          const src = srcs[i];
          if (scripts.indexOf(src) === -1) {
            // if a script exists in more than one htmls,
            // TODO, or match the pattern in exclude array
            const count = htmlPaths.reduce((sum, path) => (htmls[path].srcs.indexOf(src) !== -1 ? ++sum : sum), 0);
            if (count > 1) {
              // remove
              log[options.silent ? 'debug' : 'info']('update Concate JS: remove %s from %s', src, path);
              html.$scripts[src].remove();
              delete html.$scripts[src];
              srcs.splice(srcs.indexOf(src), 1);
              scripts.push(src);
            }
            // if (htmlPaths.every(path => htmls[path].srcs.indexOf(src) !== -1) ||
            //   include.some(pattern => minimatch(src, pattern, { matchBase: true }))) {
            // }
          } else {
            // remove
            log[options.silent ? 'debug' : 'info']('update Concate JS: remove %s from %s', src, path);
            html.$scripts[src].remove();
            delete html.$scripts[src];
            srcs.splice(srcs.indexOf(src), 1);
          }
        }
        html.srcs = srcs;
      }

      if (scripts.length > 1) {
        // add the bundle script to all html
        for (const path of htmlPaths) {
          const html = htmls[path];
          if (front) {
            html.$(`<script type="text/javascript" src="${route.format(bundlePath)}"></script>`).insertBefore(html.$('body>script').first());
          } else {
            html.$('body').append(`<script type="text/javascript" src="/${route.format(bundlePath)}"></script>`);
          }
          route.set(path, html.$.html());
          log[options.silent ? 'debug' : 'info']('update Concate JS: add /%s to %s', route.format(bundlePath), path);
        }
      }
      return scripts.reverse();
    })
    // 3. concat the script
    .then((scripts) => {
      if (scripts.length < 1) return;
      log[options.silent ? 'debug' : 'info']('update Concate JS: try to concat %s scripts', scripts.length);
      return Promise.all(scripts.map(path => {
        return new Promise((resolve, reject) => {
          const script = route.get(path);
          let scriptTxt = '';
          if (!script) {
            log[options.silent ? 'debug' : 'info']('update Concate JS: script %s is not found, skipping', path);
            route.remove(path);
            resolve("");
            return;
          }
          script.on('data', chunk => (scriptTxt += chunk));
          script.on('end', () => {
            route.remove(path);
            log[options.silent ? 'debug' : 'info']('update Concate JS: concat script %s', path);
            resolve(scriptTxt);
          });
        });
      })).then(results => {
        const bundleScript = results.reduce((txt, script) => (txt += script), '');
        route.set(route.format(bundlePath), bundleScript);
        log[options.silent ? 'debug' : 'info']('update Concate JS: finish concat js script');
      });
    });
}

module.exports = concatJS;
<|endoftext|>


<commit_before>'use strict';

var path   = require( 'path' );
var util   = require( 'util' );
var yeoman = require( 'yeoman-generator' );
var yosay  = require( 'yosay' );

var CustomGenerator = module.exports = function CustomGenerator( args, options, config ) {

  yeoman.generators.Base.apply( this, arguments );
  this.pkg = JSON.parse( this.readFileAsString( path.join( __dirname, '../package.json' ) ) );

};

util.inherits( CustomGenerator, yeoman.generators.Base );

CustomGenerator.prototype.prompting = function prompting () {

  // Let Yeoman welcome the user.
  console.log( yosay() );

  var prompts = [
    {
      name: 'projectName',
      message: 'What would you like to call your project?'
    }
  ];

  var callback = this.async();
  this.prompt( prompts, function ( answers ) {

    this.projectName = answers.projectName;
    callback();

  }.bind( this ) );

};

CustomGenerator.prototype.install = function install () {

  var sourcePath = this.sourceRoot( path.resolve( __dirname, '../node_modules/loopback-angular-ui-router' ) );

  // Copy whole directories.
  this.directory( path.join( sourcePath, 'app' ),     path.join( this.projectName, 'app' )    );
  this.directory( path.join( sourcePath, 'server' ),  path.join( this.projectName, 'server' ) );
  this.directory( path.join( sourcePath, 'test' ),    path.join( this.projectName, 'test' )   );

  // List out the files to copy.
  var files = [
    '.bowerrc',
    '.editorconfig',
    '.gitattributes',
    '.jshintignore',
    '.jshintrc',
    '.travis.yml',
    '.yo-rc.json',
    'bower.json',
    'Gruntfile.js',
    'karma.conf.js',
    'karma-e2e.conf.js',
    'package.json'
  ];

  // Copy all of the files to the destination.
  var self = this;
  files.forEach( function ( filePath ) {
    self.copy(
      path.join( sourcePath, filePath ),
      path.join( self.projectName, filePath )
    );
  } );

  // Copy the .gitignore since it's named weirdly to prevent npm from removing it.
  self.copy(
    path.join( sourcePath, '_.gitignore' ),
    path.join( self.projectName, '.gitignore' )
  );

};

CustomGenerator.prototype.end = function end () {

  // Change into the generated folder.
  process.chdir( path.join( process.cwd(), this.projectName ) );
  console.log( '\n\nChanging directory to ./' + this.projectName + ' so you\'ll be ready to go when I\mm finished.' );

  // Install dependencies with npm/bower.
  this.installDependencies( {
    bower: true,
    npm: true,
    skipInstall: false,
    callback: function () {
      console.log( 'Everything is ready to go! Enjoy.\n' );
    }
  } );

};<commit_msg>Added an automatic 'grunt build' call to the generator.<commit_after>'use strict';

var path   = require( 'path' );
var util   = require( 'util' );
var yeoman = require( 'yeoman-generator' );
var yosay  = require( 'yosay' );

var CustomGenerator = module.exports = function CustomGenerator( args, options, config ) {

  yeoman.generators.Base.apply( this, arguments );
  this.pkg = JSON.parse( this.readFileAsString( path.join( __dirname, '../package.json' ) ) );

};

util.inherits( CustomGenerator, yeoman.generators.Base );

CustomGenerator.prototype.prompting = function prompting () {

  // Let Yeoman welcome the user.
  console.log( yosay() );

  var prompts = [
    {
      name: 'projectName',
      message: 'What would you like to call your project?'
    }
  ];

  var callback = this.async();
  this.prompt( prompts, function ( answers ) {

    this.projectName = answers.projectName;
    callback();

  }.bind( this ) );

};

CustomGenerator.prototype.install = function install () {

  var sourcePath = this.sourceRoot( path.resolve( __dirname, '../node_modules/loopback-angular-ui-router' ) );

  // Copy whole directories.
  this.directory( path.join( sourcePath, 'app' ),     path.join( this.projectName, 'app' )    );
  this.directory( path.join( sourcePath, 'server' ),  path.join( this.projectName, 'server' ) );
  this.directory( path.join( sourcePath, 'test' ),    path.join( this.projectName, 'test' )   );

  // List out the files to copy.
  var files = [
    '.bowerrc',
    '.editorconfig',
    '.gitattributes',
    '.jshintignore',
    '.jshintrc',
    '.travis.yml',
    '.yo-rc.json',
    'bower.json',
    'Gruntfile.js',
    'karma.conf.js',
    'karma-e2e.conf.js',
    'package.json'
  ];

  // Copy all of the files to the destination.
  var self = this;
  files.forEach( function ( filePath ) {
    self.copy(
      path.join( sourcePath, filePath ),
      path.join( self.projectName, filePath )
    );
  } );

  // Copy the .gitignore since it's named weirdly to prevent npm from removing it.
  self.copy(
    path.join( sourcePath, '_.gitignore' ),
    path.join( self.projectName, '.gitignore' )
  );

};

CustomGenerator.prototype.end = function end () {

  // Change into the generated folder.
  process.chdir( path.join( process.cwd(), this.projectName ) );

  // Install dependencies with npm/bower.
  var self = this;
  self.installDependencies( {
    bower: true,
    npm: true,
    skipInstall: false,
    callback: function () {
      self.spawnCommand( 'grunt', [ 'build', '--base ./' + self.projectName ] );
    }
  } );

};<|endoftext|>


<commit_before>/**
 * @namespace Consumer
 */
var amqp = require('amqplib'),
  utils = require('./helpers/utils'),
  parsers = require('./helpers/message-parsers');

var config;
var connected = false;
var connecting = false;
var reqQueue = [];
var consumptions = [];
var amqpUrl, amqpConnection, amqpChannel, amqpIntervalId;
var reconnection = false;

/**
 * Create tcp coonection between Consumer and rabbitmq server
 * @memberOf Consumer
 * @param  {String} _amqpUrl - amqp url used to connect to rabbitmq server
 * @return {Promise} - channel
 */
var connect = function(_amqpUrl) {
  if (connected) {
    return Promise.resolve(amqpChannel);
  }

  if (connecting) {
    var deferred = new Promise(function(resolve) { resolve(); });
    reqQueue.push(deferred);
    return deferred;
  }

  connecting = true;

  amqpUrl = utils.getValidUrl([amqpUrl, _amqpUrl, config.amqpUrl, process.env.AMQP_URL, 'amqp://localhost']);

  return amqp.connect(amqpUrl)
  .then(function (_connection) {
    amqpConnection = _connection;

    amqpIntervalId = clearInterval(amqpIntervalId);

    amqpConnection.on('close', reconnect);
    amqpConnection.on('error', reconnect);

    return createChannel();
  })
  .catch(catchError);
};

/**
 * Create channel
 * @memberOf Consumer
 * @return {Promise} - channel
 */
var createChannel = function() {
  return amqpConnection.createChannel()
  .then(function (_amqpChannel) {
    Logger.info('[BMQ-CONSUMER] is now connected and ready to consume messages');

    amqpChannel = _amqpChannel;
    amqpChannel.prefetch(config.prefetch || process.env.AMQP_PREFETCH);

    connected = true;
    connecting = false;

    amqpIntervalId = clearInterval(amqpIntervalId);

    amqpChannel.on('close', reconnect);
    amqpChannel.on('error', reconnect);

    while (reqQueue.length > 0) {
      reqQueue.shift()();
    }

    if (reconnection) {
      reconnection = false;
      for (var i = 0, l = consumptions.length; i < l; ++i) {
        consume(consumptions[i].queue, consumptions[i].options, consumptions[i].callback);
      }
    }

    return amqpChannel;
  })
  .catch(catchError);
};

/**
 * Reconnect after a timeout
 * @memberOf Consumer
 * @return {Nothing}
 */
var reconnect  = function() {
  if (!amqpIntervalId) {
    Logger.info('[BMQ-CONSUMER] Try to reconnect');
    connecting = false;
    connected = false;
    reconnection = true;
    amqpIntervalId = setInterval(connect, 1000);
  }
};

/**
 * Disconnect from server
 * @memberOf Consumer
 * @return {Promise}
 */
var disconnect = function() {
  if (amqpConnection && amqpChannel) {
    return amqpChannel.close()
    .then(function () {
      return amqpConnection.close();
    })
    .then(function () {
      connecting = false;
      connected = false;
      reqQueue = [];
      amqpUrl = undefined;
      amqpConnection = undefined;
      amqpChannel = undefined;
      amqpIntervalId = clearInterval(amqpIntervalId);
      Logger.info('[BMQ-CONSUMER] is now disconnected');
    });
  }
};

function catchError(err) {
  amqpIntervalId = clearInterval(amqpIntervalId);
  Logger.error('[BMQ-CONSUMER] ', err.stack, '\n    occured while connecting');
  reconnect();
}

function checkRpc(_msg, _queue) {
  return function(content) {
    if (content !== undefined && _msg.properties.replyTo) {
      var options = { correlationId: _msg.properties.correlationId };
      Logger.info('[BMQ-CONSUMER][' + _queue + '] > ', content);
      amqpChannel.sendToQueue(_msg.properties.replyTo, parsers.out(content, options), options);
    }

    return _msg;
  };
}

/**
 * Consume message from queue
 * @memberOf Consumer
 * @param {String} _queue - queue name
 * @param {String} _options - options
 * @param {String} _callback - callback to call after receiving msg
 * @return {Promise} queue
 */
var consume = function(_queue, _options, _callback) {
  if (typeof _options === 'function') {
    _callback = _options;
    _options = { persistent: true, durable: true };
  }

  utils.pushIfNotExist('consumer', consumptions, {
    queue: _queue,
    options: _options,
    callback: _callback
  });

  if (!connected) {
    return connect().then(function() {
      return consume(_queue, _options, _callback);
    });
  }

  _queue += (process.env.LOCAL_QUEUE ? process.env.LOCAL_QUEUE : '');

  return amqpChannel.assertQueue(_queue, _options)
  .then(function (_q) {
    amqpChannel.consume(_q.queue, function(msg) {
      Logger.info('[BMQ-CONSUMER][' + _queue + '] < ' + msg.content.toString());

      Promise.resolve(parsers.in(msg))
      .then(_callback)
      .then(checkRpc(msg, _queue))
      .then(function() {
        amqpChannel.ack(msg);
      })
      .catch(function (e) {
        Logger.error('[BMQ-CONSUMER] error on queue: ' + _queue, e);
        amqpChannel.reject(msg, config.isRequeueEnabled);
      });
    }, { noAck: false });

    return true;
  });
};

module.exports = function (_config) {
  config = _config;

  return {
    connect: connect,
    disconnect: disconnect,
    consume: consume
  };
};
<commit_msg>Add function init<commit_after>/**
 * @namespace Consumer
 */
var amqp = require('amqplib'),
  utils = require('./helpers/utils'),
  parsers = require('./helpers/message-parsers');

var config;
var connected = false;
var connecting = false;
var reconnection = false;
var reqQueue = [];
var consumptions = [];
var amqpUrl, amqpConnection, amqpChannel, amqpIntervalId;

function init() {
  connected = false;
  connecting = false;
  reconnection = false;
  reqQueue = [];
  consumptions = [];
  amqpUrl = undefined;
  amqpConnection = undefined;
  amqpChannel = undefined;
  amqpIntervalId = clearInterval(amqpIntervalId);
}

/**
 * Create tcp coonection between Consumer and rabbitmq server
 * @memberOf Consumer
 * @param  {String} _amqpUrl - amqp url used to connect to rabbitmq server
 * @return {Promise} - channel
 */
var connect = function(_amqpUrl) {
  if (connected) {
    return Promise.resolve(amqpChannel);
  }

  if (connecting) {
    var deferred = new Promise(function(resolve) { resolve(); });
    reqQueue.push(deferred);
    return deferred;
  }

  connecting = true;

  amqpUrl = utils.getValidUrl([amqpUrl, _amqpUrl, config.amqpUrl, process.env.AMQP_URL, 'amqp://localhost']);

  return amqp.connect(amqpUrl)
  .then(function (_connection) {
    amqpConnection = _connection;

    amqpIntervalId = clearInterval(amqpIntervalId);

    amqpConnection.on('close', reconnect);
    amqpConnection.on('error', reconnect);

    return createChannel();
  })
  .catch(catchError);
};

/**
 * Create channel
 * @memberOf Consumer
 * @return {Promise} - channel
 */
var createChannel = function() {
  return amqpConnection.createChannel()
  .then(function (_amqpChannel) {
    Logger.info('[BMQ-CONSUMER] is now connected and ready to consume messages');

    amqpChannel = _amqpChannel;
    amqpChannel.prefetch(config.prefetch || process.env.AMQP_PREFETCH);

    connected = true;
    connecting = false;

    amqpIntervalId = clearInterval(amqpIntervalId);

    amqpChannel.on('close', reconnect);
    amqpChannel.on('error', reconnect);

    while (reqQueue.length > 0) {
      reqQueue.shift()();
    }

    if (reconnection) {
      reconnection = false;
      for (var i = 0, l = consumptions.length; i < l; ++i) {
        consume(consumptions[i].queue, consumptions[i].options, consumptions[i].callback);
      }
    }

    return amqpChannel;
  })
  .catch(catchError);
};

/**
 * Reconnect after a timeout
 * @memberOf Consumer
 * @return {Nothing}
 */
var reconnect = function() {
  if (!amqpIntervalId) {
    Logger.info('[BMQ-CONSUMER] Try to reconnect');
    connecting = false;
    connected = false;
    reconnection = true;
    amqpIntervalId = setInterval(connect, 1000);
  }
};

/**
 * Disconnect from server
 * @memberOf Consumer
 * @return {Promise}
 */
var disconnect = function() {
  if (amqpConnection && amqpChannel) {
    return amqpChannel.close()
    .then(function () {
      return amqpConnection.close();
    })
    .then(function () {
      init();
      Logger.info('[BMQ-CONSUMER] is now disconnected');
    });
  }
};

function catchError(err) {
  amqpIntervalId = clearInterval(amqpIntervalId);
  Logger.error('[BMQ-CONSUMER] ', err.stack, '\n    occured while connecting');
  reconnect();
}

function checkRpc(_msg, _queue) {
  return function(content) {
    if (content !== undefined && _msg.properties.replyTo) {
      var options = { correlationId: _msg.properties.correlationId };
      Logger.info('[BMQ-CONSUMER][' + _queue + '] > ', content);
      amqpChannel.sendToQueue(_msg.properties.replyTo, parsers.out(content, options), options);
    }

    return _msg;
  };
}

/**
 * Consume message from queue
 * @memberOf Consumer
 * @param {String} _queue - queue name
 * @param {String} _options - options
 * @param {String} _callback - callback to call after receiving msg
 * @return {Promise} queue
 */
var consume = function(_queue, _options, _callback) {
  if (typeof _options === 'function') {
    _callback = _options;
    _options = { persistent: true, durable: true };
  }

  utils.pushIfNotExist('consumer', consumptions, {
    queue: _queue,
    options: _options,
    callback: _callback
  });

  if (!connected) {
    return connect().then(function() {
      return consume(_queue, _options, _callback);
    });
  }

  _queue += (process.env.LOCAL_QUEUE ? process.env.LOCAL_QUEUE : '');

  return amqpChannel.assertQueue(_queue, _options)
  .then(function (_q) {
    amqpChannel.consume(_q.queue, function(msg) {
      Logger.info('[BMQ-CONSUMER][' + _queue + '] < ' + msg.content.toString());

      Promise.resolve(parsers.in(msg))
      .then(_callback)
      .then(checkRpc(msg, _queue))
      .then(function() {
        amqpChannel.ack(msg);
      })
      .catch(function (e) {
        Logger.error('[BMQ-CONSUMER] error on queue: ' + _queue, e);
        amqpChannel.reject(msg, config.isRequeueEnabled);
      });
    }, { noAck: false });

    return true;
  });
};

module.exports = function (_config) {
  config = _config;

  return {
    connect: connect,
    disconnect: disconnect,
    consume: consume
  };
};
<|endoftext|>


<commit_before>'use strict';
const Generator = require('yeoman-generator');

const licenses = [
  { name: 'Apache 2.0', value: 'Apache-2.0' },
  { name: 'MIT', value: 'MIT' },
  { name: 'Mozilla Public License 2.0', value: 'MPL-2.0' },
  { name: 'BSD 2-Clause (FreeBSD) License', value: 'BSD-2-Clause-FreeBSD' },
  { name: 'BSD 3-Clause (NewBSD) License', value: 'BSD-3-Clause' },
  { name: 'Internet Systems Consortium (ISC) License', value: 'ISC' },
  { name: 'GNU AGPL 3.0', value: 'AGPL-3.0' },
  { name: 'GNU GPL 3.0', value: 'GPL-3.0' },
  { name: 'GNU LGPL 3.0', value: 'LGPL-3.0' },
  { name: 'Unlicense', value: 'unlicense' },
  { name: 'No License (Copyrighted)', value: 'UNLICENSED' }
];

module.exports = class GeneratorLicense extends Generator {
  constructor(args, opts) {
    super(args, opts);

    this.option('name', {
      type: String,
      desc: 'Name of the license owner',
      required: false
    });

    this.option('email', {
      type: String,
      desc: 'Email of the license owner',
      required: false
    });

    this.option('website', {
      type: String,
      desc: 'Website of the license owner',
      required: false
    });

    this.option('year', {
      type: String,
      desc: 'Year(s) to include on the license',
      required: false,
      defaults: new Date().getFullYear()
    });

    this.option('licensePrompt', {
      type: String,
      desc: 'License prompt text',
      defaults: 'Which license do you want to use?',
      hide: true,
      required: false
    });

    this.option('defaultLicense', {
      type: String,
      desc: 'Default license',
      required: false
    });

    this.option('license', {
      type: String,
      desc:
        'Select a license, so no license prompt will happen, in case you want to handle it outside of this generator',
      required: false
    });

    this.option('output', {
      type: String,
      desc: 'Set the output file for the generated license',
      required: false,
      defaults: 'LICENSE'
    });
  }

  initializing() {
    this.gitc = {
      user: {
        name: this.user.git.name(),
        email: this.user.git.email()
      }
    };
  }

  prompting() {
    const prompts = [
      {
        name: 'name',
        message: "What's your name:",
        default: this.options.name || this.gitc.user.name,
        when: this.options.name === null || this.options.name === undefined
      },
      {
        name: 'email',
        message: 'Your email (optional):',
        default: this.options.email || this.gitc.user.email,
        when: !this.options.email
      },
      {
        name: 'website',
        message: 'Your website (optional):',
        default: this.options.website,
        when: !this.options.website
      },
      {
        type: 'list',
        name: 'license',
        message: this.options.licensePrompt,
        default: this.options.defaultLicense,
        when:
          !this.options.license ||
          licenses.find(x => x.value === this.options.license) === undefined,
        choices: licenses
      }
    ];

    return this.prompt(prompts).then(props => {
      this.props = Object.assign(
        {
          name: this.options.name,
          email: this.options.email,
          website: this.options.website,
          license: this.options.license
        },
        props
      );
    });
  }

  writing() {
    // License file
    const filename = this.props.license + '.txt';
    let author = this.props.name.trim();
    if (this.props.email) {
      author += ' <' + this.props.email.trim() + '>';
    }
    if (this.props.website) {
      author += ' (' + this.props.website.trim() + ')';
    }

    this.fs.copyTpl(
      this.templatePath(filename),
      this.destinationPath(this.options.output),
      {
        year: this.options.year,
        author: author
      }
    );

    // Package
    if (!this.fs.exists(this.destinationPath('package.json'))) {
      return;
    }

    const pkg = this.fs.readJSON(this.destinationPath('package.json'), {});
    pkg.license = this.props.license;

    // We don't want users to publish their module to NPM if they copyrighted
    // their content.
    if (this.props.license === 'UNLICENSED') {
      delete pkg.license;
      pkg.private = true;
    }

    this.fs.writeJSON(this.destinationPath('package.json'), pkg);
  }
};

module.exports.licenses = licenses;
<commit_msg>Undefined or null (#87)<commit_after>'use strict';
const Generator = require('yeoman-generator');

const licenses = [
  { name: 'Apache 2.0', value: 'Apache-2.0' },
  { name: 'MIT', value: 'MIT' },
  { name: 'Mozilla Public License 2.0', value: 'MPL-2.0' },
  { name: 'BSD 2-Clause (FreeBSD) License', value: 'BSD-2-Clause-FreeBSD' },
  { name: 'BSD 3-Clause (NewBSD) License', value: 'BSD-3-Clause' },
  { name: 'Internet Systems Consortium (ISC) License', value: 'ISC' },
  { name: 'GNU AGPL 3.0', value: 'AGPL-3.0' },
  { name: 'GNU GPL 3.0', value: 'GPL-3.0' },
  { name: 'GNU LGPL 3.0', value: 'LGPL-3.0' },
  { name: 'Unlicense', value: 'unlicense' },
  { name: 'No License (Copyrighted)', value: 'UNLICENSED' }
];

module.exports = class GeneratorLicense extends Generator {
  constructor(args, opts) {
    super(args, opts);

    this.option('name', {
      type: String,
      desc: 'Name of the license owner',
      required: false
    });

    this.option('email', {
      type: String,
      desc: 'Email of the license owner',
      required: false
    });

    this.option('website', {
      type: String,
      desc: 'Website of the license owner',
      required: false
    });

    this.option('year', {
      type: String,
      desc: 'Year(s) to include on the license',
      required: false,
      defaults: new Date().getFullYear()
    });

    this.option('licensePrompt', {
      type: String,
      desc: 'License prompt text',
      defaults: 'Which license do you want to use?',
      hide: true,
      required: false
    });

    this.option('defaultLicense', {
      type: String,
      desc: 'Default license',
      required: false
    });

    this.option('license', {
      type: String,
      desc:
        'Select a license, so no license prompt will happen, in case you want to handle it outside of this generator',
      required: false
    });

    this.option('output', {
      type: String,
      desc: 'Set the output file for the generated license',
      required: false,
      defaults: 'LICENSE'
    });
  }

  initializing() {
    this.gitc = {
      user: {
        name: this.user.git.name(),
        email: this.user.git.email()
      }
    };
  }

  prompting() {
    const prompts = [
      {
        name: 'name',
        message: "What's your name:",
        default: this.options.name || this.gitc.user.name,
        when: this.options.name === undefined
      },
      {
        name: 'email',
        message: 'Your email (optional):',
        default: this.options.email || this.gitc.user.email,
        when: this.options.email === undefined
      },
      {
        name: 'website',
        message: 'Your website (optional):',
        default: this.options.website,
        when: this.options.website === undefined
      },
      {
        type: 'list',
        name: 'license',
        message: this.options.licensePrompt,
        default: this.options.defaultLicense,
        when:
          !this.options.license ||
          licenses.find(x => x.value === this.options.license) === undefined,
        choices: licenses
      }
    ];

    return this.prompt(prompts).then(props => {
      this.props = Object.assign(
        {
          name: this.options.name,
          email: this.options.email,
          website: this.options.website,
          license: this.options.license
        },
        props
      );
    });
  }

  writing() {
    // License file
    const filename = this.props.license + '.txt';
    let author = this.props.name.trim();
    if (this.props.email) {
      author += ' <' + this.props.email.trim() + '>';
    }
    if (this.props.website) {
      author += ' (' + this.props.website.trim() + ')';
    }

    this.fs.copyTpl(
      this.templatePath(filename),
      this.destinationPath(this.options.output),
      {
        year: this.options.year,
        author: author
      }
    );

    // Package
    if (!this.fs.exists(this.destinationPath('package.json'))) {
      return;
    }

    const pkg = this.fs.readJSON(this.destinationPath('package.json'), {});
    pkg.license = this.props.license;

    // We don't want users to publish their module to NPM if they copyrighted
    // their content.
    if (this.props.license === 'UNLICENSED') {
      delete pkg.license;
      pkg.private = true;
    }

    this.fs.writeJSON(this.destinationPath('package.json'), pkg);
  }
};

module.exports.licenses = licenses;
<|endoftext|>


<commit_before>var accessToken = localStorage.getItem("accessToken");

var STATES = {
  INIT: 'init',
  LOADING: 'loading',
  LOADED: 'loaded',
  ERROR: 'error'
};

var CONSTS = {
  SHOW_PHOTO_DURATION_IN_SECONDS: 20,
  REFRESH_MEDIA_INTERVAL_IN_MINUTES: 5
};

var dataSource;
var mediaToShow;
var currMediaIndex = -1;
var imgElement;
var ribbonElement;
var lastUpdateAt;
var state = STATES.INIT;
var errorCount = 0;

var imgContainerElement;
var loadingContainerElement;

window.onload = function() {
  imgContainerElement = document.getElementById("imgcontainer");
  imgElement = document.getElementById('mainimg');
  loadingContainerElement = document.getElementById('loadingcontainer');
  ribbonElement = document.getElementById('ribbon');
  loadMedia();
}

function setState(newState) {
  loadingContainerElement.textContent = newState;
  state = newState;
}

function setErrorState() {
  setState(STATES.ERROR);
  // Try to reload media in 2 min
  errorCount++;

  // Wait at most 10 minutes for retry
  var retryDelay = Math.min(10, errorCount) * 60 * 1000;
  setTimeout(loadMedia, retryDelay);
}

function loadMedia() {

  if (state === STATES.LOADING) return;

  var isAlreadyLoaded = (state === STATES.LOADED);
  setState(STATES.LOADING);

  var xhr = new XMLHttpRequest();
  xhr.timeout = 8000; //60 * 1000; // timeout of 1 minute

  var url = '/photos';
  xhr.open('GET', url);
  xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);

  xhr.ontimeout = function () {
    setErrorState();
  };

  xhr.onerror = function() {
    setErrorState();
  }

  xhr.onload = function(e) {
    if (this.status === 401) {
      // unauthorized
      location = 'https://ran-smart-frame.appspot.com/authorize';
      return;
    } else if (this.status !== 200) {
      setErrorState();
      return;
    };

    errorCount = 0;
    lastUpdateAt = new Date();
    dataSource = JSON.parse(this.response);
    mediaToShow = dataSource.Media.slice(); // make a copy

    // TODO: we should not suffle if the dataSource is the same as the last one we got to ensure we show all the pictures before suffle again.
    shuffle(mediaToShow);

    setState(STATES.LOADED);

    if (!isAlreadyLoaded) {
      //debug - loadingContainerElement.style.display = 'none';
      imgContainerElement.style.display = 'block';

      showNextPhoto();
    }
  };

  xhr.send();
}

function showNextPhoto() {
  checkMediaFreshness();

  currMediaIndex++;
  if (currMediaIndex > mediaToShow.length - 1) {
    currMediaIndex = 0;
  }

  imgElement.src = mediaToShow[currMediaIndex].URL;

  var timePicTaken = new Date(parseInt(mediaToShow[currMediaIndex].Timestamp));
  var pointInTime = new Date(2015, 1, 27, 0, 0, 0, 0);
  var duration = moment.duration(timePicTaken - pointInTime);

  var durationString;
  if (duration.asYears() < 1.1) {
    durationString = duration.humanize();
  } else {
    durationString = duration.years() + 'y ';
    if (duration.months() > 0) {
       durationString += duration.months() + 'm'
    }
  }
  ribbonElement.innerText = durationString;

  setTimeout(showNextPhoto, CONSTS.SHOW_PHOTO_DURATION_IN_SECONDS * 1000);
}

function checkMediaFreshness() {
  var now = new Date();
  var diffMs = (now - lastUpdateAt);
  var diffMin = diffMs / 1000 / 60;

  if (diffMin > CONSTS.REFRESH_MEDIA_INTERVAL_IN_MINUTES) {
    loadMedia();
    return true;
  }

  return false;
}

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}
<commit_msg>Fix time since event calculation<commit_after>var accessToken = localStorage.getItem("accessToken");

var STATES = {
  INIT: 'init',
  LOADING: 'loading',
  LOADED: 'loaded',
  ERROR: 'error'
};

var CONSTS = {
  SHOW_PHOTO_DURATION_IN_SECONDS: 20,
  REFRESH_MEDIA_INTERVAL_IN_MINUTES: 5
};

var dataSource;
var mediaToShow;
var currMediaIndex = -1;
var imgElement;
var ribbonElement;
var lastUpdateAt;
var state = STATES.INIT;
var errorCount = 0;

var imgContainerElement;
var loadingContainerElement;

window.onload = function() {
  imgContainerElement = document.getElementById("imgcontainer");
  imgElement = document.getElementById('mainimg');
  loadingContainerElement = document.getElementById('loadingcontainer');
  ribbonElement = document.getElementById('ribbon');
  loadMedia();
}

function setState(newState) {
  loadingContainerElement.textContent = newState;
  state = newState;
}

function setErrorState() {
  setState(STATES.ERROR);
  // Try to reload media in 2 min
  errorCount++;

  // Wait at most 10 minutes for retry
  var retryDelay = Math.min(10, errorCount) * 60 * 1000;
  setTimeout(loadMedia, retryDelay);
}

function loadMedia() {

  if (state === STATES.LOADING) return;

  var isAlreadyLoaded = (state === STATES.LOADED);
  setState(STATES.LOADING);

  var xhr = new XMLHttpRequest();
  xhr.timeout = 8000; //60 * 1000; // timeout of 1 minute

  var url = '/photos';
  xhr.open('GET', url);
  xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);

  xhr.ontimeout = function () {
    setErrorState();
  };

  xhr.onerror = function() {
    setErrorState();
  }

  xhr.onload = function(e) {
    if (this.status === 401) {
      // unauthorized
      location = 'https://ran-smart-frame.appspot.com/authorize';
      return;
    } else if (this.status !== 200) {
      setErrorState();
      return;
    };

    errorCount = 0;
    lastUpdateAt = new Date();
    dataSource = JSON.parse(this.response);
    mediaToShow = dataSource.Media.slice(); // make a copy

    // TODO: we should not suffle if the dataSource is the same as the last one we got to ensure we show all the pictures before suffle again.
    shuffle(mediaToShow);

    setState(STATES.LOADED);

    if (!isAlreadyLoaded) {
      //debug - loadingContainerElement.style.display = 'none';
      imgContainerElement.style.display = 'block';

      showNextPhoto();
    }
  };

  xhr.send();
}

function showNextPhoto() {
  checkMediaFreshness();

  currMediaIndex++;
  if (currMediaIndex > mediaToShow.length - 1) {
    currMediaIndex = 0;
  }

  imgElement.src = mediaToShow[currMediaIndex].URL;

  var timePicTaken = new Date(parseInt(mediaToShow[currMediaIndex].Timestamp));
  var pointInTime = new Date(2015, 1, 27, 0, 0, 0, 0);
  var duration = moment.duration(pointInTime - timePicTaken);

  var durationString;
  if (duration.asYears() < 1.1) {
    durationString = duration.humanize();
  } else {
    durationString = duration.years() + 'y ';
    if (duration.months() > 0) {
       durationString += duration.months() + 'm'
    }
  }
  ribbonElement.innerText = durationString;

  setTimeout(showNextPhoto, CONSTS.SHOW_PHOTO_DURATION_IN_SECONDS * 1000);
}

function checkMediaFreshness() {
  var now = new Date();
  var diffMs = (now - lastUpdateAt);
  var diffMin = diffMs / 1000 / 60;

  if (diffMin > CONSTS.REFRESH_MEDIA_INTERVAL_IN_MINUTES) {
    loadMedia();
    return true;
  }

  return false;
}

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

var AngularModuleGenerator = module.exports = function AngularModuleGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function() {
    this.installDependencies({
      skipInstall: options['skip-install']
    });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(AngularModuleGenerator, yeoman.generators.Base);

AngularModuleGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var prompts = [{
    type: 'input',
    name: 'moduleName',
    message: 'Name of your module?',
    default: 'ngMod'
  }, {
    type: 'input',
    name: 'moduleDescription',
    message: 'Module short description...'
  }, {
    type: 'input',
    name: 'version',
    message: 'Module initial version'
  }, {
    type: 'input',
    name: 'author',
    message: '... And you are?'
  }, {
    type: 'input',
    name: 'email',
    message: '... your email address?'
  },
  {
    type: 'input',
    name: 'repository',
    message: 'git repo address?'
  },
  {
    type: 'input',
    name: 'registry',
    message: '... a private bower registry for your module ...',
    default: 'http://localhost:8888'
  }];

  this.prompt(prompts, function(props) {
    this.moduleName = props.moduleName;
    this.author = props.author;
    this.email = props.email;
    this.moduleDescription = props.moduleDescription;
    this.version = props.version;
    this.registry = props.registry;
    this.repository = props.repository;
    cb();
  }.bind(this));
};

AngularModuleGenerator.prototype.app = function app() {
  this.mkdir('app');
  this.copy('appjshintrc', 'app/.jshintrc');
  this.mkdir('app/js');
  this.mkdir('app/js/angular');
  this.mkdir('app/js/vendor');
  this.template('_app.js', 'app/js/angular/app.js');

  this.mkdir('test');
  this.copy('testjshintrc', 'test/.jshintrc');
  this.mkdir('test/spec');
  this.mkdir('test/spec/angular');
  this.mkdir('test/spec/angular/services');
  this.mkdir('test/spec/angular/factories');
  this.mkdir('test/spec/angular/filters');
  this.mkdir('test/vendor');
};

AngularModuleGenerator.prototype.projectfiles = function projectfiles() {
  this.copy('mainjshintrc', '.jshintrc');
  this.template('_Gruntfile.js', 'Gruntfile.js');

  this.mkdir('conf');
  this.copy('karma.conf.js', 'conf/karma.conf.js');
  this.copy('karma.e2e.conf.js', 'conf/karma.e2e.conf.js');

  this.copy('gitignore', '.gitignore');
  this.template('_README.md', 'README.md');

  this.template('_package.json', 'package.json');
  this.template('_bower.json', 'bower.json');
  this.template('_bowerrc', '.bowerrc');
};
<commit_msg>fix config location<commit_after>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

var AngularModuleGenerator = module.exports = function AngularModuleGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function() {
    this.installDependencies({
      skipInstall: options['skip-install']
    });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(AngularModuleGenerator, yeoman.generators.Base);

AngularModuleGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var prompts = [{
    type: 'input',
    name: 'moduleName',
    message: 'Name of your module?',
    default: 'ngMod'
  }, {
    type: 'input',
    name: 'moduleDescription',
    message: 'Module short description...'
  }, {
    type: 'input',
    name: 'version',
    message: 'Module initial version'
  }, {
    type: 'input',
    name: 'author',
    message: '... And you are?'
  }, {
    type: 'input',
    name: 'email',
    message: '... your email address?'
  },
  {
    type: 'input',
    name: 'repository',
    message: 'git repo address?'
  },
  {
    type: 'input',
    name: 'registry',
    message: '... a private bower registry for your module ...',
    default: 'http://localhost:8888'
  }];

  this.prompt(prompts, function(props) {
    this.moduleName = props.moduleName;
    this.author = props.author;
    this.email = props.email;
    this.moduleDescription = props.moduleDescription;
    this.version = props.version;
    this.registry = props.registry;
    this.repository = props.repository;
    cb();
  }.bind(this));
};

AngularModuleGenerator.prototype.app = function app() {
  this.mkdir('app');
  this.copy('appjshintrc', 'app/.jshintrc');
  this.mkdir('app/js');
  this.mkdir('app/js/angular');
  this.mkdir('app/js/vendor');
  this.template('_app.js', 'app/js/angular/app.js');

  this.mkdir('test');
  this.copy('testjshintrc', 'test/.jshintrc');
  this.mkdir('test/spec');
  this.mkdir('test/spec/angular');
  this.mkdir('test/spec/angular/services');
  this.mkdir('test/spec/angular/factories');
  this.mkdir('test/spec/angular/filters');
  this.mkdir('test/vendor');
};

AngularModuleGenerator.prototype.projectfiles = function projectfiles() {
  this.copy('mainjshintrc', '.jshintrc');
  this.template('_Gruntfile.js', 'Gruntfile.js');

  this.mkdir('config');
  this.copy('karma.conf.js', 'config/karma.conf.js');
  this.copy('karma.e2e.conf.js', 'config/karma.e2e.conf.js');

  this.copy('gitignore', '.gitignore');
  this.template('_README.md', 'README.md');

  this.template('_package.json', 'package.json');
  this.template('_bower.json', 'bower.json');
  this.template('_bowerrc', '.bowerrc');
};
<|endoftext|>