<commit_before>#!/usr/bin/env node

var Promise = require('bluebird'),
  program = require('commander'),
  ProgressBar = require('progress'),
  request = require('request'),
  esrefactor = require('esrefactor'),
  esprima = require('esprima'),
  estraverse = require('estraverse'),
  escodegen = require('escodegen'),
  mkdirp = Promise.promisify(require('mkdirp')),
  path = require('path'),
  fs = Promise.promisifyAll(require('fs')),
  pkg = require('./package.json'),
  plugLogin = Promise.promisify(require('plug-login').guest),
  $ = require('./lib/ast'),
  cleanAst = require('./lib/clean-ast')

var _v

program
  .usage('[options]')
  .version(pkg.version)
  .option('-m, --mapping [file]', 'File containing the mapping JSON ' +
            '(optional, it\'s auto-generated if no file is given)')
  .option('-o, --out [dir]', 'Output directory [out/]')
  .option('--save-source', 'Copy the source javascript to the output directory')
  .option('--save-mapping', 'Copy the mapping file to the output directory')
  .parse(process.argv)

// formatting for escodegen
var codegenOptions = {
  format: { indent: { style: '  ' } },
  comment: true
}

var requestOpts = {
  headers: { 'user-agent': 'replug' }
}

// poor lady's merge
function merge(o, a) {
  Object.keys(a).forEach(function (k) { o[k] = a[k] })
  return o
}

function progress(text, size) {
  var bar = new ProgressBar(text + ' [:bar] :percent', {
    total: size,
    width: 40,
    complete: '#',
    clear: true,
    callback: function () {
      console.log(text + ' done')
    }
  })
  return bar
}

function fetchAppFile(url) {
  return new Promise(function (resolve, reject) {
    request(url, function (e, res) {
      if (e) reject(e)
      else   resolve(res && res.body)
    })
    .on('response', function (res) {
      var size = parseInt(res.headers['content-length'], 10)
      var bar = progress('downloading app javascript...', size)
      res.on('data', function (chunk) {
        bar.tick(chunk.length)
      })
    })
  })
}

function variableNameFor(dep, mapping) {
  var libraryNames = {
    jquery: '$',
    backbone: 'Backbone',
    handlebars: 'Handlebars',
    underscore: '_'
  }
  return dep in libraryNames
       ? libraryNames[dep]
       : dep.indexOf('hbs!templates/') === 0
       ? 'template' + dep.split('/').pop()
       : dep in mapping
       ? mapping[dep].split('/').pop().replace(/-/g, '_')
       : dep
}

function parseModules(str) {
  var ast = esprima.parse(str, { range: true })
  var modules = {}
  process.stdout.write('parsing javascript...')
  estraverse.traverse(ast, {
    enter: function (node) {
      if (node.type === 'CallExpression' &&
          node.callee.name === 'define') {
        var name = node.arguments[0],
          deps = node.arguments[1],
          factory = node.arguments[2]
        if (deps.type === 'ArrayExpression') {
          deps = deps.elements
        }
        else {
          factory = deps
          deps = []
        }
        modules[name.value] = {
          deps: deps,
          ast: factory
        }
      }
    }
  })
  console.log(' done')

  return modules
}

function findReturnVar(ast) {
  var lastSt = ast.body[ast.body.length - 1]
  if (lastSt && lastSt.type === 'ReturnStatement') {
    var retVal = lastSt.argument
    return retVal.type === 'NewExpression'
      ? retVal.callee
      : retVal.type === 'Identifier'
      ? retVal
      : null
  }
}

function cleanModules(modules) {
  var bar = progress('cleaning module ASTs...', Object.keys(modules).length)
  for (var name in modules) if (modules.hasOwnProperty(name)) {
    cleanAst(modules[name].ast)
    bar.tick()
  }
  return modules
}

function remapModuleNames(modules, mapping) {
  var bar = progress('remapping module names...', Object.keys(modules).length)
  for (var name in modules) if (modules.hasOwnProperty(name)) {
    var ast = modules[name].ast,
      deps = modules[name].deps,
      params = ast.params && ast.params.map(function (p) { return p.name })

    if (!params) {
      bar.tick()
      continue
    }
    var renames = []
    // build ast of dependency require()s
    var depsAst = deps.map(function (dep, i) {
      if (!params[i]) params[i] = '__' + i
      var newName = 'unknown'
      // rename variables according to their module names
      if (mapping[dep.value]) {
        newName = variableNameFor(dep.value, mapping)
        renames.push({ idx: dep.range[0], to: newName })
      }
      else if (/^hbs!templates\//.test(dep.value)) {
        newName = 'template' + dep.value.split('/').pop()
        renames.push({ idx: dep.range[0], to: newName })
      }
      var range = [ dep.range[0] - 1, dep.range[1] + 1 ]
      return {
        type: 'VariableDeclaration',
        kind: 'var',
        range: range,
        declarations: [ {
          type: 'VariableDeclarator',
          id: merge($.id(params[i]), { range: dep.range }),
          range: range,
          init: {
            type: 'CallExpression',
            callee: $.id('require'),
            range: range,
            arguments: [ merge(dep, {
              trailingComments: [ {
                type: 'Block',
                value: ' ' + (dep.value in mapping ? mapping[dep.value] : 'Unknown module')
              } ]
            }) ]
          }
        } ]
      }
    })

    // move dependencies from the define() call
    // to the factory body
    ast.body.body = depsAst.concat(ast.body.body)
    ast.params = [
      $.id('require'),
      $.id('exports'),
      $.id('module')
    ]

    var returnVar = findReturnVar(ast.body)
    if (returnVar) {
      renames.push({
        idx: returnVar.range[0],
        to: variableNameFor(name, mapping)
      })
    }

    // wrap the ast in a Program node so esrefactor accepts it
    var fullAst = $.largeRange({
      type: 'Program',
      body: [ $.largeRange({
        type: 'ExpressionStatement',
        expression: ast
      }) ]
    })

    processRenames(fullAst, renames)
    bar.tick()
  }

  return modules
}

function getDependents(modules, name) {
  var dependents = []
  function isDep(d) {
    return d.value === name
  }
  for (var i in modules) if (modules.hasOwnProperty(i)) {
    if (modules[i].deps.some(isDep)) {
      dependents.push(i)
    }
  }
  return dependents
}

function findMemberExpressionName(ast) {
  var body = ast.body
  for (var i = 0, l = body.length; i < l; i++) {
    if (body[i].type === 'ExpressionStatement' &&
        body[i].expression.type === 'AssignmentExpression' &&
        body[i].expression.left.type === 'MemberExpression' &&
        body[i].expression.left.object.type === 'Identifier') {
      return body[i].expression.left.property
    }
  }
}
function addMappingForUnknownModules(modules, mapping) {
  for (var orig in mapping) {
    if (mapping[orig] === 'plug/server/socketReceiver') {
      // websocket event receiver modules don't export anything,
      // so they cannot be identified individually by plug-modules.
      // however, we have accesss to their full source here, so
      // we can extract them anyway!
      // socket event receivers set properties on a shared object,
      // which will actually be require()d by plug.dj source code,
      // and which can also be identified by plug-modules. here, we
      // can find all modules that depend on socketReceiver, and find
      // the relevant assignments.
      getDependents(modules, orig).forEach(function (name) {
        var prop = findMemberExpressionName(modules[name].ast.body)
        if (prop) {
          // some of these modules have multiple event receivers, so we
          // rename them to be a bit more clear.
          var niceName = {
            // contains a bunch of booth/wait list moderation events
            modAddDJ: 'plug/server/socket/modBooth',
            // contains subscription, XP, and PP events
            earn: 'plug/server/socket/currency',
            // contains multiple events for updates to the current room
            roomNameUpdate: 'plug/server/socket/roomUpdate',
            // this is actually the websocket manager module,
            // and it sets the window._gws property to undefined.
            // it really is just a false positive but we can abuse
            // it to get the proper module, anyway.
            // TODO detect this in a less stupid way
            _gws: 'plug/server/socket'
          }[prop.name] || 'plug/server/socket/' + prop.name
          mapping[name] = niceName
        }
      })
    }
    else if (mapping[orig] === 'plug/util/API') {
      getDependents(modules, orig).forEach(function (name) {
        var prop = findMemberExpressionName(modules[name].ast.body)
        if (prop) {
          var niceName = {
            getAdmins: 'admins',
            getAmbassadors: 'ambassadors',
            getAudience: 'audience',
            getBannedUsers: 'bannedUsers',
            getDJ: 'dj',
            getHistory: 'history',
            getHost: 'host',
            getMedia: 'media',
            getNextMedia: 'nextMedia',
            getScore: 'score',
            getStaff: 'staff',
            getTimeElapsed: 'playTime',
            getUser: 'users',
            getWaitList: 'waitlist',
            moderateForceSkip: 'moderator',
            sendChat: 'chat',
            setVolume: 'volume'
          }[prop.name] || prop.name
          mapping[name] = 'plug/util/api/' + niceName
        }
      })
    }
  }
}

function processRenames(ast, renames) {
  var renaming = new esrefactor.Context(ast)
  renames.forEach(function (r) {
    var id = renaming.identify(r.idx)
    if (id) {
      // rename manually.
      // esrefactor renames things "in-place" in the source code,
      // which means that you have to parse the source again every
      // time you rename a variable. Since we don't need to retain
      // formatting (it's minified code at this point, after all)
      // we can manually rename all variables at once without ever
      // parsing the source again.
      if (id.identifier) id.identifier.name = r.to
      if (id.declaration) id.declaration.name = r.to
      id.references.forEach(function (node) { node.name = r.to })
    }
  })
  return ast
}

function extract(modules, mapping) {
  var moduleNames = Object.keys(modules)
  var bar = progress('extracting files...', moduleNames.length)
  return Promise.each(moduleNames, function (name) {
    var ast = {
      type: 'Program',
      body: [ $.statement({
        type: 'CallExpression',
        callee: $.id('define'),
        arguments: [
          merge($.literal(name), {
            trailingComments: [ {
              type: 'Block',
              value: ' ' + (name in mapping ? mapping[name] : 'Unknown module')
            } ]
          }),
          modules[name].ast
        ]
      }) ]
    }
    return outputFile(name, mapping, escodegen.generate(ast, codegenOptions))
      .tap(bar.tick.bind(bar))
  }).return(modules)
}

function outputFile(name, mapping, beauty) {
  var file = path.join(program.out, name + '.js')
  return mkdirp(path.dirname(file))
    .then(function () {
      return fs.writeFileAsync(file, beauty)
    })
    .then(function () {
      // set up symlinks from nicer paths
      if (mapping[name] && mapping[name].indexOf('plug/') === 0) {
        var niceFile = path.join(program.out, mapping[name] + '.js')
        return makeLink(file, niceFile)
      }
    })
}

function makeLink(file, niceFile) {
  // cheaty use of path.relative to find link target path
  var linkTarget = path.relative('/' + path.dirname(niceFile), '/' + file)
  return mkdirp(path.dirname(niceFile))
    .then(function () { return fs.symlinkAsync(linkTarget, niceFile) })
}

