<commit_before>import Utils from './utils'
import {isGitUrl, isBinaryFile} from './helpers'
import W from 'when'
import node from 'when/node'
import which from 'which'
import path from 'path'
import yaml from 'js-yaml'
import minimatch from 'minimatch'
import lodash from 'lodash'
import Joi from 'joi'
import _rimraf from 'rimraf'
import _readdirp from 'readdirp'
import _fs from 'fs'
import _dns from 'dns'
import {exec as _exec} from 'child_process'
import {ncp as _ncp} from 'ncp'

const rimraf = node.lift(_rimraf)
const exec = node.lift(_exec)
const readdirp = node.lift(_readdirp)
const ncp = node.lift(_ncp)
const fs = node.liftAll(_fs, (pfs, lifted, name) => {
  pfs[`${name}Async`] = lifted
  return pfs
})
const dns = node.liftAll(_dns)

/*
 * Register CoffeeScript `init` file in template can be either CoffeeScript or
 * JavaScript.
 */

require('coffee-script/register')

/*
 * Given a Sprout instance and a name, returns a Template instance.
 * @param {Function} sprout - Sprout instance.
 * @param {String} name - Name of template
 * @param {String} src (optional) - Path or URL to source. Only required for
 * `template.save`.
 * @return {Function} - Template instance.
 */
class Template {

  constructor (_options) {
    const schema = Joi.object().keys({
      sprout: Joi.any().required(),
      name: Joi.string().required(),
      src: Joi.string(),
      rootFolderName: Joi.string().default('root'),
      generatorsFolderName: Joi.string().default('generators')
    })

    let options = Joi.validate(_options, schema)
    if (options.error) { throw options.error }
    options = options.value

    this.sprout = options.sprout
    this.name = options.name
    this.path = path.join(this.sprout.path, this.name)
    this.rootPath = path.join(this.path, options.rootFolderName)
    this.generatorsPath = path.join(this.path, options.generatorsFolderName)
    this.src = options.src
    if (this.src) { this.isRemote = isGitUrl(this.src) }
  }

  /*
   * Saves `template.src` to `template.path`
   * @return {Promise} - promise for Template instance.
   */
  save () {
    return W.resolve().with(this)
      .then(ensureGitInstall)
      .then(validateSource)
      .then(ensureInternetConnection)
      .then(removeTemplate)
      .then(moveSourceToSproutPath)
      .then(validateTemplate)
      .yield(this)
  }

  /*
   * Initialize template and save to `target`
   * @param {String} target - The path to save the template to.
   * @return {Promise} - Promise for Template instance.
   */
  init (target, opts = {}) {
    const utils = new Utils(this.path, target)
    const schema = Joi.object().keys({
      locals: Joi.object().default({}),
      tag: Joi.string(),
      branch: Joi.string(),
      configPath: Joi.string(),
      questionnaire: Joi.func()
    })

    Joi.assert(target, Joi.string().required().label('target'))

    return node.call(Joi.validate, opts, schema).with(this)
      .then((res) => { opts = res })
      .then(this.update.bind(this))
      .then(validateTarget.bind(this, target))
      .then(handleBranchOrTagOption.bind(this, opts))
      .then(createTargetDirectory.bind(this, target))
      .then(installDependenciesIfPresent)
      .then(() => {
        return W.resolve().with(this)
        .then(loadConfigFile)
        .then(runBeforeHook.bind(this, utils))
        .then(mergeConfig.bind(this, opts))
        .then(runPrompts.bind(this, opts))
        .then(copyTemplateToTarget.bind(this, target))
        .then(runBeforeRenderHook.bind(this, utils))
        .then(readTemplateFiles.bind(this, target))
        .then(removeIgnoredFiles)
        .then(writeTemplateFiles.bind(this, utils))
        .then(runAfterHook.bind(this, utils))
        .then(checkoutBranchIfPresent.bind(this, this.currentBranch))
        .catch((err) => { return rimraf(target).then(() => { throw err }) })
      }).yield(this)
  }

  /*
   * Update template source.
   * @return {Promise} - Promise for Template instance.
   */
  update () {
    // Confirm template is a git repository. If not, throw an error.
    if (!fs.existsSync(path.join(this.path, '.git'))) {
      return W.reject(new Error(`${this.name} is not a git repository`))
    }

    // If remote origin exists, run `git remote update` to update the
    // repository.
    this.sprout.emit('msg', 'updating template')
    this.sprout.emit('cmd', 'git remote', this.path)

    return exec('git remote', { cwd: this.path }).then((stdout) => {
      if (!stdout[0]) { return }
      const origin = lodash.trim(stdout[0])
      this.sprout.emit('cmd', `git pull ${origin} HEAD`, this.path)
      return exec(`git pull ${origin} HEAD`, { cwd: this.path })
    }).yield(this)
  }

  /*
   * Run a template generator in the specified target.
   * @param {String} target - the target path.
   * @param {String} name - the name of the generator to use.
   * @param {Object} args - arguments to be passed to the generator
   * @return {Promise} - Promise for Template instance.
   */
  run (target, generator, _args) {
    let args = { target: target, generator: generator, generatorArgs: _args }
    const schema = Joi.object().keys({
      target: Joi.string().required(),
      generator: Joi.string().required(),
      generatorArgs: Joi.array().default([])
    })

    return node.call(Joi.validate, args, schema)
      .then((res) => { args = res })
      .then(() => {
        if (!fs.existsSync(target)) {
          throw new Error(`${target} does not exist`)
        }
      })
      .then(validateGenerator.bind(this, args.generator))
      .then(executeGenerator.bind(this, args.target, args.generatorArgs))
      .yield(this)
  }

  /*
   * Delete the template.
   * @return {Promise} - Promise for Template instance.
   */
  remove () {
    // Resolve if path does not exist.
    if (!fs.existsSync(this.path)) { return W.resolve(this) }

    // rm -rf the path.
    this.sprout.emit('msg', 'removing template')

    return fs.lstatAsync(this.path).then((stat) => {
      if (stat.isSymbolicLink()) { return fs.unlink(this.path) }
      return rimraf(this.path)
    }).yield(this)
  }
}

//
// Utility Functions
//

function ensureGitInstall () {
  // Check if git is installed
  if (!which.sync('git')) {
    throw new Error('you need to have git installed')
  }
}

function validateSource () {
  if (!this.src) { throw new Error('no source provided') }

  if (!this.isRemote && !fs.existsSync(this.src)) {
    throw new Error(`there is no sprout template located at ${this.src}`)
  }

  if (!this.isRemote && !fs.existsSync(path.join(this.src, '.git'))) {
    throw new Error(`${this.src} is not a git repository`)
  }
}

// TODO is this needed? could replace with timeout
function ensureInternetConnection () {
  if (!this.isRemote) { return }
  return dns.resolve('google.com').catch(() => {
    throw new Error('make sure that you are connected to the internet!')
  })
}

function removeTemplate () {
  return this.remove()
}

function moveSourceToSproutPath () {
  if (this.isRemote) {
    this.sprout.emit('cmd', `git clone ${this.src} ${this.path}`)
    return exec(`git clone --recursive ${this.src} ${this.path}`)
  }

  return fs.symlinkAsync(this.src, this.path)
}

function validateTemplate () {
  return W.resolve().then(() => {
    if (!fs.existsSync(path.join(this.path, 'init.js')) && !fs.existsSync(path.join(this.path, 'init.coffee'))) {
      throw new Error('neither init.coffee nor init.js exist in this template')
    }

    // Check for root path.
    if (!fs.existsSync(this.rootPath)) {
      throw new Error('root path doesn\'t exist in template')
    }
  }).catch((error) => {
    return rimraf(this.path).then(() => { throw error })
  })
}

function validateTarget (target) {
  if (fs.existsSync(target)) { throw new Error(`${target} already exists`) }
}

function handleBranchOrTagOption (opts) {
  if (!(opts.tag || opts.branch)) { return }

  this.sprout.emit('cmd', 'git rev-parse --abbrev-ref HEAD', this.path)

  return exec('git rev-parse --abbrev-ref HEAD', { cwd: this.path })
    .spread((stdout) => { this.currentBranch = stdout })
    .then(checkoutBranchIfPresent.bind(this, opts.branch))
    .then(checkoutTagIfPresent.bind(this, opts.tag))
}

function checkoutBranchIfPresent (branch) {
  if (!branch) { return }
  this.sprout.emit('cmd', `git checkout ${branch}`, this.path)
  return exec(`git checkout ${branch}`, { cwd: this.path })
}

function checkoutTagIfPresent (tag) {
  if (!tag) { return }
  this.sprout.emit('cmd', `git checkout tags/${tag}`, this.path)
  return exec(`git checkout tags/${tag}`, { cwd: this.path })
}

function createTargetDirectory (target) {
  this.sprout.emit('msg', `creating target directory: ${target}`)
  return fs.mkdir(target)
}

function installDependenciesIfPresent () {
  if (!fs.existsSync(path.join(this.path, 'package.json'))) { return }
  this.sprout.emit('msg', 'installing npm dependencies')
  return exec('npm install', { cwd: this.path })
}

function loadConfigFile () {
  const initCoffee = path.join(this.path, 'init.coffee')
  const initJS = path.join(this.path, 'init.js')
  let initPath

  if (fs.existsSync(initJS)) {
    initPath = initJS
  } else if (fs.existsSync(initCoffee)) {
    initPath = initCoffee
  } else {
    throw new Error('neither init.coffee nor init.js exist')
  }

  this.sprout.emit('msg', `requiring ${initPath}`)
  this.init = require(initPath)
}

function runBeforeHook (utils) {
  if (this.init.before) {
    this.sprout.emit('msg', 'running before hook')
    return W(this.init.before(utils, this.config))
  }
}

function mergeConfig (opts) {
  this.config = {}

  // Merge in all known values for config.
  lodash.assign(this.config, this.init.defaults, opts.locals)

  // If a config path is set, pull out its values and merge into config.
  if (opts.configPath) {
    this.sprout.emit('msg', `merging config: ${opts.configPath}`)
    let externalConfig

    if (/\.json$/.test(opts.configPath)) {
      externalConfig = require(opts.configPath)
    } else {
      externalConfig = yaml.safeLoad(fs.readFileSync(opts.configPath, 'utf8'))
    }

    lodash.assign(this.config, externalConfig)
  }
}

// If questionnaire function exists, run it to get answers.
// Omitting keys already set in config return answers merged with config values.
function runPrompts (opts) {
  // TODO remove type check here after further joi additions
  if (opts.questionnaire && lodash.isArray(this.init.configure)) {
    this.sprout.emit('msg', 'running questionnaire function')
    return opts.questionnaire(this.init.configure, lodash.keys(this.config))
      .then((answers) => { return lodash.assign(this.config, answers) })
  }
}

function copyTemplateToTarget (target) {
  this.sprout.emit('msg', 'copying files in root to target')
  return ncp(this.rootPath, target)
}

function runBeforeRenderHook (utils) {
  if (this.init.beforeRender) {
    this.sprout.emit('msg', 'running beforeRender hook')
    return W(this.init.beforeRender(utils, this.config))
  }
}

function readTemplateFiles (target) {
  this.sprout.emit('msg', 'reading target directory')
  return readdirp({
    root: target,
    directoryFilter: ['!.git', '!node_modules']
  })
}

function removeIgnoredFiles (result) {
  return lodash.filter(result.files, (file) => {
    if (this.init.ignore) {
      this.init.ignore = Array.prototype.concat(this.init.ignore)
      for (var i = 0; i < this.init.ignore.length; i++) {
        if (minimatch(file.path, this.init.ignore[i])) {
          return false
        }
      }
    }
    return true
  })
}

function writeTemplateFiles (utils, files) {
  return W.map(files, (file) => {
    this.sprout.emit('msg', `reading ${file.fullPath}`)

    if (!isBinaryFile(file.fullPath)) {
      this.sprout.emit('msg', `reading ${file.fullPath}`)
      return utils.target.read(file.path).then((output) => {
        this.sprout.emit('msg', `writing ${file.fullPath}`)
        return utils.target.write(file.path, output, this.config)
      })
    }
  })
}