function run(mapping, str) {
  var modules = parseModules(str)
  console.log('found', Object.keys(modules).length, 'modules.')
  modules = cleanModules(modules)
  addMappingForUnknownModules(modules, mapping)
  modules = remapModuleNames(modules, mapping)
  extract(modules, mapping)
    .tap(function () {
      return program.saveSource &&
        fs.writeFileAsync(path.join(program.out, 'source.js'), str)
    })
    .tap(function () {
      return program.saveMapping &&
        fs.writeFileAsync(path.join(program.out, 'mapping.json'),
                          JSON.stringify(mapping, null, 2))
    })
    .then(function () {
      return outputFile('version', {}, 'window._v = \'' + _v + '\';')
    })
    .then(function () { console.log('v' + _v + ' done') })
}

var mappingString
if (program.mapping) {
  mappingString = fs.readFileAsync(program.mapping, 'utf-8')
}
else {
  process.stdout.write('logging in to create mapping...')
  mappingString = plugLogin(requestOpts)
    .then(function (result) {
      console.log('  logged in to plug.dj')
      process.stdout.write('generating mapping...')
      return require('./lib/create-mapping')(result.jar)
    })
}

mappingString
  .then(JSON.parse)
  .then(function (result) {
    var mapping = result.mapping
    var sourceFile = result.appUrl
    // global!
    _v = result.version

    return Promise.props({
      mapping: mapping,
      src: /^https?:/.test(sourceFile)? fetchAppFile(sourceFile)
           : /* otherwise */            fs.readFileAsync(sourceFile, 'utf-8')
    })
  })
  .then(function (o) {
    return run(o.mapping, o.src)
  })
  .catch(function (e) { throw e })
<commit_msg>default out dir to out/<commit_after>#!/usr/bin/env node

var Promise = require('bluebird'),
  program = require('commander'),
  ProgressBar = require('progress'),
  request = require('request'),
  esrefactor = require('esrefactor'),
  esprima = require('esprima'),
  estraverse = require('estraverse'),
  escodegen = require('escodegen'),
  mkdirp = Promise.promisify(require('mkdirp')),
  path = require('path'),
  fs = Promise.promisifyAll(require('fs')),
  pkg = require('./package.json'),
  plugLogin = Promise.promisify(require('plug-login').guest),
  $ = require('./lib/ast'),
  cleanAst = require('./lib/clean-ast')

var _v

program
  .usage('[options]')
  .version(pkg.version)
  .option('-m, --mapping [file]', 'File containing the mapping JSON ' +
            '(optional, it\'s auto-generated if no file is given)')
  .option('-o, --out [dir]', 'Output directory [out/]', 'out/')
  .option('--save-source', 'Copy the source javascript to the output directory')
  .option('--save-mapping', 'Copy the mapping file to the output directory')
  .parse(process.argv)

// formatting for escodegen
var codegenOptions = {
  format: { indent: { style: '  ' } },
  comment: true
}

var requestOpts = {
  headers: { 'user-agent': 'replug' }
}

// poor lady's merge
function merge(o, a) {
  Object.keys(a).forEach(function (k) { o[k] = a[k] })
  return o
}

function progress(text, size) {
  var bar = new ProgressBar(text + ' [:bar] :percent', {
    total: size,
    width: 40,
    complete: '#',
    clear: true,
    callback: function () {
      console.log(text + ' done')
    }
  })
  return bar
}

function fetchAppFile(url) {
  return new Promise(function (resolve, reject) {
    request(url, function (e, res) {
      if (e) reject(e)
      else   resolve(res && res.body)
    })
    .on('response', function (res) {
      var size = parseInt(res.headers['content-length'], 10)
      var bar = progress('downloading app javascript...', size)
      res.on('data', function (chunk) {
        bar.tick(chunk.length)
      })
    })
  })
}

function variableNameFor(dep, mapping) {
  var libraryNames = {
    jquery: '$',
    backbone: 'Backbone',
    handlebars: 'Handlebars',
    underscore: '_'
  }
  return dep in libraryNames
       ? libraryNames[dep]
       : dep.indexOf('hbs!templates/') === 0
       ? 'template' + dep.split('/').pop()
       : dep in mapping
       ? mapping[dep].split('/').pop().replace(/-/g, '_')
       : dep
}

function parseModules(str) {
  var ast = esprima.parse(str, { range: true })
  var modules = {}
  process.stdout.write('parsing javascript...')
  estraverse.traverse(ast, {
    enter: function (node) {
      if (node.type === 'CallExpression' &&
          node.callee.name === 'define') {
        var name = node.arguments[0],
          deps = node.arguments[1],
          factory = node.arguments[2]
        if (deps.type === 'ArrayExpression') {
          deps = deps.elements
        }
        else {
          factory = deps
          deps = []
        }
        modules[name.value] = {
          deps: deps,
          ast: factory
        }
      }
    }
  })
  console.log(' done')

  return modules
}

function findReturnVar(ast) {
  var lastSt = ast.body[ast.body.length - 1]
  if (lastSt && lastSt.type === 'ReturnStatement') {
    var retVal = lastSt.argument
    return retVal.type === 'NewExpression'
      ? retVal.callee
      : retVal.type === 'Identifier'
      ? retVal
      : null
  }
}

function cleanModules(modules) {
  var bar = progress('cleaning module ASTs...', Object.keys(modules).length)
  for (var name in modules) if (modules.hasOwnProperty(name)) {
    cleanAst(modules[name].ast)
    bar.tick()
  }
  return modules
}

function remapModuleNames(modules, mapping) {
  var bar = progress('remapping module names...', Object.keys(modules).length)
  for (var name in modules) if (modules.hasOwnProperty(name)) {
    var ast = modules[name].ast,
      deps = modules[name].deps,
      params = ast.params && ast.params.map(function (p) { return p.name })

    if (!params) {
      bar.tick()
      continue
    }
    var renames = []
    // build ast of dependency require()s
    var depsAst = deps.map(function (dep, i) {
      if (!params[i]) params[i] = '__' + i
      var newName = 'unknown'
      // rename variables according to their module names
      if (mapping[dep.value]) {
        newName = variableNameFor(dep.value, mapping)
        renames.push({ idx: dep.range[0], to: newName })
      }
      else if (/^hbs!templates\//.test(dep.value)) {
        newName = 'template' + dep.value.split('/').pop()
        renames.push({ idx: dep.range[0], to: newName })
      }
      var range = [ dep.range[0] - 1, dep.range[1] + 1 ]
      return {
        type: 'VariableDeclaration',
        kind: 'var',
        range: range,
        declarations: [ {
          type: 'VariableDeclarator',
          id: merge($.id(params[i]), { range: dep.range }),
          range: range,
          init: {
            type: 'CallExpression',
            callee: $.id('require'),
            range: range,
            arguments: [ merge(dep, {
              trailingComments: [ {
                type: 'Block',
                value: ' ' + (dep.value in mapping ? mapping[dep.value] : 'Unknown module')
              } ]
            }) ]
          }
        } ]
      }
    })

    // move dependencies from the define() call
    // to the factory body
    ast.body.body = depsAst.concat(ast.body.body)
    ast.params = [
      $.id('require'),
      $.id('exports'),
      $.id('module')
    ]

    var returnVar = findReturnVar(ast.body)
    if (returnVar) {
      renames.push({
        idx: returnVar.range[0],
        to: variableNameFor(name, mapping)
      })
    }

    // wrap the ast in a Program node so esrefactor accepts it
    var fullAst = $.largeRange({
      type: 'Program',
      body: [ $.largeRange({
        type: 'ExpressionStatement',
        expression: ast
      }) ]
    })

    processRenames(fullAst, renames)
    bar.tick()
  }

  return modules
}

function getDependents(modules, name) {
  var dependents = []
  function isDep(d) {
    return d.value === name
  }
  for (var i in modules) if (modules.hasOwnProperty(i)) {
    if (modules[i].deps.some(isDep)) {
      dependents.push(i)
    }
  }
  return dependents
}

function findMemberExpressionName(ast) {
  var body = ast.body
  for (var i = 0, l = body.length; i < l; i++) {
    if (body[i].type === 'ExpressionStatement' &&
        body[i].expression.type === 'AssignmentExpression' &&
        body[i].expression.left.type === 'MemberExpression' &&
        body[i].expression.left.object.type === 'Identifier') {
      return body[i].expression.left.property
    }
  }
}
function addMappingForUnknownModules(modules, mapping) {
  for (var orig in mapping) {
    if (mapping[orig] === 'plug/server/socketReceiver') {
      // websocket event receiver modules don't export anything,
      // so they cannot be identified individually by plug-modules.
      // however, we have accesss to their full source here, so
      // we can extract them anyway!
      // socket event receivers set properties on a shared object,
      // which will actually be require()d by plug.dj source code,
      // and which can also be identified by plug-modules. here, we
      // can find all modules that depend on socketReceiver, and find
      // the relevant assignments.
      getDependents(modules, orig).forEach(function (name) {
        var prop = findMemberExpressionName(modules[name].ast.body)
        if (prop) {
          // some of these modules have multiple event receivers, so we
          // rename them to be a bit more clear.
          var niceName = {
            // contains a bunch of booth/wait list moderation events
            modAddDJ: 'plug/server/socket/modBooth',
            // contains subscription, XP, and PP events
            earn: 'plug/server/socket/currency',
            // contains multiple events for updates to the current room
            roomNameUpdate: 'plug/server/socket/roomUpdate',
            // this is actually the websocket manager module,
            // and it sets the window._gws property to undefined.
            // it really is just a false positive but we can abuse
            // it to get the proper module, anyway.
            // TODO detect this in a less stupid way
            _gws: 'plug/server/socket'
          }[prop.name] || 'plug/server/socket/' + prop.name
          mapping[name] = niceName
        }
      })
    }
    else if (mapping[orig] === 'plug/util/API') {
      getDependents(modules, orig).forEach(function (name) {
        var prop = findMemberExpressionName(modules[name].ast.body)
        if (prop) {
          var niceName = {
            getAdmins: 'admins',
            getAmbassadors: 'ambassadors',
            getAudience: 'audience',
            getBannedUsers: 'bannedUsers',
            getDJ: 'dj',
            getHistory: 'history',
            getHost: 'host',
            getMedia: 'media',
            getNextMedia: 'nextMedia',
            getScore: 'score',
            getStaff: 'staff',
            getTimeElapsed: 'playTime',
            getUser: 'users',
            getWaitList: 'waitlist',
            moderateForceSkip: 'moderator',
            sendChat: 'chat',
            setVolume: 'volume'
          }[prop.name] || prop.name
          mapping[name] = 'plug/util/api/' + niceName
        }
      })
    }
  }
}

function processRenames(ast, renames) {
  var renaming = new esrefactor.Context(ast)
  renames.forEach(function (r) {
    var id = renaming.identify(r.idx)
    if (id) {
      // rename manually.
      // esrefactor renames things "in-place" in the source code,
      // which means that you have to parse the source again every
      // time you rename a variable. Since we don't need to retain
      // formatting (it's minified code at this point, after all)
      // we can manually rename all variables at once without ever
      // parsing the source again.
      if (id.identifier) id.identifier.name = r.to
      if (id.declaration) id.declaration.name = r.to
      id.references.forEach(function (node) { node.name = r.to })
    }
  })
  return ast
}

function extract(modules, mapping) {
  var moduleNames = Object.keys(modules)
  var bar = progress('extracting files...', moduleNames.length)
  return Promise.each(moduleNames, function (name) {
    var ast = {
      type: 'Program',
      body: [ $.statement({
        type: 'CallExpression',
        callee: $.id('define'),
        arguments: [
          merge($.literal(name), {
            trailingComments: [ {
              type: 'Block',
              value: ' ' + (name in mapping ? mapping[name] : 'Unknown module')
            } ]
          }),
          modules[name].ast
        ]
      }) ]
    }
    return outputFile(name, mapping, escodegen.generate(ast, codegenOptions))
      .tap(bar.tick.bind(bar))
  }).return(modules)
}

function outputFile(name, mapping, beauty) {
  var file = path.join(program.out, name + '.js')
  return mkdirp(path.dirname(file))
    .then(function () {
      return fs.writeFileAsync(file, beauty)
    })
    .then(function () {
      // set up symlinks from nicer paths
      if (mapping[name] && mapping[name].indexOf('plug/') === 0) {
        var niceFile = path.join(program.out, mapping[name] + '.js')
        return makeLink(file, niceFile)
      }
    })
}

function makeLink(file, niceFile) {
  // cheaty use of path.relative to find link target path
  var linkTarget = path.relative('/' + path.dirname(niceFile), '/' + file)
  return mkdirp(path.dirname(niceFile))
    .then(function () { return fs.symlinkAsync(linkTarget, niceFile) })
}

function run(mapping, str) {
  var modules = parseModules(str)
  console.log('found', Object.keys(modules).length, 'modules.')
  modules = cleanModules(modules)
  addMappingForUnknownModules(modules, mapping)
  modules = remapModuleNames(modules, mapping)
  extract(modules, mapping)
    .tap(function () {
      return program.saveSource &&
        fs.writeFileAsync(path.join(program.out, 'source.js'), str)
    })
    .tap(function () {
      return program.saveMapping &&
        fs.writeFileAsync(path.join(program.out, 'mapping.json'),
                          JSON.stringify(mapping, null, 2))
    })
    .then(function () {
      return outputFile('version', {}, 'window._v = \'' + _v + '\';')
    })
    .then(function () { console.log('v' + _v + ' done') })
}

var mappingString
if (program.mapping) {
  mappingString = fs.readFileAsync(program.mapping, 'utf-8')
}
else {
  process.stdout.write('logging in to create mapping...')
  mappingString = plugLogin(requestOpts)
    .then(function (result) {
      console.log('  logged in to plug.dj')
      process.stdout.write('generating mapping...')
      return require('./lib/create-mapping')(result.jar)
    })
}

mappingString
  .then(JSON.parse)
  .then(function (result) {
    var mapping = result.mapping
    var sourceFile = result.appUrl
    // global!
    _v = result.version

    return Promise.props({
      mapping: mapping,
      src: /^https?:/.test(sourceFile)? fetchAppFile(sourceFile)
           : /* otherwise */            fs.readFileAsync(sourceFile, 'utf-8')
    })
  })
  .then(function (o) {
    return run(o.mapping, o.src)
  })
  .catch(function (e) { throw e })
<|endoftext|>


<commit_before>'use strict';

var transpiler = require('6to5-core');
var Filter     = require('broccoli-filter');

function TranspilerFilter(inputTree, options) {
  if (!(this instanceof TranspilerFilter)) {
    return new TranspilerFilter(inputTree, options);
  }

  this.inputTree = inputTree;
  this.options = options || {};
}

TranspilerFilter.prototype = Object.create(Filter.prototype);
TranspilerFilter.prototype.constructor = TranspilerFilter;

TranspilerFilter.prototype.extensions = ['js'];
TranspilerFilter.prototype.targetExtension = 'js';

TranspilerFilter.prototype.processString = function (string, relativePath) {
  var opts = this.copyOptions();

  opts.filename = opts.sourceMapName = opts.sourceFileName = relativePath;

  return transpiler.transform(string, opts).code;
};

TranspilerFilter.prototype.copyOptions = function() {
  return JSON.parse(JSON.stringify(this.options));
};

module.exports = TranspilerFilter;
<commit_msg>improve transpiler name (for logging/traces)<commit_after>'use strict';

var transpiler = require('6to5-core');
var Filter     = require('broccoli-filter');

function SixToFive(inputTree, options) {
  if (!(this instanceof SixToFive)) {
    return new SixToFive(inputTree, options);
  }

  this.inputTree = inputTree;
  this.options = options || {};
}

SixToFive.prototype = Object.create(Filter.prototype);
SixToFive.prototype.constructor = SixToFive;

SixToFive.prototype.extensions = ['js'];
SixToFive.prototype.targetExtension = 'js';

SixToFive.prototype.processString = function (string, relativePath) {
  var opts = this.copyOptions();

  opts.filename = opts.sourceMapName = opts.sourceFileName = relativePath;

  return transpiler.transform(string, opts).code;
};

SixToFive.prototype.copyOptions = function() {
  return JSON.parse(JSON.stringify(this.options));
};

module.exports = SixToFive;
<|endoftext|>


<commit_before>var when = require('when');
var whenGuard = require('when/guard');
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');

var PH = require('./progress-handlers');

var DEV = "DEVELOPER";
var PATHSEP = "|";
var CURRENT = "./";

function formatPath(pathstring, sep) {
  return path.join(CURRENT, pathstring).split(path.sep).join(sep || PATHSEP);
}

function isLastModifiedError(err) {
  var message = err && (err.message || err.originalError && err.originalError.message);
  return typeof message === "string" && (message.indexOf('Validation Error: LastModifedTime') === 0);
}

function aggregate(conf) {
  return function(filespecs, options, progressCallback) {
    var progress = PH.createLogger(progressCallback);
    var complete = PH.createCompleteHandler(progress);
    var step = conf.step(options, progress, complete).bind(this);
    var preprocess = conf.preprocess ? conf.preprocess(filespecs, options, progress).bind(this) : function() { return filespecs; };
    return this.client.getPackageMetadata({
      applicationKey: this.appKey
    }, {
      scope: DEV
    }).then(preprocess).then(function(filespecs) {
      return when.all(filespecs.map(whenGuard(whenGuard.n(process.env.MOZU_APPDEV_UTILS_CONCURRENCY || 16), step)));
    }).catch(function(e) {
      console.error(require('util').inspect(e));
    })
  }
}

function createClient(context, config) {
  config.context = context;
  config.plugins = config.plugins || [];
  config.plugins.push(require('mozu-node-sdk/plugins/fiddler-proxy'));
  return require('mozu-node-sdk/clients/platform/application')(config);
}

function walkMetadataTrees(trees) {
  return trees.reduce(function(files, tree) {
    return files.concat(tree.files).concat(tree.subFolders.length === 0 ? [] : walkMetadataTrees(tree.subFolders));
  }, []);
}

// legacy methods to ensure synchronousness
function getChecksum(fileText) {
  var hash = crypto.createHash('md5');
  hash.update(fileText);
  return hash.digest('hex');
}

var methods = {
  uploadFile: function(filepath, options, body, mtime) {
    if (body && typeof body === "string") {
      body = new Buffer(body, 'utf8');
    }
    var config = {
      applicationKey: this.appKey,
      filepath: formatPath(filepath)
    };
    if (options.noclobber) {
      config.lastModifiedTime = mtime || fs.statSync(filepath).mtime.toISOString();
    }
    return this.client.upsertPackageFile(config, {
      scope: DEV,
      body: body || fs.readFileSync(filepath)
    });
  },
  uploadFiles: aggregate({
    step: function(options, progress, complete) {
      return function(spec) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.BEFORE_UPLOAD, spec);
        var operation = this.uploadFile(spec.path || spec, spec.options || options, spec.body, spec.mtime).then(complete);
        if (options.noclobber) {
          return operation.catch(function(err) {
            if (isLastModifiedError(err)) {
              progress(PH.EventPhases.BEFORE, PH.EventTypes.REJECTED, {
                path: spec.path || spec,
                sizeInBytes: 0,
                type: ''
              }, 'Developer Center has a newer copy. Set the option `noclobber` to false to override.');
              return err;
            } else {
              throw err;
            }
          });
        } else {
          return operation;
        }
      }
    },
    preprocess: function(filespecs, options, progress) {

      function onlyModified(tree) {
        var pathToChecksum = walkMetadataTrees([tree]).reduce(function(memo, filespec) {
          memo[path.normalize(filespec.path)] = filespec.checkSum;
          return memo;
        }, {});
        return function(modifiedFiles, filespec) {
          var p = filespec.path || filespec;
          var fileContents = fs.readFileSync(p);
          var isSame = pathToChecksum[path.normalize(p)] === getChecksum(fileContents);
          if (isSame) {
            progress(PH.EventPhases.BEFORE, PH.EventTypes.OMITTED, filespec, 'Developer Center has an identical file. Set the option `ignoreChecksum` to true to override.');
          } else {
            // we've already read this file from the file system, so let's
            // pass the contents to uploadFile
            filespec.body = fileContents;
            filespec.mtime = fs.statSync(p).mtime.toISOString();
            modifiedFiles.push(filespec);
          }
          return modifiedFiles;
        }
      }

      return function(metadata) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.PREPROCESS, metadata);
        return options.ignoreChecksum ? filespecs : filespecs.reduce(onlyModified(metadata), []);
      };

    }
  }),
  deleteFile: function(filepath) {
    return this.client.deletePackageFile({
      applicationKey: this.appKey,
      filepath: formatPath(filepath)
    }, {
      scope: DEV
    }).then(function(r) {
      return {
        path: filepath
      };
    })
  },
  deleteFiles: aggregate({
    step: function(options, progress, complete) {
      return function(spec) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.BEFORE_DELETE, spec);
        return this.deleteFile(spec.path || spec).then(complete);
      }
    },
    preprocess: function(filespecs, options, progress) {
      return function(metadata) {
        var files = walkMetadataTrees([metadata]).reduce(function(memo, filespec) {
          memo[path.normalize(filespec.path || filespec)] = filespec;
          return memo;
        }, {});
        return filespecs.filter(function(spec) {
          var exists = !!files[path.normalize(spec.path || spec)]
          if (!exists) {
            progress(PH.EventPhases.BEFORE, PH.EventTypes.OMITTED, spec, "the file does not exist in Developer Center and therefore cannot be deleted.");
          }
          return exists;
        });
      }
    }
  }),
  deleteAllFiles: function(options, progress) {
    return this.client.getPackageMetadata({
      applicationKey: this.appKey
    }, {
      scope: DEV
    }).then(function(metadata) {
      return this.deleteFiles(walkMetadataTrees([metadata]), options, progress);
    }.bind(this));
  },
  renameFile: function(filepath, destpath, options) {
    return this.client.renamePackageFile({
      applicationKey: this.appKey,
      oldFullPath: formatPath(filepath),
      newFullPath: formatPath(destpath)
    }, {
      scope: DEV
    }).then(function(r) {
      return {
        oldPath: formatPath(filepath, '/'),
        newPath: r.path
      }
    });
  },
  renameFiles: aggregate({
    step: function(options, progress, complete) {
      return function(spec) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.BEFORE_RENAME, spec);
        return this.renameFile(spec.oldFullPath, spec.newFullPath, options).then(complete);
      }
    }
  })
}

module.exports = function(appKey, context, extraConfig) {
  return Object.create(methods, {
    appKey: {
      enumerable: true,
      configurable: false,
      writable: false,
      value: appKey,
    },
    client: {
      enumerable: true,
      configurable: true,
      writable: true,
      value: createClient(context, extraConfig || {})
    }
  });
};<commit_msg>adding better timeout for large file uploads<commit_after>var when = require('when');
var whenGuard = require('when/guard');
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');

var PH = require('./progress-handlers');

var DEV = "DEVELOPER";
var PATHSEP = "|";
var CURRENT = "./";