function runAfterHook (utils) {
  if (this.init.after) {
    this.sprout.emit('msg', 'running after hook')
    return W(this.init.after(utils, this.config))
  }
}

function validateGenerator (generator) {
  const generatorCoffee = path.join(this.generatorsPath, `${generator}.coffee`)
  const generatorJs = path.join(this.generatorsPath, `${generator}.js`)
  let generatorPath

  if (fs.existsSync(generatorJs)) {
    generatorPath = generatorJs
  } else if (fs.existsSync(generatorCoffee)) {
    generatorPath = generatorCoffee
  } else {
    throw new Error(`'${generator}' is not a generator in this template`)
  }

  this.sprout.emit('msg', `requiring '${generator}' generator`)
  return require(generatorPath)
}

function executeGenerator (target, args, generator) {
  const utils = new Utils(this.path, target)

  args = lodash.isArray(args) ? args : []
  args.unshift(utils)

  // Call the generator, pass the Utils instance and the arguments.
  this.sprout.emit('msg', `running ${generator} generator`)
  return generator.apply(null, args)
}

module.exports = Template
<commit_msg>validate init file<commit_after>import Utils from './utils'
import {isGitUrl, isBinaryFile} from './helpers'
import W from 'when'
import node from 'when/node'
import which from 'which'
import path from 'path'
import yaml from 'js-yaml'
import minimatch from 'minimatch'
import lodash from 'lodash'
import Joi from 'joi'
import _rimraf from 'rimraf'
import _readdirp from 'readdirp'
import _fs from 'fs'
import _dns from 'dns'
import {exec as _exec} from 'child_process'
import {ncp as _ncp} from 'ncp'

const rimraf = node.lift(_rimraf)
const exec = node.lift(_exec)
const readdirp = node.lift(_readdirp)
const ncp = node.lift(_ncp)
const fs = node.liftAll(_fs, (pfs, lifted, name) => {
  pfs[`${name}Async`] = lifted
  return pfs
})
const dns = node.liftAll(_dns)

/*
 * Register CoffeeScript `init` file in template can be either CoffeeScript or
 * JavaScript.
 */

require('coffee-script/register')

/*
 * Given a Sprout instance and a name, returns a Template instance.
 * @param {Function} sprout - Sprout instance.
 * @param {String} name - Name of template
 * @param {String} src (optional) - Path or URL to source. Only required for
 * `template.save`.
 * @return {Function} - Template instance.
 */
class Template {

  constructor (_options) {
    const schema = Joi.object().keys({
      sprout: Joi.any().required(),
      name: Joi.string().required(),
      src: Joi.string(),
      rootFolderName: Joi.string().default('root'),
      generatorsFolderName: Joi.string().default('generators')
    })

    let options = Joi.validate(_options, schema)
    if (options.error) { throw options.error }
    options = options.value

    this.sprout = options.sprout
    this.name = options.name
    this.path = path.join(this.sprout.path, this.name)
    this.rootPath = path.join(this.path, options.rootFolderName)
    this.generatorsPath = path.join(this.path, options.generatorsFolderName)
    this.src = options.src
    if (this.src) { this.isRemote = isGitUrl(this.src) }
  }

  /*
   * Saves `template.src` to `template.path`
   * @return {Promise} - promise for Template instance.
   */
  save () {
    return W.resolve().with(this)
      .then(ensureGitInstall)
      .then(validateSource)
      .then(ensureInternetConnection)
      .then(removeTemplate)
      .then(moveSourceToSproutPath)
      .then(validateTemplate)
      .yield(this)
  }

  /*
   * Initialize template and save to `target`
   * @param {String} target - The path to save the template to.
   * @return {Promise} - Promise for Template instance.
   */
  init (target, opts = {}) {
    const utils = new Utils(this.path, target)
    const schema = Joi.object().keys({
      locals: Joi.object().default({}),
      tag: Joi.string(),
      branch: Joi.string(),
      configPath: Joi.string(),
      questionnaire: Joi.func()
    })

    Joi.assert(target, Joi.string().required().label('target'))

    return node.call(Joi.validate, opts, schema).with(this)
      .then((res) => { opts = res })
      .then(this.update.bind(this))
      .then(validateTarget.bind(this, target))
      .then(handleBranchOrTagOption.bind(this, opts))
      .then(createTargetDirectory.bind(this, target))
      .then(installDependenciesIfPresent)
      .then(() => {
        return W.resolve().with(this)
        .then(loadConfigFile)
        .then(runBeforeHook.bind(this, utils))
        .then(mergeConfig.bind(this, opts))
        .then(runPrompts.bind(this, opts))
        .then(copyTemplateToTarget.bind(this, target))
        .then(runBeforeRenderHook.bind(this, utils))
        .then(readTemplateFiles.bind(this, target))
        .then(removeIgnoredFiles)
        .then(writeTemplateFiles.bind(this, utils))
        .then(runAfterHook.bind(this, utils))
        .then(checkoutBranchIfPresent.bind(this, this.currentBranch))
        .catch((err) => { return rimraf(target).then(() => { throw err }) })
      }).yield(this)
  }

  /*
   * Update template source.
   * @return {Promise} - Promise for Template instance.
   */
  update () {
    // Confirm template is a git repository. If not, throw an error.
    if (!fs.existsSync(path.join(this.path, '.git'))) {
      return W.reject(new Error(`${this.name} is not a git repository`))
    }

    // If remote origin exists, run `git remote update` to update the
    // repository.
    this.sprout.emit('msg', 'updating template')
    this.sprout.emit('cmd', 'git remote', this.path)

    return exec('git remote', { cwd: this.path }).then((stdout) => {
      if (!stdout[0]) { return }
      const origin = lodash.trim(stdout[0])
      this.sprout.emit('cmd', `git pull ${origin} HEAD`, this.path)
      return exec(`git pull ${origin} HEAD`, { cwd: this.path })
    }).yield(this)
  }

  /*
   * Run a template generator in the specified target.
   * @param {String} target - the target path.
   * @param {String} name - the name of the generator to use.
   * @param {Object} args - arguments to be passed to the generator
   * @return {Promise} - Promise for Template instance.
   */
  run (target, generator, _args) {
    let args = { target: target, generator: generator, generatorArgs: _args }
    const schema = Joi.object().keys({
      target: Joi.string().required(),
      generator: Joi.string().required(),
      generatorArgs: Joi.array().default([])
    })

    return node.call(Joi.validate, args, schema)
      .then((res) => { args = res })
      .then(() => {
        if (!fs.existsSync(target)) {
          throw new Error(`${target} does not exist`)
        }
      })
      .then(validateGenerator.bind(this, args.generator))
      .then(executeGenerator.bind(this, args.target, args.generatorArgs))
      .yield(this)
  }

  /*
   * Delete the template.
   * @return {Promise} - Promise for Template instance.
   */
  remove () {
    // Resolve if path does not exist.
    if (!fs.existsSync(this.path)) { return W.resolve(this) }

    // rm -rf the path.
    this.sprout.emit('msg', 'removing template')

    return fs.lstatAsync(this.path).then((stat) => {
      if (stat.isSymbolicLink()) { return fs.unlink(this.path) }
      return rimraf(this.path)
    }).yield(this)
  }
}

//
// Utility Functions
//

function ensureGitInstall () {
  // Check if git is installed
  if (!which.sync('git')) {
    throw new Error('you need to have git installed')
  }
}

function validateSource () {
  if (!this.src) { throw new Error('no source provided') }

  if (!this.isRemote && !fs.existsSync(this.src)) {
    throw new Error(`there is no sprout template located at ${this.src}`)
  }

  if (!this.isRemote && !fs.existsSync(path.join(this.src, '.git'))) {
    throw new Error(`${this.src} is not a git repository`)
  }
}

// TODO is this needed? could replace with timeout
function ensureInternetConnection () {
  if (!this.isRemote) { return }
  return dns.resolve('google.com').catch(() => {
    throw new Error('make sure that you are connected to the internet!')
  })
}

function removeTemplate () {
  return this.remove()
}

function moveSourceToSproutPath () {
  if (this.isRemote) {
    this.sprout.emit('cmd', `git clone ${this.src} ${this.path}`)
    return exec(`git clone --recursive ${this.src} ${this.path}`)
  }

  return fs.symlinkAsync(this.src, this.path)
}

function validateTemplate () {
  return W.resolve().then(() => {
    if (!fs.existsSync(path.join(this.path, 'init.js')) && !fs.existsSync(path.join(this.path, 'init.coffee'))) {
      throw new Error('neither init.coffee nor init.js exist in this template')
    }

    // Check for root path.
    if (!fs.existsSync(this.rootPath)) {
      throw new Error('root path doesn\'t exist in template')
    }
  }).catch((error) => {
    return rimraf(this.path).then(() => { throw error })
  })
}

function validateTarget (target) {
  if (fs.existsSync(target)) { throw new Error(`${target} already exists`) }
}

function handleBranchOrTagOption (opts) {
  if (!(opts.tag || opts.branch)) { return }

  this.sprout.emit('cmd', 'git rev-parse --abbrev-ref HEAD', this.path)

  return exec('git rev-parse --abbrev-ref HEAD', { cwd: this.path })
    .spread((stdout) => { this.currentBranch = stdout })
    .then(checkoutBranchIfPresent.bind(this, opts.branch))
    .then(checkoutTagIfPresent.bind(this, opts.tag))
}

function checkoutBranchIfPresent (branch) {
  if (!branch) { return }
  this.sprout.emit('cmd', `git checkout ${branch}`, this.path)
  return exec(`git checkout ${branch}`, { cwd: this.path })
}

function checkoutTagIfPresent (tag) {
  if (!tag) { return }
  this.sprout.emit('cmd', `git checkout tags/${tag}`, this.path)
  return exec(`git checkout tags/${tag}`, { cwd: this.path })
}

function createTargetDirectory (target) {
  this.sprout.emit('msg', `creating target directory: ${target}`)
  return fs.mkdir(target)
}

function installDependenciesIfPresent () {
  if (!fs.existsSync(path.join(this.path, 'package.json'))) { return }
  this.sprout.emit('msg', 'installing npm dependencies')
  return exec('npm install', { cwd: this.path })
}

function loadConfigFile () {
  const initCoffee = path.join(this.path, 'init.coffee')
  const initJS = path.join(this.path, 'init.js')
  let initPath

  if (fs.existsSync(initJS)) {
    initPath = initJS
  } else if (fs.existsSync(initCoffee)) {
    initPath = initCoffee
  } else {
    throw new Error('neither init.coffee nor init.js exist')
  }

  this.sprout.emit('msg', `requiring and validating ${initPath}`)

  const schema = Joi.object().keys({
    before: Joi.func(),
    configure: Joi.array().items(Joi.object()),
    beforeRender: Joi.func(),
    after: Joi.func(),
    ignore: Joi.array().single(),
    defaults: Joi.object()
  })

  const result = Joi.validate(require(initPath), schema)
  if (result.error) { throw result.error }

  this.init = result.value
}

function runBeforeHook (utils) {
  if (this.init.before) {
    this.sprout.emit('msg', 'running before hook')
    return W(this.init.before(utils, this.config))
  }
}

function mergeConfig (opts) {
  this.config = {}

  // Merge in all known values for config.
  lodash.assign(this.config, this.init.defaults, opts.locals)

  // If a config path is set, pull out its values and merge into config.
  if (opts.configPath) {
    this.sprout.emit('msg', `merging config: ${opts.configPath}`)
    let externalConfig

    if (/\.json$/.test(opts.configPath)) {
      externalConfig = require(opts.configPath)
    } else {
      externalConfig = yaml.safeLoad(fs.readFileSync(opts.configPath, 'utf8'))
    }

    lodash.assign(this.config, externalConfig)
  }
}

// If questionnaire function exists, run it to get answers.
// Omitting keys already set in config return answers merged with config values.
function runPrompts (opts) {
  if (opts.questionnaire && this.init.configure) {
    this.sprout.emit('msg', 'running questionnaire function')
    return opts.questionnaire(this.init.configure, lodash.keys(this.config))
      .then((answers) => { return lodash.assign(this.config, answers) })
  }
}

function copyTemplateToTarget (target) {
  this.sprout.emit('msg', 'copying files in root to target')
  return ncp(this.rootPath, target)
}

function runBeforeRenderHook (utils) {
  if (this.init.beforeRender) {
    this.sprout.emit('msg', 'running beforeRender hook')
    return W(this.init.beforeRender(utils, this.config))
  }
}

function readTemplateFiles (target) {
  this.sprout.emit('msg', 'reading target directory')
  return readdirp({
    root: target,
    directoryFilter: ['!.git', '!node_modules']
  })
}

function removeIgnoredFiles (result) {
  return lodash.filter(result.files, (file) => {
    if (this.init.ignore) {
      this.init.ignore = Array.prototype.concat(this.init.ignore)
      for (var i = 0; i < this.init.ignore.length; i++) {
        if (minimatch(file.path, this.init.ignore[i])) {
          return false
        }
      }
    }
    return true
  })
}

function writeTemplateFiles (utils, files) {
  return W.map(files, (file) => {
    this.sprout.emit('msg', `reading ${file.fullPath}`)

    if (!isBinaryFile(file.fullPath)) {
      this.sprout.emit('msg', `reading ${file.fullPath}`)
      return utils.target.read(file.path).then((output) => {
        this.sprout.emit('msg', `writing ${file.fullPath}`)
        return utils.target.write(file.path, output, this.config)
      })
    }
  })
}

function runAfterHook (utils) {
  if (this.init.after) {
    this.sprout.emit('msg', 'running after hook')
    return W(this.init.after(utils, this.config))
  }
}

function validateGenerator (generator) {
  const generatorCoffee = path.join(this.generatorsPath, `${generator}.coffee`)
  const generatorJs = path.join(this.generatorsPath, `${generator}.js`)
  let generatorPath

  if (fs.existsSync(generatorJs)) {
    generatorPath = generatorJs
  } else if (fs.existsSync(generatorCoffee)) {
    generatorPath = generatorCoffee
  } else {
    throw new Error(`'${generator}' is not a generator in this template`)
  }

  this.sprout.emit('msg', `requiring '${generator}' generator`)
  return require(generatorPath)
}

function executeGenerator (target, args, generator) {
  const utils = new Utils(this.path, target)

  args = lodash.isArray(args) ? args : []
  args.unshift(utils)

  // Call the generator, pass the Utils instance and the arguments.
  this.sprout.emit('msg', `running ${generator} generator`)
  return generator.apply(null, args)
}

module.exports = Template
<|endoftext|>


<commit_before>/*!
 * Coolony's Kiwi
 * Copyright ©2012 Pierre Matri <pierre.matri@coolony.com>
 * MIT Licensed
 */

/**
 * Module dependencies
 */

// if browser
var Cache = require('./cache');
var CappedCache = Cache;
// end
// if node
var path = require('path');
var frame = require('frame');
var Cache = frame.Cache;
var CappedCache = frame.CappedCache;
var construct = frame.classes.construct;
var _ = require('underscore');
// end

var utils = require('./utils');
var token = require('./token');
var tools = require('./tools');
var Compiler = require('./compiler');
var filter = require('./filter');

/**
 * Constants
 */

var DEFAULTS = {
  lookup: utils.lookupTemplate,
  load: utils.loadTemplate,
  path: null,
  cache: null,
  cacheHandler: Cache,
  cacheOptions: [],
  lookupPaths: [],
  cacheTmplHandler: CappedCache,
  cacheTmplOptions: [1000],
  useIsolatedTmplCache: true,
  cacheContext: null,
  strict: true,
  eachCounters: true,
  _parent: null,
  _cacheAttachment: '_cache',
  _cacheTmplAttachment: '_nestCache'
}
var TEMPLATE_EXPORTS = {filter: filter, utils: utils, tools: tools};

/**
 * Initializes `Template` with optionnally the given `str` and
 * `options`.
 *
 * @param {String} [str]
 * @param {Object} [options]
 * @api public
 */

function Template(str, options) {

  // Handle the case where the only argument passed is the `options` object
  if(_.isObject(str) && !options){
    options = str;
    str = null;
  }

  // Create options if not provided
  options = options ? _.clone(options) : {};

  // Set default cache behavior
  if(!_.isBoolean(options.cache)) {
    if(options && options.settings) {
      options.cache = options.settings.env !== 'development';
    } else {
      options.cache = true;
    }
  }

  // Merges given `options` with `DEFAULTS`
  options = _.defaults(options, DEFAULTS);
  options.cacheContext = options.cacheContext || Template;

  // Sets instance variables
  this.template = str;
  this.options = options;
  this._compiled = null;

  // Creates the cache if not already done
  if(options.cache && !(this._getCache() instanceof options.cacheHandler)) {
    var cacheOptions = [options.cacheHandler].concat(options.cacheOptions);
    options.cacheContext[options._cacheProp] = typeof window !== 'undefined' ?
                                                 new options.cacheHandler() :
                                                 construct.apply(this,
                                                                 cacheOptions);
  }
}

/**
 * Get cache handler
 *
 * @return {Object}
 * @api private
 */

Template.prototype._getCache = function() {
  return this.options.cacheContext[this.options._cacheProp];
}

/**
 * Load the template from disk at `filePath`, and invoke `callback(err, data)`.
 *
 * @param {String} filePath
 * @param {Function} callback
 * @api public
 */

Template.prototype.loadFile = function(filePath, callback) {
// if node
  var _this = this;
  this.options.load(filePath, function onLoad(err, data) {
    if(err) return callback(err);
    _this.options.path = path.normalize(filePath);
    _this.template = data;
    callback(null, data);
  });
// end
// if browser
if(typeof window !== 'undefined') {
  callback(new Error('Client mode does not support reading from file.'));
}
// end
}

/**
 * Render the template with given `data`, and invoke `callback(err, compiled)`.
 *
 * @param {Object} [data]
 * @param {Function} callback
 * @api public
 */

Template.prototype.render = function(data, callback) {

  // Handle the case where the only argument passed is the `options` object
  if(_.isFunction(data) && !callback){
    callback = data;
    data = {};
  }

  // Check whether we have the compiled template ready in the object or in cache
  var cacheKey = 'template::' + this._cacheKey();
  if(!this.compiled && this.options.cache) {
    this._compiled = this._getCache().get(cacheKey);
  }

  // Render it if we got it…
  if(this._compiled) return this._renderCompiled(data, callback);

  // …or compile it if we don't
  var _this = this;
  this._compile(function(err){
    if(err) return callback(err);
    _this._renderCompiled(data, callback);
  })
}

/**
 * Render the compiled template with given `data`, and invoke
 * `callback(err, compiled)`.
 *
 * @param {String} filePath
 * @param {Function} callback
 * @api private
 */

Template.prototype._renderCompiled = function onRendered(data, callback) {
  try {
    // Apply compiled function to itself (needed for function helpers)
    this._compiled.call(this._compiled, this, TEMPLATE_EXPORTS, _, data,
                        token.helpers, callback);
  } catch(err) {
    callback(err);
  }
}

/**
 * Compile the template, and invoke `callback(err, compiled)`.
 *
 * @param {Function} callback
 * @api private
 */

Template.prototype._compile = function(callback) {
  var _this = this;
  if(!_.isString(this.template)) {
    return callback(new Error('Template contents not set'));
  }

  new Compiler(this).compile(function(err, compiled) {

    if(err) return callback(err);

    // Save the compiled template in this object
    _this._compiled = compiled;

    // Cache it, if possible
    var cacheKey = 'template::' + _this._cacheKey();
    if(_this.options.cache) {
      _this._getCache().cache(cacheKey, compiled);
    }

    // Invoke the callback
    callback(null, compiled);
  });
}

/**
 * Render `nested` template with `data`, and invoke `callback(err, rendered)`.
 *
 * @param {String} nested
 * @param {Object} data
 * @param {Function} callback
 * @api private
 */

Template.prototype._nest = function(nested, data, callback) {
  var options = _.clone(this.options);
  if(options.useIsolatedTmplCache) {
    options._cacheAttachment = options._cacheTmplAttachment;
    options.cacheHandler = options.cacheTmplHandler;
    options.cacheOptions = options.cacheTmplOptions;
  }
  new Template(nested, options).render(data, function onDone(err, rendered) {
    if(err) return callback(err);
    callback(null, rendered);
  });
}

/**
 * Render `nested` template with `data`, and invoke `callback(err, rendered)`.
 *
 * @param {String} nested
 * @param {Object} data
 * @param {Function} callback
 * @api private
 */

Template.prototype._renderRelative = function(name, data, rendered, callback) {
  var _this = this;
  var options = _.clone(this.options);
  options._parent = rendered;
  var template = new Template(options);
  var cacheKey = 'path::' + this._cacheKey() + '::' + name;
  var cachedPath;

  function onTemplateLocated(err, filePath) {
    if(err) return callback(err);
    if(_this.options.cache) {
      _this._getCache().cache(cacheKey, filePath);
    }
    template.loadFile(filePath, onTemplateLoaded);
  }

  function onTemplateLoaded(err, source) {
    if(err) return callback(err);
    template.render(data, onTemplateRendered);
  }

  function onTemplateRendered(err, result) {
    if(err) return callback(err);
    callback(null, result);
  }

  if(this.options.cache) {
    cachedPath = this._getCache().get(cacheKey);
  }

  if(cachedPath) {
    template.loadFile(cachedPath, onTemplateLoaded);
  } else {
    this.options.lookup(name, this, onTemplateLocated);
  }
}

/**
 * Calculate  and return cache key.
 *
 * @return {String} Cache key.
 * @api private
 */

Template.prototype._cacheKey = function() {
  return this.options.path || this.template || null;
}

/**
 * Module exports
 */

exports = module.exports = Template;
<commit_msg>Fixed development mode detection.<commit_after>/*!
 * Coolony's Kiwi
 * Copyright ©2012 Pierre Matri <pierre.matri@coolony.com>
 * MIT Licensed
 */

/**
 * Module dependencies
 */

// if browser
var Cache = require('./cache');
var CappedCache = Cache;
// end
// if node
var path = require('path');
var frame = require('frame');
var Cache = frame.Cache;
var CappedCache = frame.CappedCache;
var construct = frame.classes.construct;
var _ = require('underscore');
// end

var utils = require('./utils');
var token = require('./token');
var tools = require('./tools');
var Compiler = require('./compiler');
var filter = require('./filter');

/**
 * Constants
 */

var DEFAULTS = {
  lookup: utils.lookupTemplate,
  load: utils.loadTemplate,
  path: null,
  cache: null,
  cacheHandler: Cache,
  cacheOptions: [],
  lookupPaths: [],
  cacheTmplHandler: CappedCache,
  cacheTmplOptions: [1000],
  useIsolatedTmplCache: true,
  cacheContext: null,
  strict: true,
  eachCounters: true,
  _parent: null,
  _cacheAttachment: '_cache',
  _cacheTmplAttachment: '_nestCache'
}
var TEMPLATE_EXPORTS = {filter: filter, utils: utils, tools: tools};

/**
 * Initializes `Template` with optionnally the given `str` and
 * `options`.
 *
 * @param {String} [str]
 * @param {Object} [options]
 * @api public
 */

function Template(str, options) {

  // Handle the case where the only argument passed is the `options` object
  if(_.isObject(str) && !options){
    options = str;
    str = null;
  }

  // Create options if not provided
  options = options ? _.clone(options) : {};

  // Set default cache behavior
  if(!_.isBoolean(options.cache)) {
    options.cache = process.env.NODE_ENV === 'production';
  }

  // Merges given `options` with `DEFAULTS`
  options = _.defaults(options, DEFAULTS);
  options.cacheContext = options.cacheContext || Template;

  // Sets instance variables
  this.template = str;
  this.options = options;
  this._compiled = null;

  // Creates the cache if not already done
  if(options.cache && !(this._getCache() instanceof options.cacheHandler)) {
    var cacheOptions = [options.cacheHandler].concat(options.cacheOptions);
    options.cacheContext[options._cacheProp] = typeof window !== 'undefined' ?
                                                 new options.cacheHandler() :
                                                 construct.apply(this,
                                                                 cacheOptions);
  }
}

/**
 * Get cache handler
 *
 * @return {Object}
 * @api private
 */