function formatPath(pathstring, sep) {
  return path.join(CURRENT, pathstring).split(path.sep).join(sep || PATHSEP);
}

function isLastModifiedError(err) {
  var message = err && (err.message || err.originalError && err.originalError.message);
  return typeof message === "string" && (message.indexOf('Validation Error: LastModifedTime') === 0);
}

function aggregate(conf) {
  return function(filespecs, options, progressCallback) {
    var progress = PH.createLogger(progressCallback);
    var complete = PH.createCompleteHandler(progress);
    var step = conf.step(options, progress, complete).bind(this);
    var preprocess = conf.preprocess ? conf.preprocess(filespecs, options, progress).bind(this) : function() { return filespecs; };
    return this.client.getPackageMetadata({
      applicationKey: this.appKey
    }, {
      scope: DEV
    }).then(preprocess).then(function(filespecs) {
      return when.all(filespecs.map(whenGuard(whenGuard.n(process.env.MOZU_APPDEV_UTILS_CONCURRENCY || 16), step)));
    }).catch(function(e) {
      console.error(require('util').inspect(e));
    })
  }
}

function createClient(context, config) {
  config.context = context;
  config.plugins = config.plugins || [];
  config.plugins.push(require('mozu-node-sdk/plugins/fiddler-proxy'));
  config.defaultRequestOptions = {
    timeout: process.env.MOZU_APPDEV_UTILS_TIMEOUT_SECONDS ? Number(process.env.MOZU_APPDEV_UTILS_TIMEOUT_SECONDS) * 1000 : 60000
  };
  return require('mozu-node-sdk/clients/platform/application')(config);
}

function walkMetadataTrees(trees) {
  return trees.reduce(function(files, tree) {
    return files.concat(tree.files).concat(tree.subFolders.length === 0 ? [] : walkMetadataTrees(tree.subFolders));
  }, []);
}

// legacy methods to ensure synchronousness
function getChecksum(fileText) {
  var hash = crypto.createHash('md5');
  hash.update(fileText);
  return hash.digest('hex');
}

var methods = {
  uploadFile: function(filepath, options, body, mtime) {
    if (body && typeof body === "string") {
      body = new Buffer(body, 'utf8');
    }
    var config = {
      applicationKey: this.appKey,
      filepath: formatPath(filepath)
    };
    if (options.noclobber) {
      config.lastModifiedTime = mtime || fs.statSync(filepath).mtime.toISOString();
    }
    return this.client.upsertPackageFile(config, {
      scope: DEV,
      body: body || fs.readFileSync(filepath)
    });
  },
  uploadFiles: aggregate({
    step: function(options, progress, complete) {
      return function(spec) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.BEFORE_UPLOAD, spec);
        var operation = this.uploadFile(spec.path || spec, spec.options || options, spec.body, spec.mtime).then(complete);
        if (options.noclobber) {
          return operation.catch(function(err) {
            if (isLastModifiedError(err)) {
              progress(PH.EventPhases.BEFORE, PH.EventTypes.REJECTED, {
                path: spec.path || spec,
                sizeInBytes: 0,
                type: ''
              }, 'Developer Center has a newer copy. Set the option `noclobber` to false to override.');
              return err;
            } else {
              throw err;
            }
          });
        } else {
          return operation;
        }
      }
    },
    preprocess: function(filespecs, options, progress) {

      function onlyModified(tree) {
        var pathToChecksum = walkMetadataTrees([tree]).reduce(function(memo, filespec) {
          memo[path.normalize(filespec.path)] = filespec.checkSum;
          return memo;
        }, {});
        return function(modifiedFiles, filespec) {
          var p = filespec.path || filespec;
          var fileContents = fs.readFileSync(p);
          var isSame = pathToChecksum[path.normalize(p)] === getChecksum(fileContents);
          if (isSame) {
            progress(PH.EventPhases.BEFORE, PH.EventTypes.OMITTED, filespec, 'Developer Center has an identical file. Set the option `ignoreChecksum` to true to override.');
          } else {
            // we've already read this file from the file system, so let's
            // pass the contents to uploadFile
            filespec.body = fileContents;
            filespec.mtime = fs.statSync(p).mtime.toISOString();
            modifiedFiles.push(filespec);
          }
          return modifiedFiles;
        }
      }

      return function(metadata) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.PREPROCESS, metadata);
        return options.ignoreChecksum ? filespecs : filespecs.reduce(onlyModified(metadata), []);
      };

    }
  }),
  deleteFile: function(filepath) {
    return this.client.deletePackageFile({
      applicationKey: this.appKey,
      filepath: formatPath(filepath)
    }, {
      scope: DEV
    }).then(function(r) {
      return {
        path: filepath
      };
    })
  },
  deleteFiles: aggregate({
    step: function(options, progress, complete) {
      return function(spec) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.BEFORE_DELETE, spec);
        return this.deleteFile(spec.path || spec).then(complete);
      }
    },
    preprocess: function(filespecs, options, progress) {
      return function(metadata) {
        var files = walkMetadataTrees([metadata]).reduce(function(memo, filespec) {
          memo[path.normalize(filespec.path || filespec)] = filespec;
          return memo;
        }, {});
        return filespecs.filter(function(spec) {
          var exists = !!files[path.normalize(spec.path || spec)]
          if (!exists) {
            progress(PH.EventPhases.BEFORE, PH.EventTypes.OMITTED, spec, "the file does not exist in Developer Center and therefore cannot be deleted.");
          }
          return exists;
        });
      }
    }
  }),
  deleteAllFiles: function(options, progress) {
    return this.client.getPackageMetadata({
      applicationKey: this.appKey
    }, {
      scope: DEV
    }).then(function(metadata) {
      return this.deleteFiles(walkMetadataTrees([metadata]), options, progress);
    }.bind(this));
  },
  renameFile: function(filepath, destpath, options) {
    return this.client.renamePackageFile({
      applicationKey: this.appKey,
      oldFullPath: formatPath(filepath),
      newFullPath: formatPath(destpath)
    }, {
      scope: DEV
    }).then(function(r) {
      return {
        oldPath: formatPath(filepath, '/'),
        newPath: r.path
      }
    });
  },
  renameFiles: aggregate({
    step: function(options, progress, complete) {
      return function(spec) {
        progress(PH.EventPhases.BEFORE, PH.EventTypes.BEFORE_RENAME, spec);
        return this.renameFile(spec.oldFullPath, spec.newFullPath, options).then(complete);
      }
    }
  })
}

module.exports = function(appKey, context, extraConfig) {
  return Object.create(methods, {
    appKey: {
      enumerable: true,
      configurable: false,
      writable: false,
      value: appKey,
    },
    client: {
      enumerable: true,
      configurable: true,
      writable: true,
      value: createClient(context, extraConfig || {})
    }
  });
};<|endoftext|>