Template.prototype._getCache = function() {
  return this.options.cacheContext[this.options._cacheProp];
}

/**
 * Load the template from disk at `filePath`, and invoke `callback(err, data)`.
 *
 * @param {String} filePath
 * @param {Function} callback
 * @api public
 */

Template.prototype.loadFile = function(filePath, callback) {
// if node
  var _this = this;
  this.options.load(filePath, function onLoad(err, data) {
    if(err) return callback(err);
    _this.options.path = path.normalize(filePath);
    _this.template = data;
    callback(null, data);
  });
// end
// if browser
if(typeof window !== 'undefined') {
  callback(new Error('Client mode does not support reading from file.'));
}
// end
}

/**
 * Render the template with given `data`, and invoke `callback(err, compiled)`.
 *
 * @param {Object} [data]
 * @param {Function} callback
 * @api public
 */

Template.prototype.render = function(data, callback) {

  // Handle the case where the only argument passed is the `options` object
  if(_.isFunction(data) && !callback){
    callback = data;
    data = {};
  }

  // Check whether we have the compiled template ready in the object or in cache
  var cacheKey = 'template::' + this._cacheKey();
  if(!this.compiled && this.options.cache) {
    this._compiled = this._getCache().get(cacheKey);
  }

  // Render it if we got it…
  if(this._compiled) return this._renderCompiled(data, callback);

  // …or compile it if we don't
  var _this = this;
  this._compile(function(err){
    if(err) return callback(err);
    _this._renderCompiled(data, callback);
  })
}

/**
 * Render the compiled template with given `data`, and invoke
 * `callback(err, compiled)`.
 *
 * @param {String} filePath
 * @param {Function} callback
 * @api private
 */

Template.prototype._renderCompiled = function onRendered(data, callback) {
  try {
    // Apply compiled function to itself (needed for function helpers)
    this._compiled.call(this._compiled, this, TEMPLATE_EXPORTS, _, data,
                        token.helpers, callback);
  } catch(err) {
    callback(err);
  }
}

/**
 * Compile the template, and invoke `callback(err, compiled)`.
 *
 * @param {Function} callback
 * @api private
 */

Template.prototype._compile = function(callback) {
  var _this = this;
  if(!_.isString(this.template)) {
    return callback(new Error('Template contents not set'));
  }

  new Compiler(this).compile(function(err, compiled) {

    if(err) return callback(err);

    // Save the compiled template in this object
    _this._compiled = compiled;

    // Cache it, if possible
    var cacheKey = 'template::' + _this._cacheKey();
    if(_this.options.cache) {
      _this._getCache().cache(cacheKey, compiled);
    }

    // Invoke the callback
    callback(null, compiled);
  });
}

/**
 * Render `nested` template with `data`, and invoke `callback(err, rendered)`.
 *
 * @param {String} nested
 * @param {Object} data
 * @param {Function} callback
 * @api private
 */

Template.prototype._nest = function(nested, data, callback) {
  var options = _.clone(this.options);
  if(options.useIsolatedTmplCache) {
    options._cacheAttachment = options._cacheTmplAttachment;
    options.cacheHandler = options.cacheTmplHandler;
    options.cacheOptions = options.cacheTmplOptions;
  }
  new Template(nested, options).render(data, function onDone(err, rendered) {
    if(err) return callback(err);
    callback(null, rendered);
  });
}

/**
 * Render `nested` template with `data`, and invoke `callback(err, rendered)`.
 *
 * @param {String} nested
 * @param {Object} data
 * @param {Function} callback
 * @api private
 */

Template.prototype._renderRelative = function(name, data, rendered, callback) {
  var _this = this;
  var options = _.clone(this.options);
  options._parent = rendered;
  var template = new Template(options);
  var cacheKey = 'path::' + this._cacheKey() + '::' + name;
  var cachedPath;

  function onTemplateLocated(err, filePath) {
    if(err) return callback(err);
    if(_this.options.cache) {
      _this._getCache().cache(cacheKey, filePath);
    }
    template.loadFile(filePath, onTemplateLoaded);
  }

  function onTemplateLoaded(err, source) {
    if(err) return callback(err);
    template.render(data, onTemplateRendered);
  }

  function onTemplateRendered(err, result) {
    if(err) return callback(err);
    callback(null, result);
  }

  if(this.options.cache) {
    cachedPath = this._getCache().get(cacheKey);
  }

  if(cachedPath) {
    template.loadFile(cachedPath, onTemplateLoaded);
  } else {
    this.options.lookup(name, this, onTemplateLocated);
  }
}

/**
 * Calculate  and return cache key.
 *
 * @return {String} Cache key.
 * @api private
 */

Template.prototype._cacheKey = function() {
  return this.options.path || this.template || null;
}

/**
 * Module exports
 */

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


<commit_before>//Template class for Noodles
//otherwise just make sure that the browser version loads before this file.
if(typeof process !== "undefined"){
	//if node
	var requirejs = require('require-node');
	var define = requirejs.define;
	requirejs.config({
	    nodeRequire: require,
		baseUrl: __dirname,
	});
}
else{
	requirejs = require;
}
requirejs(['_noodles_utilities'],function(_Utilities){

define('_noodles_template',function(require, exports, module){
/**--module--
name: BrowserEnvironment
description: Browser Environment boolean
@type{boolean}
*/
var BrowserEnvironment = typeof process === "undefined";
/**--module--
name:reIdentifier
description: regular expression to determine Identifier worthiness
@type{RegExp}
*/
var reIdentifier = _Utilities.reIdentifier;
/**--module--
name:corePlugins
description: list of core module handlers
@type{array}
*/
var corePlugins = ['coretags']
/**--module--
name:allPlugins
description: object of core module handlers
@type{object}
*/
var allPlugins = {};
/**--Noodles--
name:Template
description: Template Class
@param {object}
@param {Noodles.Template}
@return {Template}
*/
var _Template = exports.Template = function(objArg,Template){
	this._rawString = objArg.rawString;
	this._stringCache = objArg.rawString;
	this._document = [];
	this._leftCount = 0;
	this._warnings = [];
	this._metaData = {};
	this._needs = {};
	this._master = false;
	this._tagDelegation = {};
	this._lineOffset = objArg.lineOffset || 0;
	var metaData = objArg.metaData
	if(typeof metData !== 'undefined'){
		var metaArr = metaData.split(/\n+/),
			i = metaArr.length,
			reMeta = /([^=]+)(={1})(.*)/,
			meta,name,value,keys,l;
		while(i--){
			if(/^\s+$/.test(metArr[i])) continue;
			meta = reMeta.exec(metaArr[i].trim());
			name = meta[1].toLowerCase();
			value = meta[3];
			if(reIdentifier.test(name) && meta[2] === '='){
				this._metaData[name] = new _Template({rawString:value},this);
			}
		}
		this._metaData['plugins'] = this._metaData['plugins'] || [];
		this._plugins = corePlugins.concat(this._metaData['plugins']);
		_registerPlugins.call(this);
		this._master = true;
	}
	else if(typeof Template !== "undefined" && Template instanceof _Template){
		this._plugins = Template._plugins.slice();
		_registerPlugins.call(this);
	}
	this._templating = true;
    while(this._templating){
		_create.call(this);
    }

};
/**--module--
name:_create - private method
description: creates the document list of the Template Class
*/
var _create = function(){
	this._rawString
	var leftIndex = this._rawString.indexOf('<{'),
        rightIndex = this._rawString.indexOf('}>'),
		expression,tag,lineStart;

	if(leftIndex > -1){

		this._leftCount++;
		if(rightIndex > -1){
			expression = this._rawString.slice(leftIndex + 2, rightIndex);
			this._document.push( new _String(this, this._rawString.slice(0,leftIndex) ) );
            this._rawString = this._rawString.slice(rightIndex + 2);
			if(expression.charAt(0) === ' '){
				_warning(this,'Invalid whitespace at the start of expression');
			}
			else{
				tag = expression.split(' ')[0].toLowerCase();
				lineStart = _getLineCount(this);
				expression = typeof allPlugins[this._tagDelegation[tag]] !== "undefined" ? allPlugins[this._tagDelegation[tag]].handleToken(this, expression, tag) : _parseType(this, expression);

				if(typeof expression.skip === "undefined" || expression.skip === false){

					expression.lineStart = lineStart;
					this._document.push(expression);
					expression.needs = expression.needs || {};
					//this.needs = _mergeObjectWith(this.needs,expression.needs);
					//this.sets = _mergeObjectWith(this.sets,expression.sets);
					//this.modifies = _mergeObjectWith(this.modifies,expression.modifies);

				}
				else if(typeof expression.warnings !== "undefined"){
					_warning(this,expression.warnings);
				}
			}
		}
		else{
			_warning(this,'Open ended expression');
		}
	}
	else{
		this._templating = false;
		this._document.push(new _String(this, this._rawString ));
		this._documentLength = this._document.length;
		delete this._rawString;
		tag = _Utilities.stringOnly(this._document);

		if(tag.stringOnly){
			this._stringOnly = true;
			this._document = [new _String(tag.string)];
			this._documentLength = 1;
			this.needs = {};
		}
		_createExecutionOrder.call(this,this._master);
	}
};
/**--module--
name:_createExecutionOrder - private method
description: creates the execution order for a template based on its needs.
@param{boolean}
*/
var _createExecutionOrder = function(master){
	_reduceNeeds.call(this,master);
	this._executionStack;
	//We want to get anything that is ambiguous or requires a callback
	//to execute ASAP because they will be our bottlenecks.
	//1. Anything that modifies or sets something needs to execute in
	//	order against anything that needs that thing.
	//2. Anything that is ambiguous acts as a break point, nothing after it
	//	can render until it's done, ambiguity trumps callbacks.
	//3. Anything that doesn't need anything can render at anytime.
};
/**--module--
name:_reduceNeeds - private method
description: reduces the needs, sets and modifies, objects
of all the objects to what they ought to be.
@param{boolean}
*/
var _reduceNeeds = function(master){
	this.needs = {};
	this.sets = {};
	this.modifies = {};
	this.ambiguous = [];
	this.callbacks = [];
	var docs = this._document,
		l = docs.length,
		i = 0,
		arr = [],
		count = -1,
		doc, needs,sets,modifies,t,key;
	//actually figure out what Template needs and sets. Modifies is always correct (even when it isn't :)
	while(i < l){
		doc = docs[i];
		if(doc.skip) continue;
		count++;
		arr.push(doc);
		if(doc.ambiguous){
			this.ambiguous.push(count);
		}
		if(doc.needsCallback){
			this.callbacks.push(count);
		}
		if(typeof doc.sets !== "undefined"){
			sets = Object.keys(doc.sets);
			t = sets.length;
			while(t--){
				key = sets[t].toLowerCase();
				if(typeof this.set[key] === "undefined"){
					this.sets[key] = true;
				}
				else{
					delete doc.sets[sets[t]];
				}
			}
		}
		if(typeof doc.needs !== "undefined"){
			needs = Object.keys(doc.needs);
			t = needs.length;
			while(t--){
				key = needs[t].toLowerCase();
				if(typeof this.sets[key] === "undefined"){
					this.needs[key] = true;
				}
			}
		}
		if(typeof doc.modifies !== "undefined"){
			modifies = Object.keys(doc.modifies);
			t = modifies.length;
			while(t--){
				key = modifies[t].toLowerCase();
				this.modifies[key] = true;
			}
		}
		i++;
	}
	this._executionStack = arr;
}
/**--Noodles.Template--
name:execute
description: Template execution
@param {Noodles.Template||object}
@param {Noodles.Context||object}
@return {Template}
*/
Template.prototype.execute = function(Template,Context){
	if(!(Template instanceof Noodles.Template)){
		var _Context = new Context(this,Template),
			_onRender = typeof Context.onRender === "undefined" ? function(){} : Context.buffer ? function(string){Context.onRender(new Buffer(string));} : Context.onRender,
			_onRenderAll : typeof Context.onRender === "undefined" ? function(){} : Context.buffer ? function(string){Context.onRenderAll(new Buffer(string));} : Context.onRenderAll,
			_onFinish : typeof Context.onFinish === "undefined" ? function(){} : Context.onFinish;
	}
};
/**--Noodles--
name:_registerPlugins - private method
description: registers the plugins of the Template Class
*/
var _registerPlugins = function(){
	var i = this._plugins.length,
		_self = this,
		key, value,t;
	while(i--){
		key = this._plugins[i];
		if(typeof allPlugins[key] !== "undefined"){
			value = allPlugins[key].willHandle
		}
		else {
			_localRequire.call(_self,key);
			continue;
		}

		if(typeof value !== "undefined" && 0 < (t = value.length)){
			while(t--){
				_self._tagDelegation[value[t]] = key;
			}
		}
	}
};
/**--module--
name:localRequire - private method
description: get required modules, check in plugins and lib folder
*/
var _localRequire = function(key){
	var _self = this;
	require(['./../plugins/'+ key],function(plugin){
		plugin = plugin.Plugin;
		if(typeof plugin.pluginName === "undefined") throw "The following plugin needs a plugin name: "+ plugin.toString()+'.';
		if(BrowserEnvironment && !plugin.browserFriendly) throw "The pluguin "+plugin.pluginName+" does not work in the browser.";
		if(typeof plugin.onTemplateCreate !== "undefined") plugin.onTemplateCreate(_self);
		if(typeof plugin.willHandle === "undefined" || plugin.handleToken === "undefined") return;
		allPlugins[plugin.pluginName] = plugin;
		var handle = plugin.willHandle,
			i = handle.length;
		while(i--){
			_self._tagDelegation[handle[i]] = plugin.pluginName;

		}
	});
};
});
});<commit_msg>Added some depency logic, added lambda variable, and retooled buffering<commit_after>//Template class for Noodles
//otherwise just make sure that the browser version loads before this file.
if(typeof process !== "undefined"){
	//if node
	var requirejs = require('require-node');
	var define = requirejs.define;
	requirejs.config({
	    nodeRequire: require,
		baseUrl: __dirname,
	});
}
else{
	requirejs = require;
}
requirejs(['_noodles_utilities'],function(_Utilities){

define('_noodles_template',function(require, exports, module){
/**--module--
name: lambda
description: empty function for whatever.
@type{function}
*/
var lambda = function(){};
/**--module--
name: BrowserEnvironment
description: Browser Environment boolean
@type{boolean}
*/
var BrowserEnvironment = typeof process === "undefined";
/**--module--
name:reIdentifier
description: regular expression to determine Identifier worthiness
@type{RegExp}
*/
var reIdentifier = _Utilities.reIdentifier;
/**--module--
name:corePlugins
description: list of core module handlers
@type{array}
*/
var corePlugins = ['coretags']
/**--module--
name:allPlugins
description: object of core module handlers
@type{object}
*/
var allPlugins = {};
/**--Noodles--
name:Template
description: Template Class
@param {object}
@param {Noodles.Template}
@return {Template}
*/
var _Template = exports.Template = function(objArg,Template){
	this._rawString = objArg.rawString;
	this._stringCache = objArg.rawString;
	this._document = [];
	this._leftCount = 0;
	this._warnings = [];
	this._metaData = {};
	this._needs = {};
	this._master = false;
	this._tagDelegation = {};
	this._lineOffset = objArg.lineOffset || 0;
	var metaData = objArg.metaData
	if(typeof metData !== 'undefined'){
		var metaArr = metaData.split(/\n+/),
			i = metaArr.length,
			reMeta = /([^=]+)(={1})(.*)/,
			meta,name,value,keys,l;
		while(i--){
			if(/^\s+$/.test(metArr[i])) continue;
			meta = reMeta.exec(metaArr[i].trim());
			name = meta[1].toLowerCase();
			value = meta[3];
			if(reIdentifier.test(name) && meta[2] === '='){
				this._metaData[name] = new _Template({rawString:value},this);
			}
		}
		this._metaData['plugins'] = this._metaData['plugins'] || [];
		this._plugins = corePlugins.concat(this._metaData['plugins']);
		_registerPlugins.call(this);
		this._master = true;
	}
	else if(typeof Template !== "undefined" && Template instanceof _Template){
		this._plugins = Template._plugins.slice();
		_registerPlugins.call(this);
	}
	this._templating = true;
    while(this._templating){
		_create.call(this);
    }

};
/**--module--
name:_create - private method
description: creates the document list of the Template Class
*/
var _create = function(){
	this._rawString
	var leftIndex = this._rawString.indexOf('<{'),
        rightIndex = this._rawString.indexOf('}>'),
		expression,tag,lineStart;

	if(leftIndex > -1){

		this._leftCount++;
		if(rightIndex > -1){
			expression = this._rawString.slice(leftIndex + 2, rightIndex);
			this._document.push( new _String(this, this._rawString.slice(0,leftIndex) ) );
            this._rawString = this._rawString.slice(rightIndex + 2);
			if(expression.charAt(0) === ' '){
				_warning(this,'Invalid whitespace at the start of expression');
			}
			else{
				tag = expression.split(' ')[0].toLowerCase();
				lineStart = _getLineCount(this);
				expression = typeof allPlugins[this._tagDelegation[tag]] !== "undefined" ? allPlugins[this._tagDelegation[tag]].handleToken(this, expression, tag) : _parseType(this, expression);

				if(typeof expression.skip === "undefined" || expression.skip === false){

					expression.lineStart = lineStart;
					this._document.push(expression);
					expression.needs = expression.needs || {};
					//this.needs = _mergeObjectWith(this.needs,expression.needs);
					//this.sets = _mergeObjectWith(this.sets,expression.sets);
					//this.modifies = _mergeObjectWith(this.modifies,expression.modifies);

				}
				else if(typeof expression.warnings !== "undefined"){
					_warning(this,expression.warnings);
				}
			}
		}
		else{
			_warning(this,'Open ended expression');
		}
	}
	else{
		this._templating = false;
		this._document.push(new _String(this, this._rawString ));
		this._documentLength = this._document.length;
		delete this._rawString;
		tag = _Utilities.stringOnly(this._document);

		if(tag.stringOnly){
			this._stringOnly = true;
			this._document = [new _String(tag.string)];
			this._documentLength = 1;
			this.needs = {};
		}
		_createExecutionOrder.call(this,this._master);
	}
};
/**--module--
name:_createExecutionOrder - private method
description: creates the execution order for a template based on its needs.
@param{boolean}
*/
var _createExecutionOrder = function(master){
	_reduceNeeds.call(this,master);
	//We want to get anything that is ambiguous or requires a callback
	//to execute ASAP because they will be our bottlenecks.
	//1. Anything that modifies or sets something needs to execute in
	//	order against anything that needs that thing.
	//2. Anything that is ambiguous acts as a break point, nothing after it
	//	can render until it's done, ambiguity trumps callbacks.
	//3. Anything that doesn't need anything can render at anytime.
	//Contrary to intuition, going in order is actually ideal, save for
	// our bottlenecks, because the more we can do in order the more we
	// can buffer to the serve in the appropriate order.
	//
	this._executionOrder = [];
	this._lowestNotDone = 0;
	this._inAlready = {};
	var i = 0,
		l = this.ambiguous.length;
	//figure ambiguity out
	while(i < l){
		_orderNeedsByObject.call(this,this.ambiguous[i],'ambiguous');
		i++;
	}
	delete this.ambiguous;

};
/**--module--
name:_orderNeedsByObject - private method
description: orders the execution stack based on where the current object is.
@param{number}
*/
var _orderNeedsByObject = function(index,reason){
	var obj = this._executionStack[index],
		i = 0,
		l = index,
		makesAvailable = [],
		temp,t,setsOrModifies;
	while(i < l){
		if(this._inAlready[i.toString()]){
			i++;
			continue
		}
		temp = this._executionStack[i];
		setsOrModifies = [];
		if(typeof temp.modifies !== "undefined"){
			setsOrModifies = setsOrModifies.concat(Object.keys(temp.modifies));
		}
		if(typeof temp.sets !== "undefined"){
			setsOrModifies = setsOrModifies.concat(Object.keys(temp.sets));
		}
		t = setsOrModifies.length;
		while(t--){
			if(obj.needs[setsOrModifies[t]]){
				//We need this object
				_orderNeedsByObject.call(this,i,'child');
				this._executionOrder.push({index:i});
				this._inAlready[i.toString()] = true;
				break;
			}
		}
		i++;
	}
	if(reason === "ambiguous"){
		i++
		l = this._executionOrder.length
		while(i < l){
			temp = this._executionStack[i];
			makesAvailable.push(i);
			i++;
		}
		this._executionOrder.push({index:index,reason:reason,makesAvailable:makesAvailable});
	}
	else{
		this._executionOrder.push({index:index,reason:reason});
	}
};
/**--module--
name:_reduceNeeds - private method
description: reduces the needs, sets and modifies, objects
of all the objects to what they ought to be.
@param{boolean}
*/
var _reduceNeeds = function(master){
	this.needs = {};
	this.sets = {};
	this.modifies = {};
	this.ambiguous = [];
	this.callbacks = [];
	var docs = this._document,
		l = docs.length,
		i = 0,
		arr = [],
		count = -1,
		doc, needs,sets,modifies,t,key;
	//actually figure out what Template needs and sets. Modifies is always correct (even when it isn't :)
	while(i < l){
		doc = docs[i];
		if(doc.skip){
			i++;
			continue;
		}
		count++;
		arr.push(doc);
		if(doc.ambiguous){
			this.ambiguous.push(count);
		}
		else if(doc.needsCallback){
			this.callbacks.push(count);
		}
		if(typeof doc.sets !== "undefined"){
			sets = Object.keys(doc.sets);
			t = sets.length;
			while(t--){
				key = sets[t].toLowerCase();
				if(typeof this.set[key] === "undefined"){
					this.sets[key] = true;
				}
				else{
					delete doc.sets[sets[t]];
				}
			}
		}
		if(typeof doc.needs !== "undefined"){
			needs = Object.keys(doc.needs);
			t = needs.length;
			while(t--){
				key = needs[t].toLowerCase();
				if(typeof this.sets[key] === "undefined"){
					this.needs[key] = true;
				}
			}
		}
		if(typeof doc.modifies !== "undefined"){
			modifies = Object.keys(doc.modifies);
			t = modifies.length;
			while(t--){
				key = modifies[t].toLowerCase();
				this.modifies[key] = true;
			}
		}
		i++;
	}
	this._executionStack = arr;
}
/**--Noodles.Template--
name:execute
description: Template execution
@param {Noodles.Template||object}
@param {Noodles.Context||object}
@param {boolean=}
@return {Template}
*/
Template.prototype.execute = function(Template,Context,inOrder,debugMode){
	if(!(Template instanceof Noodles.Template)){
		var _Context = new Context(this,Template),
			_onRender = typeof Context.onRender === "undefined" ? lambda : Context.onRender,
			_onRenderAll : typeof Context.onRender === "undefined" ? lambda : Context.onRenderAll,
			_onFinish : typeof Context.onFinish === "undefined" ? lambda : Context.onFinish;
	}
};
/**--Noodles--
name:_registerPlugins - private method
description: registers the plugins of the Template Class
*/
var _registerPlugins = function(){
	var i = this._plugins.length,
		_self = this,
		key, value,t;
	while(i--){
		key = this._plugins[i];
		if(typeof allPlugins[key] !== "undefined"){
			value = allPlugins[key].willHandle
		}
		else {
			_localRequire.call(_self,key);
			continue;
		}

		if(typeof value !== "undefined" && 0 < (t = value.length)){
			while(t--){
				_self._tagDelegation[value[t]] = key;
			}
		}
	}
};
/**--module--
name:localRequire - private method
description: get required modules, check in plugins and lib folder
*/
var _localRequire = function(key){
	var _self = this;
	require(['./../plugins/'+ key],function(plugin){
		plugin = plugin.Plugin;
		if(typeof plugin.pluginName === "undefined") throw "The following plugin needs a plugin name: "+ plugin.toString()+'.';
		if(BrowserEnvironment && !plugin.browserFriendly) throw "The pluguin "+plugin.pluginName+" does not work in the browser.";
		if(typeof plugin.onTemplateCreate !== "undefined") plugin.onTemplateCreate(_self);
		if(typeof plugin.willHandle === "undefined" || plugin.handleToken === "undefined") return;
		allPlugins[plugin.pluginName] = plugin;
		var handle = plugin.willHandle,
			i = handle.length;
		while(i--){
			_self._tagDelegation[handle[i]] = plugin.pluginName;

		}
	});
};
});
});<|endoftext|>