<commit_before>// Override equals to convert functions to message and execute them as tests()
function equals(actual, expected, message) {
	if (typeof actual === 'function') {
		if (!message) {
			message = actual.toString().match(
				/^\s*function[^\{]*\{([\s\S]*)\}\s*$/)[1]
					.replace(/    /g, '')
					.replace(/^\s+|\s+$/g, '');
			if (/^return /.test(message)) {
				message = message
					.replace(/^return /, '')
					.replace(/;$/, '');
			}
		}
		actual = actual();
	}
	// Let's be strict
	return strictEqual(actual, expected, message);
}

function test(testName, expected) {
	return QUnit.test(testName, function() {
		var project = new Project();
		expected();
		project.remove();
	});
}

function compareNumbers(number1, number2, message) {
	if (number1 !== 0)
		number1 = Math.round(number1 * 100) / 100;
	if (number2 !== 0)
		number2 = Math.round(number2 * 100) / 100;
	equals(number1, number2, message);
}

function comparePoints(point1, point2, message) {
	compareNumbers(point1.x, point2.x,
			(message || '') + ' x');
	compareNumbers(point1.y, point2.y,
			(message || '') + ' y');
}

function compareRectangles(rect1, rect2, message) {
	compareNumbers(rect1.x, rect2.x,
			(message || '') + ' x');
	compareNumbers(rect1.y, rect2.y,
			(message || '') + ' y');
	compareNumbers(rect1.width, rect2.width,
			(message || '') + ' width');
	compareNumbers(rect1.height, rect2.height,
			(message || '') + ' height');
}

function compareRGBColors(color1, color2, message) {
	color1 = new RGBColor(color1);
	color2 = new RGBColor(color2);

	compareNumbers(color1.red, color2.red,
			(message || '') + ' red');
	compareNumbers(color1.green, color2.green,
			(message || '') + ' green');
	compareNumbers(color1.blue, color2.blue,
			(message || '') + ' blue');
	compareNumbers(color1.alpha, color2.alpha,
			(message || '') + ' alpha');
}

function compareHSBColors(color1, color2, message) {
	color1 = new HSBColor(color1);
	color2 = new HSBColor(color2);

	compareNumbers(color1.hue, color2.hue,
			(message || '') + ' hue');
	compareNumbers(color1.saturation, color2.saturation,
			(message || '') + ' saturation');
	compareNumbers(color1.brightness, color2.brightness,
			(message || '') + ' brightness');
	compareNumbers(color1.alpha, color2.alpha,
			(message || '') + ' alpha');
}

function compareGrayColors(color1, color2, message) {
	color1 = new GrayColor(color1);
	color2 = new GrayColor(color2);

	compareNumbers(color1.gray, color2.gray,
			(message || '') + ' gray');
}

function compareGradientColors(color1, color2) {
	Base.each(['origin', 'destination', 'hilite'], function(key) {
		equals(color1[key].toString(), color2[key].toString(),
			'color1[' + key + '].toString() == color2[' + key + '].toString()');
	});
	equals(function() {
		return color1.gradient.equals(color2.gradient);
	}, true);
}

function cloneAndCompare(item) {
	var copy = item.clone();
	compareItems(item, copy);
	// Remove the cloned item to restore the document:
	copy.remove();
}

function compareItems(item, item2) {
	equals(function() {
		return item != item2;
	}, true);

	var itemProperties = ['opacity', 'locked', 'visible', 'blendMode', 'name',
	 		'closed', 'selected'];
	Base.each(itemProperties, function(key) {
		equals(function() {
			return item[key] == item2[key];
		}, true, 'item[\'' + key + '\'] == item2[\'' + key + '\']');
	});

	equals(function() {
		return item.id != item2.id;
	}, true);

	if (item._matrix) {
		equals(function() {
			return item._matrix != item2._matrix;
		}, true);
		equals(item._matrix.toString(), item2._matrix.toString(),
				'item._matrix.toString() == item2._matrix.toString()');
	}

	if (item2.segments) {
		equals(item.segments.toString(), item2.segments.toString(),
				'item.segments.toString() == item2.segments.toString()');
	}

	// Path specific
	if (item instanceof PathItem) {
		equals(function() {
			return item._clockwise == item2._clockwise;
		}, true);
	}

	// Group specific
	if (item instanceof Group) {
		equals(function() {
			return item._clipped == item2._clipped;
		}, true);
	}

	// Layer specific
	if (item instanceof Layer) {
		equals(function() {
			return item.project == item2.project;
		}, true);
	}

	// PlacedSymbol specific
	if (item instanceof PlacedSymbol) {
		equals(function() {
			return item.symbol == item2.symbol;
		}, true);
	}

	// TODO: Raster specific

	// TextItem specific:
	if (item instanceof TextItem) {
		equals(item.content, item2.content, 'item.content == item2.content');
		var characterStyleKeys = ['fontSize', 'font'];
		Base.each(characterStyleKeys, function(key) {
			equals(function() {
				return item2.characterStyle[key];
			}, item.characterStyle[key], 'item.characterStyle[\'' + key
					+ '\'] == item2.characterStyle[\'' + key + '\']');
		});
		var paragraphStyleKeys = ['justification'];
		Base.each(paragraphStyleKeys, function(key) {
			equals(function() {
				return item2.paragraphStyle[key];
			}, item.paragraphStyle[key], 'item.paragraphStyle[\'' + key
					+ '\'] == item2.paragraphStyle[\'' + key + '\']');
		});
	}

	// PointText specific:
	if (item instanceof PointText) {
		equals(item.point.toString(), item2.point.toString());
	}

	if (item._style) {
		// Path Style
		if (item.fillColor) {
			// The fillColor should not point to the same color object:
			equals(function() {
				return item.fillColor != item2.fillColor;
			}, true, 'The fillColor should not point to the same color object:');
			if (item.fillColor instanceof GradientColor) {
				// TODO!
			} else {
				equals(item.fillColor.toString(), item2.fillColor.toString());
			}
		}

		if (item.strokeColor) {
			equals(function() {
				return item.strokeColor != item2.strokeColor;
			}, true, 'The strokeColor should not point to the same color object:');
			if (item.strokeColor instanceof GradientColor) {
				// TODO
			} else {
				equals(item.strokeColor.toString(), item2.strokeColor.toString());
			}
		}

		Base.each(['strokeCap', 'strokeJoin', 'dashOffset', 'miterLimit',
		'strokeOverprint', 'fillOverprint'], function(key) {
			if (item[key]) {
				equals(function() {
					return item[key] == item2[key];
				}, true, 'item[\'' + key + '\'] == item2[\'' + key + '\']');
			}
		});

		if (item.dashArray) {
			equals(item.dashArray.toString(), item2.dashArray.toString(),
				'item.dashArray.toString(), item2.dashArray.toString()');
		}
	}

	// Check length of children and recursively compare them:
	if (item.children) {
		equals(function() {
			return item.children.length == item2.children.length;
		}, true);
		for (var i = 0, l = item.children.length; i < l; i++) {
			compareItems(item.children[i], item2.children[i]);
		}
	}
}<commit_msg>Tests: support comparing of GradientColor in compareItems helper function.<commit_after>// Override equals to convert functions to message and execute them as tests()
function equals(actual, expected, message) {
	if (typeof actual === 'function') {
		if (!message) {
			message = actual.toString().match(
				/^\s*function[^\{]*\{([\s\S]*)\}\s*$/)[1]
					.replace(/    /g, '')
					.replace(/^\s+|\s+$/g, '');
			if (/^return /.test(message)) {
				message = message
					.replace(/^return /, '')
					.replace(/;$/, '');
			}
		}
		actual = actual();
	}
	// Let's be strict
	return strictEqual(actual, expected, message);
}

function test(testName, expected) {
	return QUnit.test(testName, function() {
		var project = new Project();
		expected();
		project.remove();
	});
}

function compareNumbers(number1, number2, message) {
	if (number1 !== 0)
		number1 = Math.round(number1 * 100) / 100;
	if (number2 !== 0)
		number2 = Math.round(number2 * 100) / 100;
	equals(number1, number2, message);
}

function comparePoints(point1, point2, message) {
	compareNumbers(point1.x, point2.x,
			(message || '') + ' x');
	compareNumbers(point1.y, point2.y,
			(message || '') + ' y');
}

function compareRectangles(rect1, rect2, message) {
	compareNumbers(rect1.x, rect2.x,
			(message || '') + ' x');
	compareNumbers(rect1.y, rect2.y,
			(message || '') + ' y');
	compareNumbers(rect1.width, rect2.width,
			(message || '') + ' width');
	compareNumbers(rect1.height, rect2.height,
			(message || '') + ' height');
}

function compareRGBColors(color1, color2, message) {
	color1 = new RGBColor(color1);
	color2 = new RGBColor(color2);

	compareNumbers(color1.red, color2.red,
			(message || '') + ' red');
	compareNumbers(color1.green, color2.green,
			(message || '') + ' green');
	compareNumbers(color1.blue, color2.blue,
			(message || '') + ' blue');
	compareNumbers(color1.alpha, color2.alpha,
			(message || '') + ' alpha');
}

function compareHSBColors(color1, color2, message) {
	color1 = new HSBColor(color1);
	color2 = new HSBColor(color2);

	compareNumbers(color1.hue, color2.hue,
			(message || '') + ' hue');
	compareNumbers(color1.saturation, color2.saturation,
			(message || '') + ' saturation');
	compareNumbers(color1.brightness, color2.brightness,
			(message || '') + ' brightness');
	compareNumbers(color1.alpha, color2.alpha,
			(message || '') + ' alpha');
}

function compareGrayColors(color1, color2, message) {
	color1 = new GrayColor(color1);
	color2 = new GrayColor(color2);

	compareNumbers(color1.gray, color2.gray,
			(message || '') + ' gray');
}

function compareGradientColors(color1, color2) {
	Base.each(['origin', 'destination', 'hilite'], function(key) {
		equals(color1[key].toString(), color2[key].toString(),
			'color1[' + key + '].toString() == color2[' + key + '].toString()');
	});
	equals(function() {
		return color1.gradient.equals(color2.gradient);
	}, true);
}

function cloneAndCompare(item) {
	var copy = item.clone();
	compareItems(item, copy);
	// Remove the cloned item to restore the document:
	copy.remove();
}

function compareItems(item, item2) {
	equals(function() {
		return item != item2;
	}, true);

	var itemProperties = ['opacity', 'locked', 'visible', 'blendMode', 'name',
	 		'closed', 'selected'];
	Base.each(itemProperties, function(key) {
		equals(function() {
			return item[key] == item2[key];
		}, true, 'item[\'' + key + '\'] == item2[\'' + key + '\']');
	});

	equals(function() {
		return item.id != item2.id;
	}, true);

	if (item._matrix) {
		equals(function() {
			return item._matrix != item2._matrix;
		}, true);
		equals(item._matrix.toString(), item2._matrix.toString(),
				'item._matrix.toString() == item2._matrix.toString()');
	}

	if (item2.segments) {
		equals(item.segments.toString(), item2.segments.toString(),
				'item.segments.toString() == item2.segments.toString()');
	}

	// Path specific
	if (item instanceof PathItem) {
		equals(function() {
			return item._clockwise == item2._clockwise;
		}, true);
	}

	// Group specific
	if (item instanceof Group) {
		equals(function() {
			return item._clipped == item2._clipped;
		}, true);
	}

	// Layer specific
	if (item instanceof Layer) {
		equals(function() {
			return item.project == item2.project;
		}, true);
	}

	// PlacedSymbol specific
	if (item instanceof PlacedSymbol) {
		equals(function() {
			return item.symbol == item2.symbol;
		}, true);
	}

	// TODO: Raster specific

	// TextItem specific:
	if (item instanceof TextItem) {
		equals(item.content, item2.content, 'item.content == item2.content');
		var characterStyleKeys = ['fontSize', 'font'];
		Base.each(characterStyleKeys, function(key) {
			equals(function() {
				return item2.characterStyle[key];
			}, item.characterStyle[key], 'item.characterStyle[\'' + key
					+ '\'] == item2.characterStyle[\'' + key + '\']');
		});
		var paragraphStyleKeys = ['justification'];
		Base.each(paragraphStyleKeys, function(key) {
			equals(function() {
				return item2.paragraphStyle[key];
			}, item.paragraphStyle[key], 'item.paragraphStyle[\'' + key
					+ '\'] == item2.paragraphStyle[\'' + key + '\']');
		});
	}

	// PointText specific:
	if (item instanceof PointText) {
		equals(item.point.toString(), item2.point.toString());
	}

	if (item._style) {
		// Path Style

		Base.each(['fillColor', 'strokeColor'], function(key) {
			if (item[key]) {
				// The fillColor should not point to the same color object:
				equals(function() {
					return item[key] != item2[key];
				}, true, 'The ' + key + ' should not point to the same color object:');
				if (item[key] instanceof GradientColor) {
					// TODO!
					equals(function() {
						return item[key].gradient == item2[key].gradient;
					}, true, 'The ' + key + '.gradient should point to the same object:');
					compareGradientColors(item[key], item2[key],
							'Compare item[' + key + '] and item2[' + key + ']');
				} else {
					equals(item[key].toString(), item2[key].toString(),
							'item[' + key + '] == item2[' + key + ']');
				}
			}
		});

		Base.each(['strokeCap', 'strokeJoin', 'dashOffset', 'miterLimit',
		'strokeOverprint', 'fillOverprint'], function(key) {
			if (item[key]) {
				equals(function() {
					return item[key] == item2[key];
				}, true, 'item[\'' + key + '\'] == item2[\'' + key + '\']');
			}
		});

		if (item.dashArray) {
			equals(item.dashArray.toString(), item2.dashArray.toString(),
				'item.dashArray.toString(), item2.dashArray.toString()');
		}
	}

	// Check length of children and recursively compare them:
	if (item.children) {
		equals(function() {
			return item.children.length == item2.children.length;
		}, true);
		for (var i = 0, l = item.children.length; i < l; i++) {
			compareItems(item.children[i], item2.children[i]);
		}
	}
}<|endoftext|>


<commit_before>/*
 * interns-test.js: Tests for Loggly interns utility module
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENSE
 *
 */

var path = require('path'),
    vows = require('vows'),
    assert = require('assert');
    helpers = require('./helper');

require.paths.unshift(path.join(__dirname, '..', 'lib'));

var winston = require('winston');

vows.describe('winton/logger').addBatch({
  "The winston logger": {
    "the logger() method": {
      topic: function () {
       return new (winston.Logger)({transports: {"Console": {level: "info"}}});
      },
      "should return a winston Logger": function (logger) {
        helpers.assertLogger(logger);
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({transports: {}}),
    "The logger should start with 0 transports": {
      topic: function(logger) {
        return logger;
      }
    },
    "should return 0": function(logger) {
      assert.equal(helpers.size(logger.transports), 0);
    },
    "the add() with an unsupported transport": {
      topic: function (logger) {
       try {
         return logger.add("unsupported", {});
        }
       catch(err) {
        return err;
       }
      },
      "should return an Error": function (err) {
       assert.instanceOf(err, Error);
      }
    },
    "the add() method with a supported method": {
      topic: function (logger) {
         logger.add("Console", {});
         return logger;
      },
      "should push a Console Transport onto transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertConsole(logger.transports.Console);
      },
      "and adding an additional method": {
        topic: function (logger) {
           logger.add("Riak", {});
           return logger;
        },
        "should be able to add multiple transports": function (logger) {
          assert.equal(helpers.size(logger.transports), 2);
          helpers.assertConsole(logger.transports.Console);
          helpers.assertRiak(logger.transports.Riak);
        }
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({transports: {Console: {}, Riak: {}}}),
    "The logger should start with 2 transports": {
      topic: function(logger) {
        return logger;
      }
    },
    "should return 2": function(logger) {
      assert.equal(helpers.size(logger.transports), 2);
    },
    "the remove() with an unadded transport": {
      topic: function (logger) {
       try {
         return logger.remove("Loggly");
        }
       catch(err) {
        return err;
       }
      },
      "should return an Error": function (err) {
       assert.instanceOf(err, Error);
      }
    },
    "the remove() method with an added transport": {
      topic: function (logger) {
         logger.remove("Console");
         return logger;
      },
      "should remove a Console Transport from transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertRiak(logger.transports.Riak);
      },
      "and removing an additional transport": {
        topic: function (logger) {
           logger.remove("Riak");
           return logger;
        },
        "should remove Riak Transport": function (logger) {
          assert.equal(helpers.size(logger.transports), 0);
        }
      }
    }
  }
}).export(module);<commit_msg>[test] Cleanup tests slightly<commit_after>/*
 * interns-test.js: Tests for Loggly interns utility module
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENSE
 *
 */

var path = require('path'),
    vows = require('vows'),
    assert = require('assert');
    helpers = require('./helper');

require.paths.unshift(path.join(__dirname, '..', 'lib'));

var winston = require('winston');

vows.describe('winton/logger').addBatch({
  "The winston logger": {
    "the logger() method": {
      topic: function () {
       return new (winston.Logger)({ transports: { Console: { level: "info" }}});
      },
      "should return a winston Logger": function (logger) {
        helpers.assertLogger(logger);
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({ transports: {} }),
    "should return 0": function(logger) {
      assert.equal(helpers.size(logger.transports), 0);
    },
    "the add() with an unsupported transport": {
      "should throw an error": function () {
        assert.throws(function () { logger.add('unsupported', {}) }, Error);
      }
    },
    "the add() method with a supported method": {
      topic: function (logger) {
         logger.add("Console", {});
         return logger;
      },
      "should push a Console Transport onto transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertConsole(logger.transports.Console);
      },
      "and adding an additional method": {
        topic: function (logger) {
           logger.add("Riak", {});
           return logger;
        },
        "should be able to add multiple transports": function (logger) {
          assert.equal(helpers.size(logger.transports), 2);
          helpers.assertConsole(logger.transports.Console);
          helpers.assertRiak(logger.transports.Riak);
        }
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({ transports: { Console: {}, Riak: {} } }),
    "should return 2": function(logger) {
      assert.equal(helpers.size(logger.transports), 2);
    },
    "the remove() with an unadded transport": {
      "should throw an Error": function (logger) {
       assert.throws(function () { logger.remove('loggly') }, Error);
      }
    },
    "the remove() method with an added transport": {
      topic: function (logger) {
         logger.remove("Console");
         return logger;
      },
      "should remove a Console Transport from transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertRiak(logger.transports.Riak);
      },
      "and removing an additional transport": {
        topic: function (logger) {
           logger.remove("Riak");
           return logger;
        },
        "should remove Riak Transport": function (logger) {
          assert.equal(helpers.size(logger.transports), 0);
        }
      }
    }
  }
}).export(module);<|endoftext|>


<commit_before>AWS_ACCESS_ID = '<AWS_ACCESS_ID>';
AWS_ACCESS_KEY = '<AWS_ACCESS_KEY>';
AWS_REGION = '<AWS_REGION>';

BASE_DOMAIN_NAME = '<DOMAIN_NAME>';
HOSTED_ZONE_ID = '<HOSTED_ZONE_ID>';

var util = require('util');
var aws = require('aws-sdk');
aws.config.update({accessKeyId: AWS_ACCESS_ID, secretAccessKey: AWS_ACCESS_KEY});
aws.config.update({region: AWS_REGION});

exports.handler = function(event, context) {
  var ec2 = new aws.EC2();
  var route53 = new aws.Route53();

  if (event.detail.state === 'running') {
    describeInstance(ec2, event.detail['instance-id'], function(err, instance) {
      if (err) {
        return context.fail(err);
      }
      domainNameFrom(instance, instance.InstanceId, context, function(err, FQDN) {
        if (err) {
          return context.fail(err);
        }
        addToRoute53(route53, FQDN, HOSTED_ZONE_ID, instance.PublicIpAddress, function(err) {
          if (err) {
            return context.fail(err);
          }
          return context.succeed('OK');
        });
      });
    });
  } else {
    ec2.describeInstances(function(err, result) {
      if (err) {
        context.fail(err);
        return;
      }
      result.Reservations.forEach(function(reservation) {
        reservation.Instances.forEach(function(instance) {
          if ((instance.InstanceId) == event.detail['instance-id']) {
            var id = instance.InstanceId;
            var ip = instance.PublicIpAddress;

            domainNameFrom(instance, id, context, function(name) {
              dnsRecordChange = dnsRecordChangeFrom(event, ip, name);
              route53.changeResourceRecordSets(dnsRecordChange, function(err, data) {
                if (err) {
                  context.fail(err);
                  return;
                }
                console.log('Change DNS record: ', JSON.stringify(dnsRecordChange));
                context.succeed('Changed DNS record');
              });
            });
          }
        });
      });
    });
  }
};

function describeInstance(ec2, instanceId, callback) {
  var params = {InstanceIds: [instanceId]};
  ec2.describeInstances(params, function(err, result) {
    if (err) {
      return callback(err, null);
    }
    result.Reservations.forEach(function(reservation) {
      reservation.Instances.forEach(function(instance) {
        if (instance.PublicIpAddress) {
          return callback(null, instance);
        }
        setTimeout(function() {
          console.log('Missing publicIP, try later...');
          describeInstance(ec2, instanceId, callback)
        }, 300);
      });
    });
  });
}

function addToRoute53(route53, FQDN, hostedZoneId, publicIp, callback) {
  hostedZoneRecord(route53, hostedZoneId, 'A', FQDN, function(err, resourceRecordSet) {
    if (err) {
      return callback(err);
    }
    var dnsRecordChange = {
      HostedZoneId: hostedZoneId,
      ChangeBatch: {
        Changes: [{
          Action: 'CREATE',
          ResourceRecordSet: {
            Name: FQDN,
            Type: 'A',
            ResourceRecords: [{Value: publicIp}],
            TTL: 60,
          }
        }]
      }
    };
    if (resourceRecordSet) {
      var previousIp = resourceRecordSet.ResourceRecords[0].Value;
      if (previousIp === publicIp) {
        console.log('Found A record for', FQDN, 'with current IP', publicIp, 'so nothing to do');
        return callback(null);
      }
      console.log('Found A record for', FQDN, 'with IP', previousIp, 'update to IP', publicIp);
      dnsRecordChange.ChangeBatch.Changes.unshift({
        Action: 'DELETE',
        ResourceRecordSet: {
          Name: FQDN,
          Type: 'A',
          ResourceRecords: [{Value: previousIp}],
          TTL: 60,
        }
      });
    } else {
      console.log('Missing A record for', FQDN, 'create with IP', publicIp);
    }
    route53.changeResourceRecordSets(dnsRecordChange, function(err, data) {
      if (err) {
        return callback(err);
      }
      return callback(null);
    });
  });
}

function hostedZoneRecord(route53, hostedZoneId, recordType, FQDN, callback) {
  FQDN = util.format('%s.', FQDN);
  var params = {
    HostedZoneId: hostedZoneId,
    MaxItems: '1',
    StartRecordName: FQDN,
    StartRecordType: recordType
  };
  route53.listResourceRecordSets(params, function(err, data) {
    if (err) {
      return callback(err);
    }
    var resourceRecordSet = data.ResourceRecordSets && data.ResourceRecordSets[0];
    if (resourceRecordSet && (resourceRecordSet.Name === FQDN)) {
      return callback(null, resourceRecordSet);
    }
    callback(null, null);
  });
}

function domainNameFrom(instance, id, context, callback) {
  var domainName = null;
  instance.Tags.forEach(function(tag) {
    if (tag.Key === 'Name') {
      domainName = util.format('%s.%s', tag.Value, BASE_DOMAIN_NAME);
    }
  });
  if (domainName) {
    return callback(null, domainName);
  }
  callback(util.format("Unable to find tag with key 'Name' in instance '%s'", id), null);
}

function dnsRecordChangeFrom(event, ip, name) {
  if (event.detail.state === 'stopping' || event.detail.state === 'shutting-down') {
    return deleteDnsRecord(ip, name);
  }
  return createDnsRecord(ip, name);
}

function deleteDnsRecord(ip, name) {
  return dnsRecord('DELETE', ip, name);
}

function createDnsRecord(ip, name) {
  return dnsRecord('CREATE', ip, name);
}

function dnsRecord(action, ip, name) {
  return {
    HostedZoneId: HOSTED_ZONE_ID,
    ChangeBatch: {
      Changes: [{
        Action: action,
        ResourceRecordSet: {
          Name: name,
          Type: 'A',
          ResourceRecords: [{Value: ip}],
          TTL: 600,
        }
      }]
    }
  };
}
<commit_msg>Remove from Route53 searching IP in Route53<commit_after>AWS_ACCESS_ID = '<AWS_ACCESS_ID>';
AWS_ACCESS_KEY = '<AWS_ACCESS_KEY>';
AWS_REGION = '<AWS_REGION>';

BASE_DOMAIN_NAME = '<DOMAIN_NAME>';
HOSTED_ZONE_ID = '<HOSTED_ZONE_ID>';

var util = require('util');
var aws = require('aws-sdk');
aws.config.update({accessKeyId: AWS_ACCESS_ID, secretAccessKey: AWS_ACCESS_KEY});
aws.config.update({region: AWS_REGION});

exports.handler = function(event, context) {
  var ec2 = new aws.EC2();
  var route53 = new aws.Route53();

  if (event.detail.state === 'running') {
    describeInstance(ec2, event.detail['instance-id'], function(err, instance) {
      if (err) {
        return context.fail(err);
      }
      domainNameFrom(instance, instance.InstanceId, context, function(err, FQDN) {
        if (err) {
          return context.fail(err);
        }
        addOrUpdateInRoute53(route53, FQDN, HOSTED_ZONE_ID, instance.PublicIpAddress, function(err) {
          if (err) {
            return context.fail(err);
          }
          return context.succeed('OK');
        });
      });
    });
  }
  if (event.detail.state === 'shutting-down' || event.detail.state === 'stopping') {
    ec2.describeInstances(function(err, result) {
      if (err) {
        context.fail(err);
        return;
      }
      result.Reservations.forEach(function(reservation) {
        reservation.Instances.forEach(function(instance) {
          domainNameFrom(instance, instance.InstanceId, context, function(err, FQDN) {
            if (err) {
              return context.fail(err);
            }
            removeFromRoute53(route53, FQDN, HOSTED_ZONE_ID, function(err) {
              if (err) {
                return context.fail(err);
              }
              return context.succeed('OK');
            });
          });
        });
      });
    });
  }
};

function describeInstance(ec2, instanceId, callback) {
  var params = {InstanceIds: [instanceId]};
  ec2.describeInstances(params, function(err, result) {
    if (err) {
      return callback(err, null);
    }
    result.Reservations.forEach(function(reservation) {
      reservation.Instances.forEach(function(instance) {
        if (instance.PublicIpAddress) {
          return callback(null, instance);
        }
        setTimeout(function() {
          console.log('Missing publicIP, try later...');
          describeInstance(ec2, instanceId, callback)
        }, 300);
      });
    });
  });
}

function addOrUpdateInRoute53(route53, FQDN, hostedZoneId, publicIp, callback) {
  hostedZoneRecord(route53, hostedZoneId, 'A', FQDN, function(err, resourceRecordSet) {
    if (err) {
      return callback(err);
    }
    var dnsRecordChange = {
      HostedZoneId: hostedZoneId,
      ChangeBatch: {
        Changes: [{
          Action: 'CREATE',
          ResourceRecordSet: {
            Name: FQDN,
            Type: 'A',
            ResourceRecords: [{Value: publicIp}],
            TTL: 60,
          }
        }]
      }
    };
    if (resourceRecordSet) {
      var previousIp = resourceRecordSet.ResourceRecords[0].Value;
      if (previousIp === publicIp) {
        console.log('Found A record for', FQDN, 'with current IP', publicIp, 'so nothing to do');
        return callback(null);
      }
      console.log('Found A record for', FQDN, 'with IP', previousIp, 'update to IP', publicIp);
      dnsRecordChange.ChangeBatch.Changes.unshift({
        Action: 'DELETE',
        ResourceRecordSet: {
          Name: FQDN,
          Type: 'A',
          ResourceRecords: [{Value: previousIp}],
          TTL: 60,
        }
      });
    } else {
      console.log('Missing A record for', FQDN, 'create with IP', publicIp);
    }
    route53.changeResourceRecordSets(dnsRecordChange, function(err, data) {
      if (err) {
        return callback(err);
      }
      return callback(null);
    });
  });
}

function removeFromRoute53(route53, FQDN, hostedZoneId, callback) {
  hostedZoneRecord(route53, hostedZoneId, 'A', FQDN, function(err, resourceRecordSet) {
    if (err) {
      return callback(err);
    }
    if (!resourceRecordSet) {
      console.log('Not found A record for', FQDN, 'so nothing to do');
      return callback(null);
    }
    var dnsRecordChange = {
      HostedZoneId: hostedZoneId,
      ChangeBatch: {
        Changes: [{
          Action: 'DELETE',
          ResourceRecordSet: {
            Name: FQDN,
            Type: 'A',
            ResourceRecords: resourceRecordSet.ResourceRecords,
            TTL: 60,
          }
        }]
      }
    };
    route53.changeResourceRecordSets(dnsRecordChange, function(err, data) {
      if (err) {
        return callback(err);
      }
      return callback(null);
    });
  });
}

function hostedZoneRecord(route53, hostedZoneId, recordType, FQDN, callback) {
  FQDN = util.format('%s.', FQDN);
  var params = {
    HostedZoneId: hostedZoneId,
    MaxItems: '1',
    StartRecordName: FQDN,
    StartRecordType: recordType
  };
  route53.listResourceRecordSets(params, function(err, data) {
    if (err) {
      return callback(err);
    }
    var resourceRecordSet = data.ResourceRecordSets && data.ResourceRecordSets[0];
    if (resourceRecordSet && (resourceRecordSet.Name === FQDN)) {
      return callback(null, resourceRecordSet);
    }
    callback(null, null);
  });
}

function domainNameFrom(instance, id, context, callback) {
  var domainName = null;
  instance.Tags.forEach(function(tag) {
    if (tag.Key === 'Name') {
      domainName = util.format('%s.%s', tag.Value, BASE_DOMAIN_NAME);
    }
  });
  if (domainName) {
    return callback(null, domainName);
  }
  callback(util.format("Unable to find tag with key 'Name' in instance '%s'", id), null);
}

function dnsRecordChangeFrom(event, ip, name) {
  if (event.detail.state === 'stopping' || event.detail.state === 'shutting-down') {
    return deleteDnsRecord(ip, name);
  }
  return createDnsRecord(ip, name);
}

function deleteDnsRecord(ip, name) {
  return dnsRecord('DELETE', ip, name);
}

function createDnsRecord(ip, name) {
  return dnsRecord('CREATE', ip, name);
}

function dnsRecord(action, ip, name) {
  return {
    HostedZoneId: HOSTED_ZONE_ID,
    ChangeBatch: {
      Changes: [{
        Action: action,
        ResourceRecordSet: {
          Name: name,
          Type: 'A',
          ResourceRecords: [{Value: ip}],
          TTL: 600,
        }
      }]
    }
  };
}
<|endoftext|>


<commit_before>'use strict';

for (var i = 0; i < gameImages.length; i++)
  gameImages[i] = "img/" + gameImages[i];

// Loading progress text
var progressScreenText = new Game.Text("Carregando: 0%", {
    "default": {fontFamily: "Book Antiqua", fontSize: "40px",
      dropShadow: true, dropShadowBlur: 10,
      fill: 0xFFFFFF, align: "left"
    }
  });
progressScreenText.setAnchor(0.5, 0.5);
progressScreenText.setPosition(1920/2, 1080/2);

var onProgressCallback = function(progressInfo) {
  // Update text
  progressScreenText.text = "Carregando: " + progressInfo.progress.toFixed(1) + "%";
  // Draw on screen
  stage.addChild(progressScreenText);
  renderer.render(stage);
}

// After loading all images, load scenes
loader.add(gameImages)
  .on("progress", onProgressCallback)
  .load(function() {
    progressScreenText = null; // Delete the loading object
    for (var i = 0; i < sceneLoader.length; i++) {
      if (sceneLoader[i] != null)
        sceneLoader[i]();
      else
        console.log("ERROR: Failed to load scene " + i);
    }

    // Initial Scene
    setScene(0);
  });
<commit_msg>changed default scene to 2<commit_after>'use strict';

for (var i = 0; i < gameImages.length; i++)
  gameImages[i] = "img/" + gameImages[i];

// Loading progress text
var progressScreenText = new Game.Text("Carregando: 0%", {
    "default": {fontFamily: "Book Antiqua", fontSize: "40px",
      dropShadow: true, dropShadowBlur: 10,
      fill: 0xFFFFFF, align: "left"
    }
  });
progressScreenText.setAnchor(0.5, 0.5);
progressScreenText.setPosition(1920/2, 1080/2);

var onProgressCallback = function(progressInfo) {
  // Update text
  progressScreenText.text = "Carregando: " + progressInfo.progress.toFixed(1) + "%";
  // Draw on screen
  stage.addChild(progressScreenText);
  renderer.render(stage);
}

// After loading all images, load scenes
loader.add(gameImages)
  .on("progress", onProgressCallback)
  .load(function() {
    progressScreenText = null; // Delete the loading object
    for (var i = 0; i < sceneLoader.length; i++) {
      if (sceneLoader[i] != null)
        sceneLoader[i]();
      else
        console.log("ERROR: Failed to load scene " + i);
    }

    // Initial Scene
    setScene(2);
  });
<|endoftext|>


<commit_before>'use strict';

var cluster = require('cluster');
var through = require('through');
var util    = require('util');

require('should');

describe('logger', function() {
  var logs, stream;

  beforeEach(function() {
    logs = [];

    stream = through(function write(data) {
      logs.push(data);
    }, function end() {
      this.queue(null);
    });
  });

  describe('when verbose is false', function() {
    it('does not log', function() {
      require('../lib/logger')(false, stream).log({ foo: 'bar' });
      logs.should.eql([]);
    });
  });

  describe('when verbose is true', function() {
    describe('when in the worker cluster', function() {
      it('logs a worker-namespaced message', function() {
        cluster.isMaster = false;
        require('../lib/logger')(true, stream).log({ foo: 'bar' });
        cluster.isMaster = true;

        logs.should.eql([
          util.format('source=teamster:worker pid=%d foo=bar\n', process.pid)
        ]);
      });
    });

    describe('when in the master cluster', function() {
      it('logs a master-namespaced message', function() {
        require('../lib/logger')(true, stream).log({ foo: 'bar' });

        logs.should.eql([
          util.format('source=teamster:master pid=%d foo=bar\n', process.pid)
        ]);
      });
    });
  });
});
<commit_msg>add test for logger default to stdout<commit_after>'use strict';

var cluster = require('cluster');
var sinon   = require('sinon');
var through = require('through');
var util    = require('util');

require('should');

describe('logger', function() {
  var logs, stream;

  beforeEach(function() {
    logs = [];

    stream = through(function write(data) {
      logs.push(data);
    }, function end() {
      this.queue(null);
    });
  });

  describe('when not given a verbose option', function() {
    it('is verbose', function() {
      require('../lib/logger')(undefined, stream).log({ foo: 'bar' });

      logs.should.eql([
        util.format('source=teamster:master pid=%d foo=bar\n', process.pid)
      ]);
    });
  });

  describe('when not given a stream', function() {
    var outSpy;

    beforeEach(function() {
      outSpy = sinon.spy(process.stdout, 'write');
    });

    afterEach(function() {
      process.stdout.write.restore();
    });

    it('logs to stdout', function() {
      require('../lib/logger')().log({ foo: 'bar' });

      outSpy.calledWithExactly(
        util.format('source=teamster:master pid=%d foo=bar\n', process.pid)
      ).should.eql(true);
    });
  });

  describe('when verbose is false', function() {
    it('does not log', function() {
      require('../lib/logger')(false, stream).log({ foo: 'bar' });
      logs.should.eql([]);
    });
  });

  describe('when verbose is true', function() {
    describe('when in the worker cluster', function() {
      it('logs a worker-namespaced message', function() {
        cluster.isMaster = false;
        require('../lib/logger')(true, stream).log({ foo: 'bar' });
        cluster.isMaster = true;

        logs.should.eql([
          util.format('source=teamster:worker pid=%d foo=bar\n', process.pid)
        ]);
      });
    });

    describe('when in the master cluster', function() {
      it('logs a master-namespaced message', function() {
        require('../lib/logger')(true, stream).log({ foo: 'bar' });

        logs.should.eql([
          util.format('source=teamster:master pid=%d foo=bar\n', process.pid)
        ]);
      });
    });
  });
});
<|endoftext|>


<commit_before>// TODO - test with conversation with multiple ppl
// vim: et:ts=2:sw=2:sts=2:ft=javascript
/**
 * Copyright 2013 j <j@mailb.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var log4js = require('ep_etherpad-lite/node_modules/log4js')
var statsLogger = log4js.getLogger("stats");
var eejs = require('ep_etherpad-lite/node/eejs/');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var sessioninfos = require('ep_etherpad-lite/node/handler/PadMessageHandler').sessioninfos;
var stats = require('ep_etherpad-lite/node/stats')
var socketio;

/**
 * Handles an RTC Message
 * @param client the client that send this message
 * @param message the message from the client
 */
function handleRTCMessage(client, payload)
{
  var userId = sessioninfos[client.id].author;
  var to = payload.to;
  var padId = sessioninfos[client.id].padId;
  var room = socketio.sockets.adapter.rooms[padId];
  var clients = [];

  if (room && room.sockets) {
    for (var id in room.sockets) {
      clients.push(socketio.sockets.sockets[id]);
    }
  }

  var msg = {
    type: "COLLABROOM",
    data: {
      type: "RTC_MESSAGE",
      payload: {
        from: userId,
        data: payload.data
      }
    }
  };
  // Lookup recipient and send message
  for(var i = 0; i < clients.length; i++) {
    var session = sessioninfos[clients[i].id];
    if(session && session.author == to) {
      clients[i].json.send(msg);
      break;
    }
  }
}

// Make sure any updates to this are reflected in README
const statErrorNames = [
  "Abort",
  "Hardware",
  "NotFound",
  "NotSupported",
  "Permission",
  "SecureConnection",
  "Unknown"
]

function handleErrorStatMessage(statName) {
  if (statErrorNames.indexOf(statName) !== -1) {
    stats.meter("ep_webrtc_err_" + statName).mark();
  } else {
    statsLogger.warn("Invalid ep_webrtc error stat: " + statName);
  }
}

exports.clientVars = function(hook, context, callback)
{
  var enabled = true;
  if(settings.ep_webrtc && settings.ep_webrtc.enabled === false){
    enabled = settings.ep_webrtc.enabled;
  }

  var audioAllowed = true;
  if(settings.ep_webrtc && settings.ep_webrtc.audio_allowed === false){
    audioAllowed = settings.ep_webrtc.audio_allowed;
  }

  var audioEnabledOnStart = true;
  if(settings.ep_webrtc && settings.ep_webrtc.audio_enabled_on_start_default === false){
    audioEnabledOnStart = settings.ep_webrtc.audio_enabled_on_start_default;
  }

  var videoAllowed = true;
  if(settings.ep_webrtc && settings.ep_webrtc.video_allowed === false){
    videoAllowed = settings.ep_webrtc.video_allowed;
  }
  var videoEnabledOnStart = true;
  if(settings.ep_webrtc && settings.ep_webrtc.video_enabled_on_start_default === false){
    videoEnabledOnStart = settings.ep_webrtc.video_enabled_on_start_default;
  }

  var iceServers = [ {"url": "stun:stun.l.google.com:19302"} ];
  if(settings.ep_webrtc && settings.ep_webrtc.iceServers){
    iceServers = settings.ep_webrtc.iceServers;
  }

  var listenClass = false;
  if(settings.ep_webrtc && settings.ep_webrtc.listenClass){
    listenClass = settings.ep_webrtc.listenClass;
  }

  var video = {sizes: {}};
  if(settings.ep_webrtc && settings.ep_webrtc.video && settings.ep_webrtc.video.sizes) {
    video.sizes = {
      large: settings.ep_webrtc.video.sizes.large,
      small: settings.ep_webrtc.video.sizes.small
    }
  }

  return callback({
    webrtc: {
      "iceServers": iceServers,
      "enabled": enabled,
      "audio_allowed": audioAllowed,
      "audio_enabled_on_start_default": audioEnabledOnStart,
      "video_allowed": videoAllowed,
      "video_enabled_on_start_default": videoEnabledOnStart,
      "listenClass": listenClass,
      "video": video
    }
  });
};

exports.handleMessage = function ( hook, context, callback )
{
  if (context.message.type == 'COLLABROOM' && context.message.data.type == 'RTC_MESSAGE') {
    handleRTCMessage(context.client, context.message.data.payload);
    callback([null]);
  } else if (context.message.type == 'STATS' && context.message.data.type == 'RTC_MESSAGE') {
    handleErrorStatMessage(context.message.data.statName);
    callback([null]);
  } else {
    callback();
  }
};

exports.setSocketIO = function (hook, context, callback)
{
  socketio = context.io;
  callback();
};

exports.eejsBlock_mySettings = function (hook, context, callback)
{
    var enabled = (settings.ep_webrtc && settings.ep_webrtc.enabled === false)
      ? 'unchecked'
      : 'checked';

    var audioAllowed = (settings.ep_webrtc && settings.ep_webrtc.audio_allowed === false)
      ? false
      : true;

    var videoAllowed = (settings.ep_webrtc && settings.ep_webrtc.video_allowed === false)
      ? false
      : true;

    context.content += eejs.require('ep_webrtc/templates/settings.ejs', {
      enabled : enabled,
      audio_allowed : audioAllowed,
      video_allowed : videoAllowed
    });
    callback();
};

exports.eejsBlock_editorContainerBox = function (hook_name, args, cb) {
  args.content = args.content + eejs.require("ep_webrtc/templates/webrtc.ejs", {}, module);
  return cb();
}

exports.eejsBlock_styles = function (hook_name, args, cb) {
  args.content = args.content + eejs.require("ep_webrtc/templates/styles.html", {}, module);
  return cb();
};
<commit_msg>Tested it<commit_after>// vim: et:ts=2:sw=2:sts=2:ft=javascript
/**
 * Copyright 2013 j <j@mailb.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var log4js = require('ep_etherpad-lite/node_modules/log4js')
var statsLogger = log4js.getLogger("stats");
var eejs = require('ep_etherpad-lite/node/eejs/');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var sessioninfos = require('ep_etherpad-lite/node/handler/PadMessageHandler').sessioninfos;
var stats = require('ep_etherpad-lite/node/stats')
var socketio;

/**
 * Handles an RTC Message
 * @param client the client that send this message
 * @param message the message from the client
 */
function handleRTCMessage(client, payload)
{
  var userId = sessioninfos[client.id].author;
  var to = payload.to;
  var padId = sessioninfos[client.id].padId;
  var room = socketio.sockets.adapter.rooms[padId];
  var clients = [];

  if (room && room.sockets) {
    for (var id in room.sockets) {
      clients.push(socketio.sockets.sockets[id]);
    }
  }

  var msg = {
    type: "COLLABROOM",
    data: {
      type: "RTC_MESSAGE",
      payload: {
        from: userId,
        data: payload.data
      }
    }
  };
  // Lookup recipient and send message
  for(var i = 0; i < clients.length; i++) {
    var session = sessioninfos[clients[i].id];
    if(session && session.author == to) {
      clients[i].json.send(msg);
      break;
    }
  }
}

// Make sure any updates to this are reflected in README
const statErrorNames = [
  "Abort",
  "Hardware",
  "NotFound",
  "NotSupported",
  "Permission",
  "SecureConnection",
  "Unknown"
]

function handleErrorStatMessage(statName) {
  if (statErrorNames.indexOf(statName) !== -1) {
    stats.meter("ep_webrtc_err_" + statName).mark();
  } else {
    statsLogger.warn("Invalid ep_webrtc error stat: " + statName);
  }
}

exports.clientVars = function(hook, context, callback)
{
  var enabled = true;
  if(settings.ep_webrtc && settings.ep_webrtc.enabled === false){
    enabled = settings.ep_webrtc.enabled;
  }

  var audioAllowed = true;
  if(settings.ep_webrtc && settings.ep_webrtc.audio_allowed === false){
    audioAllowed = settings.ep_webrtc.audio_allowed;
  }

  var audioEnabledOnStart = true;
  if(settings.ep_webrtc && settings.ep_webrtc.audio_enabled_on_start_default === false){
    audioEnabledOnStart = settings.ep_webrtc.audio_enabled_on_start_default;
  }

  var videoAllowed = true;
  if(settings.ep_webrtc && settings.ep_webrtc.video_allowed === false){
    videoAllowed = settings.ep_webrtc.video_allowed;
  }
  var videoEnabledOnStart = true;
  if(settings.ep_webrtc && settings.ep_webrtc.video_enabled_on_start_default === false){
    videoEnabledOnStart = settings.ep_webrtc.video_enabled_on_start_default;
  }

  var iceServers = [ {"url": "stun:stun.l.google.com:19302"} ];
  if(settings.ep_webrtc && settings.ep_webrtc.iceServers){
    iceServers = settings.ep_webrtc.iceServers;
  }

  var listenClass = false;
  if(settings.ep_webrtc && settings.ep_webrtc.listenClass){
    listenClass = settings.ep_webrtc.listenClass;
  }

  var video = {sizes: {}};
  if(settings.ep_webrtc && settings.ep_webrtc.video && settings.ep_webrtc.video.sizes) {
    video.sizes = {
      large: settings.ep_webrtc.video.sizes.large,
      small: settings.ep_webrtc.video.sizes.small
    }
  }

  return callback({
    webrtc: {
      "iceServers": iceServers,
      "enabled": enabled,
      "audio_allowed": audioAllowed,
      "audio_enabled_on_start_default": audioEnabledOnStart,
      "video_allowed": videoAllowed,
      "video_enabled_on_start_default": videoEnabledOnStart,
      "listenClass": listenClass,
      "video": video
    }
  });
};

exports.handleMessage = function ( hook, context, callback )
{
  if (context.message.type == 'COLLABROOM' && context.message.data.type == 'RTC_MESSAGE') {
    handleRTCMessage(context.client, context.message.data.payload);
    callback([null]);
  } else if (context.message.type == 'STATS' && context.message.data.type == 'RTC_MESSAGE') {
    handleErrorStatMessage(context.message.data.statName);
    callback([null]);
  } else {
    callback();
  }
};

exports.setSocketIO = function (hook, context, callback)
{
  socketio = context.io;
  callback();
};

exports.eejsBlock_mySettings = function (hook, context, callback)
{
    var enabled = (settings.ep_webrtc && settings.ep_webrtc.enabled === false)
      ? 'unchecked'
      : 'checked';

    var audioAllowed = (settings.ep_webrtc && settings.ep_webrtc.audio_allowed === false)
      ? false
      : true;

    var videoAllowed = (settings.ep_webrtc && settings.ep_webrtc.video_allowed === false)
      ? false
      : true;

    context.content += eejs.require('ep_webrtc/templates/settings.ejs', {
      enabled : enabled,
      audio_allowed : audioAllowed,
      video_allowed : videoAllowed
    });
    callback();
};

exports.eejsBlock_editorContainerBox = function (hook_name, args, cb) {
  args.content = args.content + eejs.require("ep_webrtc/templates/webrtc.ejs", {}, module);
  return cb();
}

exports.eejsBlock_styles = function (hook_name, args, cb) {
  args.content = args.content + eejs.require("ep_webrtc/templates/styles.html", {}, module);
  return cb();
};
<|endoftext|>


<commit_before>/*
    Copyright (c) 2012, 2013 The WebStory Engine Contributors
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    * Neither the name WebStory Engine nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function (out)
{
    "use strict";

    out.commands.restart = function (command, interpreter)
    {
        interpreter.bus.trigger(
            "wse.interpreter.commands.restart",
            {
                interpreter: interpreter,
                command: command
            },
            false
        );

        interpreter.bus.trigger("wse.interpreter.message", "Restarting game...", false);
        interpreter.bus.trigger("wse.interpreter.restart", interpreter, false);

        interpreter.runVars = {};
        interpreter.log = [];
        interpreter.visitedScenes = [];
        interpreter.startTime = Math.round(+new Date() / 1000);
        interpreter.waitCounter = 0;
        interpreter.state = "listen";
        interpreter.stage.innerHTML = "";

        this.assets = {};
        interpreter.buildAssets();

        return {
            doNext: true,
            changeScene: interpreter.scenes[0]
        };
    };
}(WSE));<commit_msg>Fixed "overwriting asset" warnings on <restart />.<commit_after>/*
    Copyright (c) 2012, 2013 The WebStory Engine Contributors
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    * Neither the name WebStory Engine nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function (out)
{
    "use strict";

    out.commands.restart = function (command, interpreter)
    {
        interpreter.bus.trigger(
            "wse.interpreter.commands.restart",
            {
                interpreter: interpreter,
                command: command
            },
            false
        );

        interpreter.bus.trigger("wse.interpreter.message", "Restarting game...", false);
        interpreter.bus.trigger("wse.interpreter.restart", interpreter, false);

        interpreter.runVars = {};
        interpreter.log = [];
        interpreter.visitedScenes = [];
        interpreter.startTime = Math.round(+new Date() / 1000);
        interpreter.waitCounter = 0;
        interpreter.state = "listen";
        interpreter.stage.innerHTML = "";

        interpreter.assets = {};
        interpreter.buildAssets();

        return {
            doNext: true,
            changeScene: interpreter.scenes[0]
        };
    };
}(WSE));<|endoftext|>