<commit_before>var inherits = require('util').inherits;

var CSI_PATTERN = /^\x1b\[([?!>]?)([0-9;]*)([@A-Za-z`]?)/;
var DCS_PATTERN = /^\x1bP([0-9;@A-Za-z`]*)\x1b\\/;
var OSC_PATTERN = /^\x1b\]([0-9]+);([^\x07]*)(\x07?)/;

/**
* TermWriter is the glue between a TerminalBuffer and the escape sequence
* interpreters.
* @constructor
*/
function TermWriter(buffer) {
	TermWriter.super_.call(this, { decodeStrings: false });
	this.buffer = buffer;
	this.oldChunk = null;
}
inherits(TermWriter, require('stream').Writable);
module.exports = TermWriter;

TermWriter.prototype.handlers = {
	chr: require('./handler/chr.js'),
	esc: require('./handler/esc.js'),
	csi: require('./handler/csi.js'),
	sgr: require('./handler/sgr.js'),
	dcs: require('./handler/dcs.js'),
	mode: require('./handler/mode.js'),
	osc: require('./handler/osc.js'),
};

/**
* Takes a chunk of data, interprets its escape sequences, and fills backend buffer
* @alias TermWriter.prototype.write
* @see http://nodejs.org/docs/latest/api/stream.html#stream_writable_write_chunk_encoding_callback
*/
TermWriter.prototype._write = function(chunk, encoding, callback) {
	var len = 1;
	if(typeof chunk !== 'string')
		chunk = chunk.toString();

	if(this.oldChunk !== null) {
		chunk = this.oldChunk + chunk;
		this.oldChunk = null;
	}

	while(chunk.length > 0 && len > 0) {
		len = this.callHandler('chr', chunk[0], chunk);
		if(len === null) {
			for(len = 1; len < chunk.length &&
				!(chunk[len] in this.handlers.chr); len++);

			this.buffer.write(chunk.substr(0, len));
		}

		if(len > 0)
			chunk = chunk.slice(len);
	}
	if(chunk.length !== 0)
		this.oldChunk = chunk;
	this.emit('ready');
	callback();
};

/**
* calls an handler
* @param type {string} one of the following types:
*

*
chr: interprets special characters (such as \r or \b)

*
esc: interprets simple escape characters starting with \x1b

*
csi: interprets CSI escape sequences

*
sgr: interprets SGR escape sequences

*
dcs: interprets DCS escape sequences

*
mode: interprets mode sequences

*
osc: interpretes OSC escape sequences

*

* @param cmd {string} command to execute
* @param ... {...array} passed to the command function
*/
TermWriter.prototype.callHandler = function(type, cmd) {
	if(!(type in this.handlers && cmd in this.handlers[type]))
		return null;

	var args = Array.prototype.slice.call(arguments, 1);
	if(typeof this.handlers[type][cmd] === 'string')
		cmd = this.handlers[type][cmd];

	result = this.handlers[type][cmd].apply(this, args);
	return result === undefined ? 1 : result;
};

/**
* reads a CSI command sequence from a chunk of data
* @params chunk {string} a chunk of data to parse
* @returns {{args: Number|Array, mod: String, cmd: String, length: Number}}
*/
TermWriter.prototype.parseCsi = function(chunk) {
	var i;
	var match = CSI_PATTERN.exec(chunk);
	if(match === null)
		return null;
	var args = match[2] === "" ? [] : match[2].split(';');
	for(i = 0; i < args.length; i++)
		args[i] = +args[i];
	return {
		args: args,
		mod: match[1],
		cmd: match[3],
		length: match[0].length
	};
};

/**
* reads a OSC command sequence from a chunk of data
* @params chunk {string} a chunk of data to parse
* @returns {{args: String|Array, mod: String, cmd: String, length: Number,
* terminated: Boolean}}
*/
TermWriter.prototype.parseOsc = function(chunk) {
	var match = OSC_PATTERN.exec(chunk);
	if(match === null)
		return null;
	return {
		args: match[2].split(';'),
		cmd: match[1],
		terminated: match[3] === '\x07',
		length: match[0].length
	};
};

/**
* reads a OSC command sequence from a chunk of data
* @params chunk {string} a chunk of data to parse
* @returns {{args: String|Array, mod: String, cmd: String, length: Number}}
*/
TermWriter.prototype.parseDcs = function(chunk) {
	var i;
	var match = DCS_PATTERN.exec(chunk);
	if(match === null)
		return null;
	return {
		args: [null,null],
		mod: match[1],
		cmd: match[1],
		length: match[0].length
	};
};

/**
* @see TermBuffer.prototype.toString
*/
TermWriter.prototype.toString = function() {
	return this.buffer.toString.apply(this.buffer, arguments);
};
<commit_msg>lib/terminal.js: using Terminal instead of TermWriter.<commit_after>var inherits = require('util').inherits;

var CSI_PATTERN = /^\x1b\[([?!>]?)([0-9;]*)([@A-Za-z`]?)/;
var DCS_PATTERN = /^\x1bP([0-9;@A-Za-z`]*)\x1b\\/;
var OSC_PATTERN = /^\x1b\]([0-9]+);([^\x07]*)(\x07?)/;

/**
* Terminal is the glue between a TerminalBuffer and the escape sequence
* interpreters.
* @constructor
*/
function Terminal(buffer) {
	Terminal.super_.call(this, { decodeStrings: false });
	this.buffer = buffer;
	this.oldChunk = null;
}
inherits(Terminal, require('stream').Writable);
module.exports = Terminal;

Terminal.prototype.handlers = {
	chr: require('./handler/chr.js'),
	esc: require('./handler/esc.js'),
	csi: require('./handler/csi.js'),
	sgr: require('./handler/sgr.js'),
	dcs: require('./handler/dcs.js'),
	mode: require('./handler/mode.js'),
	osc: require('./handler/osc.js'),
};

/**
* Takes a chunk of data, interprets its escape sequences, and fills backend buffer
* @alias Terminal.prototype.write
* @see http://nodejs.org/docs/latest/api/stream.html#stream_writable_write_chunk_encoding_callback
*/
Terminal.prototype._write = function(chunk, encoding, callback) {
	var len = 1;
	if(typeof chunk !== 'string')
		chunk = chunk.toString();

	if(this.oldChunk !== null) {
		chunk = this.oldChunk + chunk;
		this.oldChunk = null;
	}

	while(chunk.length > 0 && len > 0) {
		len = this.callHandler('chr', chunk[0], chunk);
		if(len === null) {
			for(len = 1; len < chunk.length &&
				!(chunk[len] in this.handlers.chr); len++);

			this.buffer.write(chunk.substr(0, len));
		}

		if(len > 0)
			chunk = chunk.slice(len);
	}
	if(chunk.length !== 0)
		this.oldChunk = chunk;
	this.emit('ready');
	callback();
};

/**
* calls an handler
* @param type {string} one of the following types:
*

*
chr: interprets special characters (such as \r or \b)

*
esc: interprets simple escape characters starting with \x1b

*
csi: interprets CSI escape sequences

*
sgr: interprets SGR escape sequences

*
dcs: interprets DCS escape sequences

*
mode: interprets mode sequences

*
osc: interpretes OSC escape sequences

*

* @param cmd {string} command to execute
* @param ... {...array} passed to the command function
*/
Terminal.prototype.callHandler = function(type, cmd) {
	if(!(type in this.handlers && cmd in this.handlers[type]))
		return null;

	var args = Array.prototype.slice.call(arguments, 1);
	if(typeof this.handlers[type][cmd] === 'string')
		cmd = this.handlers[type][cmd];

	result = this.handlers[type][cmd].apply(this, args);
	return result === undefined ? 1 : result;
};

/**
* reads a CSI command sequence from a chunk of data
* @params chunk {string} a chunk of data to parse
* @returns {{args: Number|Array, mod: String, cmd: String, length: Number}}
*/
Terminal.prototype.parseCsi = function(chunk) {
	var i;
	var match = CSI_PATTERN.exec(chunk);
	if(match === null)
		return null;
	var args = match[2] === "" ? [] : match[2].split(';');
	for(i = 0; i < args.length; i++)
		args[i] = +args[i];
	return {
		args: args,
		mod: match[1],
		cmd: match[3],
		length: match[0].length
	};
};

/**
* reads a OSC command sequence from a chunk of data
* @params chunk {string} a chunk of data to parse
* @returns {{args: String|Array, mod: String, cmd: String, length: Number,
* terminated: Boolean}}
*/
Terminal.prototype.parseOsc = function(chunk) {
	var match = OSC_PATTERN.exec(chunk);
	if(match === null)
		return null;
	return {
		args: match[2].split(';'),
		cmd: match[1],
		terminated: match[3] === '\x07',
		length: match[0].length
	};
};

/**
* reads a OSC command sequence from a chunk of data
* @params chunk {string} a chunk of data to parse
* @returns {{args: String|Array, mod: String, cmd: String, length: Number}}
*/
Terminal.prototype.parseDcs = function(chunk) {
	var i;
	var match = DCS_PATTERN.exec(chunk);
	if(match === null)
		return null;
	return {
		args: [null,null],
		mod: match[1],
		cmd: match[1],
		length: match[0].length
	};
};

/**
* @see TermBuffer.prototype.toString
*/
Terminal.prototype.toString = function() {
	return this.buffer.toString.apply(this.buffer, arguments);
};
<|endoftext|>


<commit_before>var obj_canvas,
obj_c,
cp_canvas = null;

var canvas
var video_canvas,
vid_c;

var brown_const=0;

var vid_width = 640;
var vid_height = 480;
var n_object = 20;
var m_object = 5;

var canvas;
var context;

function setupD3(){
	var canvas = d3.select("#canvasArea").append("canvas")
    	.attr("width", vid_width)
    	.attr("height", vid_height);

	var context = canvas.node().getContext("2d");
}

function getVideo(){
    getVidFrame("http://171.65.102.132:8080/?action=snapshot?t=" + new Date().getTime(), function(image) {
		context.clearRect(0, 0, vid_width, vid_height);
		context.drawImage(image, 0, 0, vid_width, vid_height);
	});

	function getVidFrame(path, callback) {
  		var image = new Image;
  		image.onload = function() {
  			callback(image);
  			compareFrame(image);
  		};
  		image.src = path;
	}
}

var gameobject = d3.range(n_object).map(function() {
	var x = Math.random() * vid_width, y = Math.random() * vid_height;
	return {
		vx: Math.random() * 2 - 1,
		vy: Math.random() * 2 - 1,
		path: d3.range(m_object).map(function() { return [x, y]; }),
		count: 0
	};
});

var w = 640,
    h = 480,
    n = 20,
    m = 12,
    degrees = 180 / Math.PI;

var spermatozoa = d3.range(n).map(function() {
  var x = Math.random() * w, y = Math.random() * h;
  return {
    vx: Math.random() * 2 - 1,
    vy: Math.random() * 2 - 1,
    path: d3.range(m).map(function() { return [x, y]; }),
    count: 0
  };
});

var svg = d3.select("canvas").append("svg:svg")
    .attr("width", w)
    .attr("height", h);

var g = svg.selectAll("g")
    .data(spermatozoa)
  .enter().append("svg:g");

var head = g.append("svg:ellipse")
    .attr("rx", 6.5)
    .attr("ry", 4);

g.append("svg:path")
    .map(function(d) { return d.path.slice(0, 3); })
    .attr("class", "mid");

g.append("svg:path")
    .map(function(d) { return d.path; })
    .attr("class", "tail");

var tail = g.selectAll("path");

d3.timer(function() {
	//getVideo();
  for (var i = -1; ++i < n;) {
    var spermatozoon = spermatozoa[i],
        path = spermatozoon.path,
        dx = spermatozoon.vx,
        dy = spermatozoon.vy,
        x = path[0][0] += dx,
        y = path[0][1] += dy,
        speed = Math.sqrt(dx * dx + dy * dy),
        count = speed * 10,
        k1 = -5 - speed / 3;

    // Bounce off the walls.
    if (x < 0 || x > w) spermatozoon.vx *= -1;
    if (y < 0 || y > h) spermatozoon.vy *= -1;

    // Swim!
    for (var j = 0; ++j < m;) {
      var vx = x - path[j][0],
          vy = y - path[j][1],
          k2 = Math.sin(((spermatozoon.count += count) + j * 3) / 300) / speed;
      path[j][0] = (x += dx / speed * k1) - dy * k2;
      path[j][1] = (y += dy / speed * k1) + dx * k2;
      speed = Math.sqrt((dx = vx) * dx + (dy = vy) * dy);
    }
  }

  head.attr("transform", function(d) {
    return "translate(" + d.path[0] + ")rotate(" + Math.atan2(d.vy, d.vx) * degrees + ")";
  });

  tail.attr("d", function(d) {
    return "M" + d.join("L");
  });
});

function game(){
	switch(gamephase)
	{
		case 'pre-game':
			// draw intro
		break;
		case 'game-rest':
    		vid_c.fillStyle = "#fff";
    		vid_c.font="14px sans-serif";
    		vid_c.fillText('New target ...',200,20);
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
		break;
		case 'game-action':
    		vid_c.fillStyle = "#fff";
    		vid_c.font="14px sans-serif";
    		vid_c.fillText('Run! Run! Run!',200,20);
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
		break;
		case 'gameover':
    		vid_c.fillStyle = "#fff";
    		vid_c.font="14px sans-serif";
    		vid_c.textAlign="start";
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
    		vid_c.fillStyle = "rgba(253,172,13,1)";
    		vid_c.font="40pt sans-serif";
    		vid_c.textAlign="center";
    		vid_c.fillText('GAME OVER',vid_width/2,vid_height/2-100);
    		vid_c.fillStyle = "#fff";
    		vid_c.font="20pt sans-serif";
    		vid_c.fillText(username+' scored '+score_val,vid_width/2,vid_height/2);
		break;
		default:
			vid_c.fillStyle = "#fff";
			vid_c.font="14px sans-serif";
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
	}
}

var shipX=vid_width/2,
	shipY=vid_height/2,
	shipRad,
	shipL=20,
	starX=40,
	starY=20;
var gamelevel;
var int_star=-1;
var int_engine=-1;
var engine = false;
var rest = false;
var starTimer;
var enginerTimer;
var gamephase;
var score_val = 0;
var actionTimer;
var hit = new Array();
var unit=30;

function setGameAction(){
	actionTimer = window.requestAnimationFrame(actionLoop);
}

function setbackPreGame(){
    score_val = 0;
    hit = new Array();
    gamelevel=1;

	shipX = vid_width/2;
    shipY = vid_height/2;

    gamephase='pre-game';
}

function setGameOver(){
  	window.cancelAnimationFrame(actionTimer);
    actionTimer = undefined;
}

function actionLoop(){
	switch(gamephase)
	{
		case 'rest':
  			if(rest==false)
			{
				rest=true;
				int_star=gamelevel+6;
				getStarLocation(); // get new starX, starY, shipRad
				starTimer=window.setInterval(showStar,500);
			}
			drawStar(shipX,shipY,starX,starY,gamelevel-(int_star-6));
			drawShip(shipX,shipY,shipRad);
			actionTimer = window.requestAnimationFrame(gameLoop);
  		break;
		case 'engine':
			console.log(hit);
  			if(hit>0)
			{
				window.clearInterval(engineTimer);
				engine=false;
				rest=false;
				int_star=-1;
				int_engine=-1;
				gamephase='gameover';
				gamelevel=-1;
			}
			else
			{
				score_val=score_val+10;
				if(engine==false)
				{
					engine=true;
					int_engine=gamelevel+4;
					engineTimer=window.setInterval(runEngine,500);
				}
			}
			drawStar(shipX,shipY,starX,starY,gamelevel-(int_star-6));
			drawShip(shipX,shipY,shipRad);

  		break;
	}
}

function getStarLocation(){
	shipRad=Math.random()*Math.PI*2;
	starX=shipX+unit*(Math.cos(shipRad))*gamelevel;
	starY=shipY+unit*(Math.sin(shipRad))*gamelevel;
}

function getShipLocation(){
	var step = gamelevel-(int_engine-4);
	var u = (step > gamelevel - 1) ? 0 : 1;
	shipX=shipX+unit*(Math.cos(shipRad))*u;
	shipY=shipY+unit*(Math.sin(shipRad))*u;
}

function showStar(){
	if(int_star>0)
	{
		int_star=int_star-1;
	}
	else
	{
		window.clearInterval(starTimer);
		rest=false;
		gamephase='engine';
	}
}

function runEngine(){
	if(int_engine>0)
	{
		getShipLocation();
		int_engine=int_engine-1;
	}
	else
	{
		window.clearInterval(engineTimer);
		engine=false;
		gamephase='rest';
		if(gamelevel<10)
		{
			gamelevel=gamelevel+1;
		}
	}
}

function gameOver(){
    var msg = {type:'sendscore', user:username, score:score_val};
    socket.json.send(msg);
}

/*******************************************************************************
  Copyright (C) 2009 Tom Stoeveken
  This program is free software;
  you can redistribute it and/or modify it under the terms of the
  GNU General Public License, version 2.
  See the file COPYING for details.
*******************************************************************************/

var img1 = null;
var img2 = null;
var md_canvas = null;

function setupMotionDetection() {
  md_canvas = document.getElementById('mdCanvas');
  test_canvas = document.getElementById('testCanvas');
  md_canvas.width = vid_width;
  md_canvas.height = vid_height;
}

/*
  compare two images and count the differences

  input.: image1 and image2 are Image() objects
  input.: threshold specifies by how much the color value of a pixel
          must differ before they are regarded to be different

  return: number of different pixels
*/

function compare(image1, image2, ptX, ptY, threshold, ObjR) {
  var movement = new Array(0,0,0,0);
  var md_ctx = md_canvas.getContext("2d");
  var width = md_canvas.width/2, height = md_canvas.height/2;

  // copy images into canvas element
  // these steps scale the images and decodes the image data
  md_ctx.drawImage(image1, 0, 0, width, height);
  md_ctx.drawImage(image2, width, 0, width, height);

  // this makes r,g,b,alpha data of images available
  var pixels1 = md_ctx.getImageData(0, 0, width, height);
  var pixels2 = md_ctx.getImageData(width, 0, width, height);

  // substract picture1 from picture2
  // if they differ set color value to max,
  // if the difference is below threshold set difference to 0.
  for (var x = Math.round((ptX-ObjR)/2); x < Math.round((ptX+ObjR)/2); x++) {
    for (var y = Math.round((ptY-ObjR)/2); y < Math.round((ptY+ObjR)/2); y++) {

      // each pixel has a red, green, blue and alpha value
      // all values are stored in a linear array
      var i = x*4 + y*4*pixels1.width;

      var ch0 = ((pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
      var ch1 = ((pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
      var ch2 = ((pixels1.data[i] - pixels2.data[i])>threshold)?255:0;

      // count differing pixels
      var n = (x<Math.round(ptX/2))?0:1;
      var m = (y<Math.round(ptY/2))?0:2;
      movement[n+m] += Math.min(1, ch0 + ch1 + ch2);
    }
  }
  return movement;
}

function compareFrame(img1,arrObject) {
  // just compare if there are two pictures
  if ( img2 != null ) {
    var res=[0,0,0,0];
    var ObjR=10;

    try {
    		for (var n=0; n<arrMotion.length; n++){
    			// arrObject [active, position_x, position_y, detection_radius]
    			res = compare(img1, img2, arrObject[n][1], arrObject[n][2], 10, arrObject[n][3]);
    			    if ((res[0]>400)||(res[1]>400)||(res[2]>400)||(res[3]>400)){
            			res[0]=0;res[1]=0;res[2]=0;res[3]=0;
    				}
				hit[n]=res[0]+res[1]+res[2]+res[3];
    		}
    	}
    catch(e) {
    		// errors
    	}
	}
	img2 = img1;
}
<commit_msg>playing with d3<commit_after>var obj_canvas,
obj_c,
cp_canvas = null;

var canvas
var video_canvas,
vid_c;

var brown_const=0;

var vid_width = 640;
var vid_height = 480;
var n_object = 20;
var m_object = 5;

var canvas;
var context;

function setupD3(){
	var canvas = d3.select("#canvasArea").append("canvas")
    	.attr("width", vid_width)
    	.attr("height", vid_height);

	var context = canvas.node().getContext("2d");

function getVideo(){
    getVidFrame("http://171.65.102.132:8080/?action=snapshot?t=" + new Date().getTime(), function(image) {
		context.clearRect(0, 0, vid_width, vid_height);
		context.drawImage(image, 0, 0, vid_width, vid_height);
	});

	function getVidFrame(path, callback) {
  		var image = new Image;
  		image.onload = function() {
  			callback(image);
  			compareFrame(image);
  		};
  		image.src = path;
	}
}

var gameobject = d3.range(n_object).map(function() {
	var x = Math.random() * vid_width, y = Math.random() * vid_height;
	return {
		vx: Math.random() * 2 - 1,
		vy: Math.random() * 2 - 1,
		path: d3.range(m_object).map(function() { return [x, y]; }),
		count: 0
	};
});

var w = 640,
    h = 480,
    n = 20,
    m = 12,
    degrees = 180 / Math.PI;

var spermatozoa = d3.range(n).map(function() {
  var x = Math.random() * w, y = Math.random() * h;
  return {
    vx: Math.random() * 2 - 1,
    vy: Math.random() * 2 - 1,
    path: d3.range(m).map(function() { return [x, y]; }),
    count: 0
  };
});

var svg = d3.select("canvas").append("svg:svg")
    .attr("width", w)
    .attr("height", h);

var g = svg.selectAll("g")
    .data(spermatozoa)
  .enter().append("svg:g");

var head = g.append("svg:ellipse")
    .attr("rx", 6.5)
    .attr("ry", 4);

g.append("svg:path")
    .map(function(d) { return d.path.slice(0, 3); })
    .attr("class", "mid");

g.append("svg:path")
    .map(function(d) { return d.path; })
    .attr("class", "tail");

var tail = g.selectAll("path");

d3.timer(function() {
	getVideo();
  for (var i = -1; ++i < n;) {
    var spermatozoon = spermatozoa[i],
        path = spermatozoon.path,
        dx = spermatozoon.vx,
        dy = spermatozoon.vy,
        x = path[0][0] += dx,
        y = path[0][1] += dy,
        speed = Math.sqrt(dx * dx + dy * dy),
        count = speed * 10,
        k1 = -5 - speed / 3;

    // Bounce off the walls.
    if (x < 0 || x > w) spermatozoon.vx *= -1;
    if (y < 0 || y > h) spermatozoon.vy *= -1;

    // Swim!
    for (var j = 0; ++j < m;) {
      var vx = x - path[j][0],
          vy = y - path[j][1],
          k2 = Math.sin(((spermatozoon.count += count) + j * 3) / 300) / speed;
      path[j][0] = (x += dx / speed * k1) - dy * k2;
      path[j][1] = (y += dy / speed * k1) + dx * k2;
      speed = Math.sqrt((dx = vx) * dx + (dy = vy) * dy);
    }
  }

  head.attr("transform", function(d) {
    return "translate(" + d.path[0] + ")rotate(" + Math.atan2(d.vy, d.vx) * degrees + ")";
  });

  tail.attr("d", function(d) {
    return "M" + d.join("L");
  });
});

}

function game(){
	switch(gamephase)
	{
		case 'pre-game':
			// draw intro
		break;
		case 'game-rest':
    		vid_c.fillStyle = "#fff";
    		vid_c.font="14px sans-serif";
    		vid_c.fillText('New target ...',200,20);
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
		break;
		case 'game-action':
    		vid_c.fillStyle = "#fff";
    		vid_c.font="14px sans-serif";
    		vid_c.fillText('Run! Run! Run!',200,20);
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
		break;
		case 'gameover':
    		vid_c.fillStyle = "#fff";
    		vid_c.font="14px sans-serif";
    		vid_c.textAlign="start";
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
    		vid_c.fillStyle = "rgba(253,172,13,1)";
    		vid_c.font="40pt sans-serif";
    		vid_c.textAlign="center";
    		vid_c.fillText('GAME OVER',vid_width/2,vid_height/2-100);
    		vid_c.fillStyle = "#fff";
    		vid_c.font="20pt sans-serif";
    		vid_c.fillText(username+' scored '+score_val,vid_width/2,vid_height/2);
		break;
		default:
			vid_c.fillStyle = "#fff";
			vid_c.font="14px sans-serif";
    		vid_c.fillText('player : ' + username + '  score : ' +score_val ,20,20);
	}
}

var shipX=vid_width/2,
	shipY=vid_height/2,
	shipRad,
	shipL=20,
	starX=40,
	starY=20;
var gamelevel;
var int_star=-1;
var int_engine=-1;
var engine = false;
var rest = false;
var starTimer;
var enginerTimer;
var gamephase;
var score_val = 0;
var actionTimer;
var hit = new Array();
var unit=30;

function setGameAction(){
	actionTimer = window.requestAnimationFrame(actionLoop);
}

function setbackPreGame(){
    score_val = 0;
    hit = new Array();
    gamelevel=1;

	shipX = vid_width/2;
    shipY = vid_height/2;

    gamephase='pre-game';
}

function setGameOver(){
  	window.cancelAnimationFrame(actionTimer);
    actionTimer = undefined;
}

function actionLoop(){
	switch(gamephase)
	{
		case 'rest':
  			if(rest==false)
			{
				rest=true;
				int_star=gamelevel+6;
				getStarLocation(); // get new starX, starY, shipRad
				starTimer=window.setInterval(showStar,500);
			}
			drawStar(shipX,shipY,starX,starY,gamelevel-(int_star-6));
			drawShip(shipX,shipY,shipRad);
			actionTimer = window.requestAnimationFrame(gameLoop);
  		break;
		case 'engine':
			console.log(hit);
  			if(hit>0)
			{
				window.clearInterval(engineTimer);
				engine=false;
				rest=false;
				int_star=-1;
				int_engine=-1;
				gamephase='gameover';
				gamelevel=-1;
			}
			else
			{
				score_val=score_val+10;
				if(engine==false)
				{
					engine=true;
					int_engine=gamelevel+4;
					engineTimer=window.setInterval(runEngine,500);
				}
			}
			drawStar(shipX,shipY,starX,starY,gamelevel-(int_star-6));
			drawShip(shipX,shipY,shipRad);

  		break;
	}
}

function getStarLocation(){
	shipRad=Math.random()*Math.PI*2;
	starX=shipX+unit*(Math.cos(shipRad))*gamelevel;
	starY=shipY+unit*(Math.sin(shipRad))*gamelevel;
}

function getShipLocation(){
	var step = gamelevel-(int_engine-4);
	var u = (step > gamelevel - 1) ? 0 : 1;
	shipX=shipX+unit*(Math.cos(shipRad))*u;
	shipY=shipY+unit*(Math.sin(shipRad))*u;
}

function showStar(){
	if(int_star>0)
	{
		int_star=int_star-1;
	}
	else
	{
		window.clearInterval(starTimer);
		rest=false;
		gamephase='engine';
	}
}

function runEngine(){
	if(int_engine>0)
	{
		getShipLocation();
		int_engine=int_engine-1;
	}
	else
	{
		window.clearInterval(engineTimer);
		engine=false;
		gamephase='rest';
		if(gamelevel<10)
		{
			gamelevel=gamelevel+1;
		}
	}
}

function gameOver(){
    var msg = {type:'sendscore', user:username, score:score_val};
    socket.json.send(msg);
}

/*******************************************************************************
  Copyright (C) 2009 Tom Stoeveken
  This program is free software;
  you can redistribute it and/or modify it under the terms of the
  GNU General Public License, version 2.
  See the file COPYING for details.
*******************************************************************************/

var img1 = null;
var img2 = null;
var md_canvas = null;

function setupMotionDetection() {
  md_canvas = document.getElementById('mdCanvas');
  test_canvas = document.getElementById('testCanvas');
  md_canvas.width = vid_width;
  md_canvas.height = vid_height;
}

/*
  compare two images and count the differences

  input.: image1 and image2 are Image() objects
  input.: threshold specifies by how much the color value of a pixel
          must differ before they are regarded to be different

  return: number of different pixels
*/

function compare(image1, image2, ptX, ptY, threshold, ObjR) {
  var movement = new Array(0,0,0,0);
  var md_ctx = md_canvas.getContext("2d");
  var width = md_canvas.width/2, height = md_canvas.height/2;

  // copy images into canvas element
  // these steps scale the images and decodes the image data
  md_ctx.drawImage(image1, 0, 0, width, height);
  md_ctx.drawImage(image2, width, 0, width, height);

  // this makes r,g,b,alpha data of images available
  var pixels1 = md_ctx.getImageData(0, 0, width, height);
  var pixels2 = md_ctx.getImageData(width, 0, width, height);

  // substract picture1 from picture2
  // if they differ set color value to max,
  // if the difference is below threshold set difference to 0.
  for (var x = Math.round((ptX-ObjR)/2); x < Math.round((ptX+ObjR)/2); x++) {
    for (var y = Math.round((ptY-ObjR)/2); y < Math.round((ptY+ObjR)/2); y++) {

      // each pixel has a red, green, blue and alpha value
      // all values are stored in a linear array
      var i = x*4 + y*4*pixels1.width;

      var ch0 = ((pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
      var ch1 = ((pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
      var ch2 = ((pixels1.data[i] - pixels2.data[i])>threshold)?255:0;

      // count differing pixels
      var n = (x<Math.round(ptX/2))?0:1;
      var m = (y<Math.round(ptY/2))?0:2;
      movement[n+m] += Math.min(1, ch0 + ch1 + ch2);
    }
  }
  return movement;
}

function compareFrame(img1,arrObject) {
  // just compare if there are two pictures
  if ( img2 != null ) {
    var res=[0,0,0,0];
    var ObjR=10;

    try {
    		for (var n=0; n<arrMotion.length; n++){
    			// arrObject [active, position_x, position_y, detection_radius]
    			res = compare(img1, img2, arrObject[n][1], arrObject[n][2], 10, arrObject[n][3]);
    			    if ((res[0]>400)||(res[1]>400)||(res[2]>400)||(res[3]>400)){
            			res[0]=0;res[1]=0;res[2]=0;res[3]=0;
    				}
				hit[n]=res[0]+res[1]+res[2]+res[3];
    		}
    	}
    catch(e) {
    		// errors
    	}
	}
	img2 = img1;
}
<|endoftext|>


<commit_before>define([
    'kb_plugin_login',
    'preact',
    'htm',
    '../components/Signin'
], (
    Plugin,
    preact,
    htm,
    Signin
) => {
    'use strict';

    const { h, render } = preact;
    const html = htm.bind(h);

    class SigninWidget {
        constructor({ runtime }) {
            if (!runtime) {
                throw {
                    name: 'RuntimeMissing',
                    message: 'The runtime argument is required but is missing',
                    suggestion: 'This is an application error, and no fault of yours.'
                };
            }
            this.runtime = runtime;
            this.hostNode = null;
            this.container = null;
            this.isLoginView = null;
            this.profile = null;
            this.imagePath = Plugin.plugin.fullPath + '/images';
        }

        doSignout() {
            this.runtime
                .service('session')
                .logout()
                .then(() => {
                    this.runtime.send('app', 'navigate', {
                        path: 'auth2/signedout'
                    });
                })
                .catch((err) => {
                    console.error('ERROR');
                    console.error(err);
                    alert('Error signing out (check console for details)');
                });
        }

        getProfile() {
            if (this.runtime.service('session').isLoggedIn()) {
                return this.runtime
                    .service('userprofile')
                    .getProfile()
                    .then((profile) => {
                        this.profile = profile;
                        this.render();
                    })
                    .catch((err) => {
                        // TODO: render error
                        console.error('ERROR', err);
                    });
            } else {
                this.profile = null;
                this.render();
            }
        }

        render() {
            const props = {
                profile: this.profile,
                signout: this.doSignout.bind(this),
                isLoginView: this.isLoginView
            };
            const component = html`<${Signin} ...${props}/>`;
            render(component, this.container);
        }

        // LIFECYCLE API

        attach(node) {
            this.hostNode = node;
            this.container = this.hostNode.appendChild(document.createElement('div'));
            this.container.classList.add('kb_plugin_login_signin');
            this.container.setAttribute('data-k-b-testhook-plugin', 'login');
        }

        start() {
            // Refetch the profile (and re-render) if the user profile in the ui has
            // been changed.
            this.runtime.service('userprofile').onChange(() => {
                this.getProfile();
            });

            // Detect whether we should disable the login button.
            this.runtime.receive('route', 'routed', (message) => {
                const path = message.data.request.path.join('/');
                if (path === 'login') {
                    this.isLoginView = true;
                } else {
                    this.isLoginView = false;
                }
                this.render();
            });

            // Get the initial user profile (or not)
            this.getProfile();
        }

        detach() {
            if (this.hostNode && this.container) {
                this.hostNode.removeChild(this.container);
            }
        }

        stop() {
            return null;
        }
    }

    return SigninWidget;
});
<commit_msg>support profile:reload message for iframe plugins<commit_after>define([
    'kb_plugin_login',
    'preact',
    'htm',
    '../components/Signin'
], (
    Plugin,
    preact,
    htm,
    Signin
) => {
    'use strict';

    const { h, render } = preact;
    const html = htm.bind(h);

    class SigninWidget {
        constructor({ runtime }) {
            if (!runtime) {
                throw {
                    name: 'RuntimeMissing',
                    message: 'The runtime argument is required but is missing',
                    suggestion: 'This is an application error, and no fault of yours.'
                };
            }
            this.runtime = runtime;
            this.hostNode = null;
            this.container = null;
            this.isLoginView = null;
            this.profile = null;
            this.imagePath = Plugin.plugin.fullPath + '/images';
        }

        doSignout() {
            this.runtime
                .service('session')
                .logout()
                .then(() => {
                    this.runtime.send('app', 'navigate', {
                        path: 'auth2/signedout'
                    });
                })
                .catch((err) => {
                    console.error('ERROR');
                    console.error(err);
                    alert('Error signing out (check console for details)');
                });
        }

        getProfile() {
            if (this.runtime.service('session').isLoggedIn()) {
                return this.runtime
                    .service('userprofile')
                    .getProfile()
                    .then((profile) => {
                        this.profile = profile;
                        this.render();
                    })
                    .catch((err) => {
                        // TODO: render error
                        console.error('ERROR', err);
                    });
            } else {
                this.profile = null;
                this.render();
            }
        }

        render() {
            const props = {
                profile: this.profile,
                signout: this.doSignout.bind(this),
                isLoginView: this.isLoginView
            };
            const component = html`<${Signin} ...${props}/>`;
            render(component, this.container);
        }

        // LIFECYCLE API

        attach(node) {
            this.hostNode = node;
            this.container = this.hostNode.appendChild(document.createElement('div'));
            this.container.classList.add('kb_plugin_login_signin');
            this.container.setAttribute('data-k-b-testhook-plugin', 'login');
        }

        start() {
            // Refetch the profile (and re-render) if the user profile in the ui has
            // been changed.
            this.runtime.service('userprofile').onChange(() => {
                this.getProfile();
            });

            // Detect whether we should disable the login button.
            this.runtime.receive('route', 'routed', (message) => {
                const path = message.data.request.path.join('/');
                if (path === 'login') {
                    this.isLoginView = true;
                } else {
                    this.isLoginView = false;
                }
                this.render();
            });

            // Get the initial user profile (or not)
            this.getProfile();

            this.runtime.receive('profile', 'reload', () => {
                this.getProfile();
            });
        }

        detach() {
            if (this.hostNode && this.container) {
                this.hostNode.removeChild(this.container);
            }
        }

        stop() {
            return null;
        }
    }

    return SigninWidget;
});
<|endoftext|>