<commit_before>'use strict'

const _ = require('lodash')
const asar = require('asar')
const debug = require('debug')
const fs = require('fs-extra')
const fsize = require('get-folder-size')
const glob = require('glob')
const mkdirp = require('mkdirp')
const nodeify = require('nodeify')
const path = require('path')
const pify = require('pify')
const temp = require('temp').track()
const wrap = require('word-wrap')

const dependencies = require('./dependencies')
const spawn = require('./spawn')

const defaultLogger = debug('electron-installer-debian')

const defaultRename = (dest, src) => {
  return path.join(dest, '<%= name %>_<%= version %>_<%= arch %>.deb')
}

function errorMessage (message, err) {
  return `Error ${message}: ${err.message || err}`
}

function wrapError (message) {
  return err => {
    throw new Error(errorMessage(message, err))
  }
}

/**
 * Read `package.json` either from `resources/app.asar` (if the app is packaged)
 * or from `resources/app/package.json` (if it is not).
 */
function readMeta (options) {
  const appAsarPath = path.join(options.src, 'resources/app.asar')
  const appPackageJSONPath = path.join(options.src, 'resources/app/package.json')

  return fs.pathExists(appAsarPath)
    .then(asarExists => {
      if (asarExists) {
        options.logger(`Reading package metadata from ${appAsarPath}`)
        return JSON.parse(asar.extractFile(appAsarPath, 'package.json'))
      } else {
        options.logger(`Reading package metadata from ${appPackageJSONPath}`)
        return fs.readJson(appPackageJSONPath)
      }
    }).catch(wrapError('reading package metadata'))
}

/**
 * Read `LICENSE` from the root of the app.
 */
function copyLicense (options, copyrightFile) {
  const licenseSrc = path.join(options.src, 'LICENSE')
  options.logger(`Copying license file from ${licenseSrc}`)

  return fs.copy(licenseSrc, copyrightFile)
}

/**
 * Get the size of the app.
 */
function getSize (options) {
  return pify(fsize)(options.src)
}

/**
 * Get the hash of default options for the installer. Some come from the info
 * read from `package.json`, and some are hardcoded.
 */
function getDefaults (data) {
  const src = {src: data.src}
  return Promise.all([readMeta(data), getSize(src), dependencies.getElectronVersion(src)])
    .then(results => {
      const pkg = results[0] || {}
      const size = results[1] || 0
      const electronVersion = results[2]

      return {
        name: pkg.name || 'electron',
        productName: pkg.productName || pkg.name,
        genericName: pkg.genericName || pkg.productName || pkg.name,
        description: pkg.description,
        productDescription: pkg.productDescription || pkg.description,
        // Use '~' on pre-releases for proper Debian version ordering.
        // See https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
        version: (pkg.version || '0.0.0').replace(/(\d)[_.+-]?((RC|rc|pre|dev|beta|alpha)[_.+-]?\d*)$/, '$1~$2'),
        revision: pkg.revision || '1',

        section: 'utils',
        priority: 'optional',
        arch: undefined,
        size: Math.ceil(size / 1024),

        depends: dependencies.getDepends(electronVersion),
        recommends: [
          'pulseaudio | libasound2'
        ],
        suggests: [
          'gir1.2-gnomekeyring-1.0',
          'libgnome-keyring0',
          'lsb-release'
        ],
        enhances: [
        ],
        preDepends: [
        ],

        maintainer: pkg.author && (typeof pkg.author === 'string'
          ? pkg.author.replace(/\s+\([^)]+\)/, '')
          : pkg.author.name +
          (pkg.author.email != null ? ` <${pkg.author.email}>` : '')
        ),

        homepage: pkg.homepage || (pkg.author && (typeof pkg.author === 'string'
          ? pkg.author.replace(/.*\(([^)]+)\).*/, '$1')
          : pkg.author.url
        )),

        bin: pkg.name || 'electron',
        icon: path.resolve(__dirname, '../resources/icon.png'),

        categories: [
          'GNOME',
          'GTK',
          'Utility'
        ],

        mimeType: [],

        lintianOverrides: []
      }
    })
}

/**
 * Get the hash of options for the installer.
 */
function getOptions (data, defaults) {
  // Flatten everything for ease of use.
  const options = _.defaults({}, data, data.options, defaults)

  if (!options.description && !options.productDescription) {
    throw new Error('No Description or ProductDescription provided')
  }

  if (options.description) {
    // Replace all newlines in the description with spaces, since it's supposed
    // to be one line.
    options.description = options.description.replace(/[\r\n]+/g, ' ')
  }

  if (options.productDescription) {
    // Ensure blank lines have the "." that denotes a blank line in the control file.
    // Wrap any extended description lines to avoid lintian warning about
    // `extended-description-line-too-long`.
    options.productDescription = options.productDescription
      .replace(/\r\n/g, '\n') // Fixes errors when finding blank lines in Windows
      .replace(/^$/mg, '.')
      .split('\n')
      .map(line => wrap(line, {width: 80, indent: ' '}))
      .join('\n')
  }

  // Create array with unique values from default & user-supplied dependencies
  for (const prop of ['depends', 'recommends', 'suggests', 'enhances', 'preDepends']) {
    if (data.options) { // options passed programmatically
      options[prop] = _.union(defaults[prop], data.options[prop])
    } else { // options passed via command-line
      options[prop] = _.union(defaults[prop], data[prop])
    }
  }

  return options
}

/**
 * Fill in a template with the hash of options.
 */
function generateTemplate (options, file) {
  options.logger(`Generating template from ${file}`)

  return fs.readFile(file)
    .then(template => {
      const result = _.template(template)(options)
      options.logger(`Generated template from ${file}\n${result}`)
      return result
    })
}

/**
 * Create the control file for the package.
 *
 * See: https://www.debian.org/doc/debian-policy/ch-controlfields.html
 */
function createControl (options, dir) {
  const controlSrc = path.resolve(__dirname, '../resources/control.ejs')
  const controlDest = path.join(dir, 'DEBIAN/control')
  options.logger(`Creating control file at ${controlDest}`)

  return pify(mkdirp)(path.dirname(controlDest), '0755')
    .then(() => generateTemplate(options, controlSrc))
    .then(data => fs.outputFile(controlDest, data))
    .catch(wrapError('creating control file'))
}

/**
 * Copy debian scripts.
 */
function copyScripts (options, dir) {
  const scriptNames = ['preinst', 'postinst', 'prerm', 'postrm']

  return Promise.all(_.map(options.scripts, (item, key) => {
    if (_.includes(scriptNames, key)) {
      const scriptFile = path.join(dir, 'DEBIAN', key)
      options.logger(`Creating script file at ${scriptFile}`)

      return fs.copy(item, scriptFile)
    } else {
      throw new Error(`Wrong executable script name: ${key}`)
    }
  })).catch(wrapError('creating script files'))
}

/**
 * Create the binary for the package.
 */
function createBinary (options, dir) {
  const binDir = path.join(dir, 'usr/bin')
  const binSrc = path.join('../lib', options.name, options.bin)
  const binDest = path.join(binDir, options.name)
  options.logger(`Symlinking binary from ${binSrc} to ${binDest}`)

  return pify(mkdirp)(binDir, '0755')
    .catch(wrapError('creating binary path'))
    .then(() => fs.symlink(binSrc, binDest, 'file'))
    .catch(wrapError('creating binary file'))
}

/**
 * Create the desktop file for the package.
 *
 * See: http://standards.freedesktop.org/desktop-entry-spec/latest/
 */
function createDesktop (options, dir) {
  const desktopSrc = options.desktopTemplate || path.resolve(__dirname, '../resources/desktop.ejs')
  const desktopDest = path.join(dir, 'usr/share/applications', `${options.name}.desktop`)
  options.logger(`Creating desktop file at ${desktopDest}`)

  return pify(mkdirp)(path.dirname(desktopDest), '0755')
    .catch(wrapError('creating desktop path'))
    .then(() => generateTemplate(options, desktopSrc))
    .then(data => fs.outputFile(desktopDest, data))
    .then(() => fs.chmod(desktopDest, '0644'))
    .catch(wrapError('creating desktop file'))
}

/**
 * Create pixmap icon for the package.
 */
function createPixmapIcon (options, dir) {
  const iconFile = path.join(dir, 'usr/share/pixmaps', `${options.name}.png`)
  options.logger(`Creating icon file at ${iconFile}`)

  return pify(mkdirp)(path.dirname(iconFile), '0755')
    .catch(wrapError('creating icon path'))
    .then(() => fs.copy(options.icon, iconFile))
    .then(() => fs.chmod(iconFile, '0644'))
    .catch(wrapError('creating icon file'))
}

/**
 * Create hicolor icon for the package.
 */
function createHicolorIcon (options, dir) {
  return Promise.all(_.map(options.icon, (icon, resolution) => {
    const iconExt = resolution === 'scalable' ? 'svg' : 'png'
    const iconFile = path.join(dir, 'usr/share/icons/hicolor', resolution, 'apps', `${options.name}.${iconExt}`)
    options.logger(`Creating icon file at ${iconFile}`)

    return pify(mkdirp)(path.dirname(iconFile), '0755')
      .then(() => fs.copy(icon, iconFile))
      .then(() => fs.chmod(iconFile, '0644'))
      .catch(wrapError('creating icon file'))
  }))
}

/**
 * Create icon for the package.
 */
function createIcon (options, dir) {
  if (_.isObject(options.icon)) {
    return createHicolorIcon(options, dir)
  } else {
    return createPixmapIcon(options, dir)
  }
}

/**
 * Create copyright for the package.
 */
function createCopyright (options, dir) {
  const copyrightFile = path.join(dir, 'usr/share/doc', options.name, 'copyright')
  options.logger(`Creating copyright file at ${copyrightFile}`)

  return pify(mkdirp)(path.dirname(copyrightFile), '0755')
    .then(() => copyLicense(options, copyrightFile))
    .then(() => fs.chmod(copyrightFile, '0644'))
    .catch(wrapError('creating copyright file'))
}

/**
 * Create lintian overrides for the package.
 */
function createOverrides (options, dir) {
  const overridesSrc = path.resolve(__dirname, '../resources/overrides.ejs')
  const overridesDest = path.join(dir, 'usr/share/lintian/overrides', options.name)
  options.logger(`Creating lintian overrides at ${overridesDest}`)

  return pify(mkdirp)(path.dirname(overridesDest), '0755')
    .then(() => generateTemplate(options, overridesSrc))
    .then(data => fs.outputFile(overridesDest, data))
    .then(() => fs.chmod(overridesDest, '0644'))
    .catch(wrapError('creating lintian overrides file'))
}

/**
 * Copy the application into the package.
 */
function createApplication (options, dir) {
  const applicationDir = path.join(dir, 'usr/lib', options.name)
  const licenseFile = path.join(applicationDir, 'LICENSE')
  options.logger(`Copying application to ${applicationDir}`)

  return pify(mkdirp)(applicationDir, '0755')
    .then(() => fs.copy(options.src, applicationDir))
    .then(() => fs.unlink(licenseFile))
    .catch(wrapError('copying application directory'))
}

/**
 * Create temporary directory where the contents of the package will live.
 */
function createDir (options) {
  options.logger('Creating temporary directory')
  let tempDir

  return pify(temp.mkdir)('electron-')
    .then(dir => {
      tempDir = path.join(dir, `${options.name}_${options.version}_${options.arch}`)
      return pify(mkdirp)(tempDir, '0755')
    })
    .catch(wrapError('creating temporary directory'))
}

/**
 * Create the contents of the package.
 */
function createContents (options, dir) {
  options.logger('Creating contents of package')
  options.logger(`createContents(${options}, ${dir})`)

  return Promise.all([
    createControl,
    copyScripts,
    createBinary,
    createDesktop,
    createIcon,
    createCopyright,
    createOverrides,
    createApplication
  ].map(func => func(options, dir)))
    .then(() => dir)
}

/**
 * Package everything using `dpkg` and `fakeroot`.
 */
function createPackage (options, dir) {
  options.logger(`Creating package at ${dir}`)

  return spawn('fakeroot', ['dpkg-deb', '--build', dir], options.logger)
    .then(output => {
      options.logger(`dpkg-deb output: ${output}`)
      return dir
    })
}

/**
 * Move the package to the specified destination.
 */
function movePackage (options, dir) {
  options.logger('Moving package to destination')

  const packagePattern = path.join(dir, '../*.deb')
  return pify(glob)(packagePattern)
    .then(files => Promise.all(files.map(file => {
      const template = options.rename(options.dest, path.basename(file))
      const dest = _.template(template)(options)
      options.logger(`Moving file ${file} to ${dest}`)
      return fs.move(file, dest, {clobber: true})
    }))).catch(wrapError('moving package files'))
}

/* ************************************************************************** */

module.exports = (data, callback) => {
  data.rename = data.rename || defaultRename
  data.logger = data.logger || defaultLogger

  let options

  if (process.umask() !== 0o0022 && process.umask() !== 0o0002) {
    console.warn(`\x1b[1mThe current umask, ${process.umask().toString(8)}, is not supported. You should use 0022 or 0002\x1b[0m`)
  }

  const promise = getDefaults(data)
    .then(defaults => getOptions(data, defaults))
    .then(generatedOptions => {
      options = generatedOptions
      return data.logger(`Creating package with options\n${JSON.stringify(options, null, 2)}`)
    }).then(() => createDir(options))
    .then(dir => createContents(options, dir))
    .then(dir => createPackage(options, dir))
    .then(dir => movePackage(options, dir))
    .then(() => {
      data.logger(`Successfully created package at ${options.dest}`)
      return options
    }).catch(err => {
      data.logger(errorMessage('creating package', err))
      throw err
    })

  return nodeify(promise, callback)
}
<commit_msg>Remove bold control characters on warn message<commit_after>'use strict'

const _ = require('lodash')
const asar = require('asar')
const debug = require('debug')
const fs = require('fs-extra')
const fsize = require('get-folder-size')
const glob = require('glob')
const mkdirp = require('mkdirp')
const nodeify = require('nodeify')
const path = require('path')
const pify = require('pify')
const temp = require('temp').track()
const wrap = require('word-wrap')

const dependencies = require('./dependencies')
const spawn = require('./spawn')

const defaultLogger = debug('electron-installer-debian')

const defaultRename = (dest, src) => {
  return path.join(dest, '<%= name %>_<%= version %>_<%= arch %>.deb')
}

function errorMessage (message, err) {
  return `Error ${message}: ${err.message || err}`
}

function wrapError (message) {
  return err => {
    throw new Error(errorMessage(message, err))
  }
}

/**
 * Read `package.json` either from `resources/app.asar` (if the app is packaged)
 * or from `resources/app/package.json` (if it is not).
 */
function readMeta (options) {
  const appAsarPath = path.join(options.src, 'resources/app.asar')
  const appPackageJSONPath = path.join(options.src, 'resources/app/package.json')

  return fs.pathExists(appAsarPath)
    .then(asarExists => {
      if (asarExists) {
        options.logger(`Reading package metadata from ${appAsarPath}`)
        return JSON.parse(asar.extractFile(appAsarPath, 'package.json'))
      } else {
        options.logger(`Reading package metadata from ${appPackageJSONPath}`)
        return fs.readJson(appPackageJSONPath)
      }
    }).catch(wrapError('reading package metadata'))
}

/**
 * Read `LICENSE` from the root of the app.
 */
function copyLicense (options, copyrightFile) {
  const licenseSrc = path.join(options.src, 'LICENSE')
  options.logger(`Copying license file from ${licenseSrc}`)

  return fs.copy(licenseSrc, copyrightFile)
}

/**
 * Get the size of the app.
 */
function getSize (options) {
  return pify(fsize)(options.src)
}

/**
 * Get the hash of default options for the installer. Some come from the info
 * read from `package.json`, and some are hardcoded.
 */
function getDefaults (data) {
  const src = {src: data.src}
  return Promise.all([readMeta(data), getSize(src), dependencies.getElectronVersion(src)])
    .then(results => {
      const pkg = results[0] || {}
      const size = results[1] || 0
      const electronVersion = results[2]

      return {
        name: pkg.name || 'electron',
        productName: pkg.productName || pkg.name,
        genericName: pkg.genericName || pkg.productName || pkg.name,
        description: pkg.description,
        productDescription: pkg.productDescription || pkg.description,
        // Use '~' on pre-releases for proper Debian version ordering.
        // See https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
        version: (pkg.version || '0.0.0').replace(/(\d)[_.+-]?((RC|rc|pre|dev|beta|alpha)[_.+-]?\d*)$/, '$1~$2'),
        revision: pkg.revision || '1',

        section: 'utils',
        priority: 'optional',
        arch: undefined,
        size: Math.ceil(size / 1024),

        depends: dependencies.getDepends(electronVersion),
        recommends: [
          'pulseaudio | libasound2'
        ],
        suggests: [
          'gir1.2-gnomekeyring-1.0',
          'libgnome-keyring0',
          'lsb-release'
        ],
        enhances: [
        ],
        preDepends: [
        ],

        maintainer: pkg.author && (typeof pkg.author === 'string'
          ? pkg.author.replace(/\s+\([^)]+\)/, '')
          : pkg.author.name +
          (pkg.author.email != null ? ` <${pkg.author.email}>` : '')
        ),

        homepage: pkg.homepage || (pkg.author && (typeof pkg.author === 'string'
          ? pkg.author.replace(/.*\(([^)]+)\).*/, '$1')
          : pkg.author.url
        )),

        bin: pkg.name || 'electron',
        icon: path.resolve(__dirname, '../resources/icon.png'),

        categories: [
          'GNOME',
          'GTK',
          'Utility'
        ],

        mimeType: [],

        lintianOverrides: []
      }
    })
}

/**
 * Get the hash of options for the installer.
 */
function getOptions (data, defaults) {
  // Flatten everything for ease of use.
  const options = _.defaults({}, data, data.options, defaults)

  if (!options.description && !options.productDescription) {
    throw new Error('No Description or ProductDescription provided')
  }

  if (options.description) {
    // Replace all newlines in the description with spaces, since it's supposed
    // to be one line.
    options.description = options.description.replace(/[\r\n]+/g, ' ')
  }

  if (options.productDescription) {
    // Ensure blank lines have the "." that denotes a blank line in the control file.
    // Wrap any extended description lines to avoid lintian warning about
    // `extended-description-line-too-long`.
    options.productDescription = options.productDescription
      .replace(/\r\n/g, '\n') // Fixes errors when finding blank lines in Windows
      .replace(/^$/mg, '.')
      .split('\n')
      .map(line => wrap(line, {width: 80, indent: ' '}))
      .join('\n')
  }

  // Create array with unique values from default & user-supplied dependencies
  for (const prop of ['depends', 'recommends', 'suggests', 'enhances', 'preDepends']) {
    if (data.options) { // options passed programmatically
      options[prop] = _.union(defaults[prop], data.options[prop])
    } else { // options passed via command-line
      options[prop] = _.union(defaults[prop], data[prop])
    }
  }

  return options
}

/**
 * Fill in a template with the hash of options.
 */
function generateTemplate (options, file) {
  options.logger(`Generating template from ${file}`)

  return fs.readFile(file)
    .then(template => {
      const result = _.template(template)(options)
      options.logger(`Generated template from ${file}\n${result}`)
      return result
    })
}

/**
 * Create the control file for the package.
 *
 * See: https://www.debian.org/doc/debian-policy/ch-controlfields.html
 */
function createControl (options, dir) {
  const controlSrc = path.resolve(__dirname, '../resources/control.ejs')
  const controlDest = path.join(dir, 'DEBIAN/control')
  options.logger(`Creating control file at ${controlDest}`)

  return pify(mkdirp)(path.dirname(controlDest), '0755')
    .then(() => generateTemplate(options, controlSrc))
    .then(data => fs.outputFile(controlDest, data))
    .catch(wrapError('creating control file'))
}

/**
 * Copy debian scripts.
 */
function copyScripts (options, dir) {
  const scriptNames = ['preinst', 'postinst', 'prerm', 'postrm']

  return Promise.all(_.map(options.scripts, (item, key) => {
    if (_.includes(scriptNames, key)) {
      const scriptFile = path.join(dir, 'DEBIAN', key)
      options.logger(`Creating script file at ${scriptFile}`)

      return fs.copy(item, scriptFile)
    } else {
      throw new Error(`Wrong executable script name: ${key}`)
    }
  })).catch(wrapError('creating script files'))
}

/**
 * Create the binary for the package.
 */
function createBinary (options, dir) {
  const binDir = path.join(dir, 'usr/bin')
  const binSrc = path.join('../lib', options.name, options.bin)
  const binDest = path.join(binDir, options.name)
  options.logger(`Symlinking binary from ${binSrc} to ${binDest}`)

  return pify(mkdirp)(binDir, '0755')
    .catch(wrapError('creating binary path'))
    .then(() => fs.symlink(binSrc, binDest, 'file'))
    .catch(wrapError('creating binary file'))
}

/**
 * Create the desktop file for the package.
 *
 * See: http://standards.freedesktop.org/desktop-entry-spec/latest/
 */
function createDesktop (options, dir) {
  const desktopSrc = options.desktopTemplate || path.resolve(__dirname, '../resources/desktop.ejs')
  const desktopDest = path.join(dir, 'usr/share/applications', `${options.name}.desktop`)
  options.logger(`Creating desktop file at ${desktopDest}`)

  return pify(mkdirp)(path.dirname(desktopDest), '0755')
    .catch(wrapError('creating desktop path'))
    .then(() => generateTemplate(options, desktopSrc))
    .then(data => fs.outputFile(desktopDest, data))
    .then(() => fs.chmod(desktopDest, '0644'))
    .catch(wrapError('creating desktop file'))
}

/**
 * Create pixmap icon for the package.
 */
function createPixmapIcon (options, dir) {
  const iconFile = path.join(dir, 'usr/share/pixmaps', `${options.name}.png`)
  options.logger(`Creating icon file at ${iconFile}`)

  return pify(mkdirp)(path.dirname(iconFile), '0755')
    .catch(wrapError('creating icon path'))
    .then(() => fs.copy(options.icon, iconFile))
    .then(() => fs.chmod(iconFile, '0644'))
    .catch(wrapError('creating icon file'))
}

/**
 * Create hicolor icon for the package.
 */
function createHicolorIcon (options, dir) {
  return Promise.all(_.map(options.icon, (icon, resolution) => {
    const iconExt = resolution === 'scalable' ? 'svg' : 'png'
    const iconFile = path.join(dir, 'usr/share/icons/hicolor', resolution, 'apps', `${options.name}.${iconExt}`)
    options.logger(`Creating icon file at ${iconFile}`)

    return pify(mkdirp)(path.dirname(iconFile), '0755')
      .then(() => fs.copy(icon, iconFile))
      .then(() => fs.chmod(iconFile, '0644'))
      .catch(wrapError('creating icon file'))
  }))
}

/**
 * Create icon for the package.
 */
function createIcon (options, dir) {
  if (_.isObject(options.icon)) {
    return createHicolorIcon(options, dir)
  } else {
    return createPixmapIcon(options, dir)
  }
}

/**
 * Create copyright for the package.
 */
function createCopyright (options, dir) {
  const copyrightFile = path.join(dir, 'usr/share/doc', options.name, 'copyright')
  options.logger(`Creating copyright file at ${copyrightFile}`)

  return pify(mkdirp)(path.dirname(copyrightFile), '0755')
    .then(() => copyLicense(options, copyrightFile))
    .then(() => fs.chmod(copyrightFile, '0644'))
    .catch(wrapError('creating copyright file'))
}

/**
 * Create lintian overrides for the package.
 */
function createOverrides (options, dir) {
  const overridesSrc = path.resolve(__dirname, '../resources/overrides.ejs')
  const overridesDest = path.join(dir, 'usr/share/lintian/overrides', options.name)
  options.logger(`Creating lintian overrides at ${overridesDest}`)

  return pify(mkdirp)(path.dirname(overridesDest), '0755')
    .then(() => generateTemplate(options, overridesSrc))
    .then(data => fs.outputFile(overridesDest, data))
    .then(() => fs.chmod(overridesDest, '0644'))
    .catch(wrapError('creating lintian overrides file'))
}

/**
 * Copy the application into the package.
 */
function createApplication (options, dir) {
  const applicationDir = path.join(dir, 'usr/lib', options.name)
  const licenseFile = path.join(applicationDir, 'LICENSE')
  options.logger(`Copying application to ${applicationDir}`)

  return pify(mkdirp)(applicationDir, '0755')
    .then(() => fs.copy(options.src, applicationDir))
    .then(() => fs.unlink(licenseFile))
    .catch(wrapError('copying application directory'))
}

/**
 * Create temporary directory where the contents of the package will live.
 */
function createDir (options) {
  options.logger('Creating temporary directory')
  let tempDir

  return pify(temp.mkdir)('electron-')
    .then(dir => {
      tempDir = path.join(dir, `${options.name}_${options.version}_${options.arch}`)
      return pify(mkdirp)(tempDir, '0755')
    })
    .catch(wrapError('creating temporary directory'))
}

/**
 * Create the contents of the package.
 */
function createContents (options, dir) {
  options.logger('Creating contents of package')
  options.logger(`createContents(${options}, ${dir})`)

  return Promise.all([
    createControl,
    copyScripts,
    createBinary,
    createDesktop,
    createIcon,
    createCopyright,
    createOverrides,
    createApplication
  ].map(func => func(options, dir)))
    .then(() => dir)
}

/**
 * Package everything using `dpkg` and `fakeroot`.
 */
function createPackage (options, dir) {
  options.logger(`Creating package at ${dir}`)

  return spawn('fakeroot', ['dpkg-deb', '--build', dir], options.logger)
    .then(output => {
      options.logger(`dpkg-deb output: ${output}`)
      return dir
    })
}

/**
 * Move the package to the specified destination.
 */
function movePackage (options, dir) {
  options.logger('Moving package to destination')

  const packagePattern = path.join(dir, '../*.deb')
  return pify(glob)(packagePattern)
    .then(files => Promise.all(files.map(file => {
      const template = options.rename(options.dest, path.basename(file))
      const dest = _.template(template)(options)
      options.logger(`Moving file ${file} to ${dest}`)
      return fs.move(file, dest, {clobber: true})
    }))).catch(wrapError('moving package files'))
}

/* ************************************************************************** */

module.exports = (data, callback) => {
  data.rename = data.rename || defaultRename
  data.logger = data.logger || defaultLogger

  let options

  if (process.umask() !== 0o0022 && process.umask() !== 0o0002) {
    console.warn(`The current umask, ${process.umask().toString(8)}, is not supported. You should use 0022 or 0002`)
  }

  const promise = getDefaults(data)
    .then(defaults => getOptions(data, defaults))
    .then(generatedOptions => {
      options = generatedOptions
      return data.logger(`Creating package with options\n${JSON.stringify(options, null, 2)}`)
    }).then(() => createDir(options))
    .then(dir => createContents(options, dir))
    .then(dir => createPackage(options, dir))
    .then(dir => movePackage(options, dir))
    .then(() => {
      data.logger(`Successfully created package at ${options.dest}`)
      return options
    }).catch(err => {
      data.logger(errorMessage('creating package', err))
      throw err
    })

  return nodeify(promise, callback)
}
<|endoftext|>


<commit_before>define([
  'angular',
  'app',
  'lodash',
], function(angular, app, _) {
  'use strict';

  var module = angular.module('grafana.panels.graph', []);
  app.useModule(module);

  module.controller('SeriesOverridesCtrl', function($scope) {
    $scope.overrideMenu = [];
    $scope.currentOverrides = [];
    $scope.override = $scope.override || {};

    $scope.addOverrideOption = function(name, propertyName, values) {
      var option = {};
      option.text = name;
      option.propertyName = propertyName;
      option.index = $scope.overrideMenu.length;
      option.values = values;

      option.submenu = _.map(values, function(value, index) {
        return {
          text: String(value),
          click: 'setOverride(' + option.index + ',' + index + ')'
        };
      });

      $scope.overrideMenu.push(option);
    };

    $scope.setOverride = function(optionIndex, valueIndex) {
      var option = $scope.overrideMenu[optionIndex];
      var value = option.values[valueIndex];
      $scope.override[option.propertyName] = value;
      $scope.updateCurrentOverrides();
      $scope.render();
    };

    $scope.removeOverride = function(option) {
      delete $scope.override[option.propertyName];
      $scope.updateCurrentOverrides();
      $scope.render();
    };

    $scope.getSeriesNames = function() {
      return _.map($scope.legend, function(info) {
        return info.alias;
      });
    };

    $scope.updateCurrentOverrides = function() {
      $scope.currentOverrides = [];
      _.each($scope.overrideMenu, function(option) {
        var value = $scope.override[option.propertyName];
        if (_.isUndefined(value)) { return; }
        $scope.currentOverrides.push({
          name: option.text,
          propertyName: option.propertyName,
          value: String(value)
        });
      });
    };

    $scope.addOverrideOption('Bars', 'bars', [true, false]);
    $scope.addOverrideOption('Lines', 'lines', [true, false]);
    $scope.addOverrideOption('Line fill', 'fill', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Line width', 'linewidth', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
    $scope.addOverrideOption('Points', 'points', [true, false]);
    $scope.addOverrideOption('Points Radius', 'pointradius', [1,2,3,4,5]);
    $scope.addOverrideOption('Stack', 'stack', [true, false]);
    $scope.addOverrideOption('Y-axis', 'yaxis', [1, 2]);
    $scope.addOverrideOption('Z-index', 'zindex', [-1,-2,-3,0,1,2,3]);
    $scope.updateCurrentOverrides();

  });

});
<commit_msg>add override options to allow multiple stacks<commit_after>define([
  'angular',
  'app',
  'lodash',
], function(angular, app, _) {
  'use strict';

  var module = angular.module('grafana.panels.graph', []);
  app.useModule(module);

  module.controller('SeriesOverridesCtrl', function($scope) {
    $scope.overrideMenu = [];
    $scope.currentOverrides = [];
    $scope.override = $scope.override || {};

    $scope.addOverrideOption = function(name, propertyName, values) {
      var option = {};
      option.text = name;
      option.propertyName = propertyName;
      option.index = $scope.overrideMenu.length;
      option.values = values;

      option.submenu = _.map(values, function(value, index) {
        return {
          text: String(value),
          click: 'setOverride(' + option.index + ',' + index + ')'
        };
      });

      $scope.overrideMenu.push(option);
    };

    $scope.setOverride = function(optionIndex, valueIndex) {
      var option = $scope.overrideMenu[optionIndex];
      var value = option.values[valueIndex];
      $scope.override[option.propertyName] = value;
      $scope.updateCurrentOverrides();
      $scope.render();
    };

    $scope.removeOverride = function(option) {
      delete $scope.override[option.propertyName];
      $scope.updateCurrentOverrides();
      $scope.render();
    };

    $scope.getSeriesNames = function() {
      return _.map($scope.legend, function(info) {
        return info.alias;
      });
    };

    $scope.updateCurrentOverrides = function() {
      $scope.currentOverrides = [];
      _.each($scope.overrideMenu, function(option) {
        var value = $scope.override[option.propertyName];
        if (_.isUndefined(value)) { return; }
        $scope.currentOverrides.push({
          name: option.text,
          propertyName: option.propertyName,
          value: String(value)
        });
      });
    };

    $scope.addOverrideOption('Bars', 'bars', [true, false]);
    $scope.addOverrideOption('Lines', 'lines', [true, false]);
    $scope.addOverrideOption('Line fill', 'fill', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Line width', 'linewidth', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
    $scope.addOverrideOption('Points', 'points', [true, false]);
    $scope.addOverrideOption('Points Radius', 'pointradius', [1,2,3,4,5]);
    $scope.addOverrideOption('Stack', 'stack', [true, false, 2, 3, 4, 5]);
    $scope.addOverrideOption('Y-axis', 'yaxis', [1, 2]);
    $scope.addOverrideOption('Z-index', 'zindex', [-1,-2,-3,0,1,2,3]);
    $scope.updateCurrentOverrides();

  });

});
<|endoftext|>


<commit_before>// ECMAScript 6 collections shim
!function(){
  var UID   = safeSymbol('uid')
    , O1    = safeSymbol('O1')
    , WEAK  = safeSymbol('weak')
    , LEAK  = safeSymbol('leak')
    , LAST  = safeSymbol('last')
    , FIRST = safeSymbol('first')
    , SIZE  = DESC ? safeSymbol('size') : 'size'
    , uid   = 0
    , tmp   = {};

  function getCollection(C, NAME, methods, commonMethods, isMap, isWeak){
    var ADDER = isMap ? 'set' : 'add'
      , proto = C && C[PROTOTYPE]
      , O     = {};
    function initFromIterable(that, iterable){
      if(iterable != undefined)forOf(iterable, isMap, that[ADDER], that);
      return that;
    }
    function fixSVZ(key, chain){
      var method = proto[key];
      if(framework)proto[key] = function(a, b){
        var result = method.call(this, a === 0 ? 0 : a, b);
        return chain ? this : result;
      };
    }
    if(!isNative(C) || !(isWeak || (!BUGGY_ITERATORS && has(proto, FOR_EACH) && has(proto, 'entries')))){
      // create collection constructor
      C = isWeak
        ? function(iterable){
            assertInstance(this, C, NAME);
            set(this, UID, uid++);
            initFromIterable(this, iterable);
          }
        : function(iterable){
            var that = this;
            assertInstance(that, C, NAME);
            set(that, O1, create(null));
            set(that, SIZE, 0);
            set(that, LAST, undefined);
            set(that, FIRST, undefined);
            initFromIterable(that, iterable);
          };
      assignHidden(assignHidden(C[PROTOTYPE], methods), commonMethods);
      isWeak || defineProperty(C[PROTOTYPE], 'size', {get: function(){
        return assertDefined(this[SIZE]);
      }});
    } else {
      var Native = C
        , inst   = new C
        , chain  = inst[ADDER](isWeak ? {} : -0, 1)
        , buggyZero;
      // wrap to init collections from iterable
      if(!NATIVE_ITERATORS || !C.length){
        C = function(iterable){
          assertInstance(this, C, NAME);
          return initFromIterable(new Native, iterable);
        }
        C[PROTOTYPE] = proto;
        if(framework)proto[CONSTRUCTOR] = C;
      }
      isWeak || inst[FOR_EACH](function(val, key){
        buggyZero = 1 / key === -Infinity;
      });
      // fix converting -0 key to +0
      if(buggyZero){
        fixSVZ('delete');
        fixSVZ('has');
        isMap && fixSVZ('get');
      }
      // + fix .add & .set for chaining
      if(buggyZero || chain !== inst)fixSVZ(ADDER, true);
    }
    setToStringTag(C, NAME);
    setSpecies(C);

    O[NAME] = C;
    $define(GLOBAL + WRAP + FORCED * !isNative(C), O);

    // add .keys, .values, .entries, [@@iterator]
    // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11
    isWeak || defineStdIterators(C, NAME, function(iterated, kind){
      set(this, ITER, {o: iterated, k: kind});
    }, function(){
      var iter  = this[ITER]
        , kind  = iter.k
        , entry = iter.l;
      // revert to the last existing entry
      while(entry && entry.r)entry = entry.p;
      // get next entry
      if(!iter.o || !(iter.l = entry = entry ? entry.n : iter.o[FIRST])){
        // or finish the iteration
        return iter.o = undefined, iterResult(1);
      }
      // return step by kind
      if(kind == KEY)  return iterResult(0, entry.k);
      if(kind == VALUE)return iterResult(0, entry.v);
                       return iterResult(0, [entry.k, entry.v]);
    }, isMap ? KEY+VALUE : VALUE, !isMap);

    return C;
  }

  function fastKey(it, create){
    // return primitive with prefix
    if(!isObject(it))return (typeof it == 'string' ? 'S' : 'P') + it;
    // can't set id to frozen object
    if(isFrozen(it))return 'F';
    if(!has(it, UID)){
      // not necessary to add id
      if(!create)return 'E';
      // add missing object id
      hidden(it, UID, ++uid);
    // return object id with prefix
    } return 'O' + it[UID];
  }
  function getEntry(that, key){
    // fast case
    var index = fastKey(key), entry;
    if(index != 'F')return that[O1][index];
    // frozen object case
    for(entry = that[FIRST]; entry; entry = entry.n){
      if(entry.k == key)return entry;
    }
  }
  function def(that, key, value){
    var entry = getEntry(that, key)
      , prev, index;
    // change existing entry
    if(entry)entry.v = value;
    // create new entry
    else {
      that[LAST] = entry = {
        i: index = fastKey(key, true), // <- index
        k: key,                        // <- key
        v: value,                      // <- value
        p: prev = that[LAST],          // <- previous entry
        n: undefined,                  // <- next entry
        r: false                       // <- removed
      };
      if(!that[FIRST])that[FIRST] = entry;
      if(prev)prev.n = entry;
      that[SIZE]++;
      // add to index
      if(index != 'F')that[O1][index] = entry;
    } return that;
  }

  var collectionMethods = {
    // 23.1.3.1 Map.prototype.clear()
    // 23.2.3.2 Set.prototype.clear()
    clear: function(){
      for(var that = this, data = that[O1], entry = that[FIRST]; entry; entry = entry.n){
        entry.r = true;
        entry.p = entry.n = undefined;
        delete data[entry.i];
      }
      that[FIRST] = that[LAST] = undefined;
      that[SIZE] = 0;
    },
    // 23.1.3.3 Map.prototype.delete(key)
    // 23.2.3.4 Set.prototype.delete(value)
    'delete': function(key){
      var that  = this
        , entry = getEntry(that, key);
      if(entry){
        var next = entry.n
          , prev = entry.p;
        delete that[O1][entry.i];
        entry.r = true;
        if(prev)prev.n = next;
        if(next)next.p = prev;
        if(that[FIRST] == entry)that[FIRST] = next;
        if(that[LAST] == entry)that[LAST] = prev;
        that[SIZE]--;
      } return !!entry;
    },
    // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
    // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
    forEach: function(callbackfn /*, that = undefined */){
      var f = ctx(callbackfn, arguments[1], 3)
        , entry;
      while(entry = entry ? entry.n : this[FIRST]){
        f(entry.v, entry.k, this);
        // revert to the last existing entry
        while(entry && entry.r)entry = entry.p;
      }
    },
    // 23.1.3.7 Map.prototype.has(key)
    // 23.2.3.7 Set.prototype.has(value)
    has: function(key){
      return !!getEntry(this, key);
    }
  }

  // 23.1 Map Objects
  Map = getCollection(Map, MAP, {
    // 23.1.3.6 Map.prototype.get(key)
    get: function(key){
      var entry = getEntry(this, key);
      return entry && entry.v;
    },
    // 23.1.3.9 Map.prototype.set(key, value)
    set: function(key, value){
      return def(this, key === 0 ? 0 : key, value);
    }
  }, collectionMethods, true);

  // 23.2 Set Objects
  Set = getCollection(Set, SET, {
    // 23.2.3.1 Set.prototype.add(value)
    add: function(value){
      return def(this, value = value === 0 ? 0 : value, value);
    }
  }, collectionMethods);

  function defWeak(that, key, value){
    if(isFrozen(assertObject(key)))leakStore(that).set(key, value);
    else {
      has(key, WEAK) || hidden(key, WEAK, {});
      key[WEAK][that[UID]] = value;
    } return that;
  }
  function leakStore(that){
    return that[LEAK] || hidden(that, LEAK, new Map)[LEAK];
  }

  var weakMethods = {
    // 23.3.3.2 WeakMap.prototype.delete(key)
    // 23.4.3.3 WeakSet.prototype.delete(value)
    'delete': function(key){
      if(!isObject(key))return false;
      if(isFrozen(key))return leakStore(this)['delete'](key);
      return has(key, WEAK) && has(key[WEAK], this[UID]) && delete key[WEAK][this[UID]];
    },
    // 23.3.3.4 WeakMap.prototype.has(key)
    // 23.4.3.4 WeakSet.prototype.has(value)
    has: function(key){
      if(!isObject(key))return false;
      if(isFrozen(key))return leakStore(this).has(key);
      return has(key, WEAK) && has(key[WEAK], this[UID]);
    }
  };

  // 23.3 WeakMap Objects
  WeakMap = getCollection(WeakMap, WEAKMAP, {
    // 23.3.3.3 WeakMap.prototype.get(key)
    get: function(key){
      if(isObject(key)){
        if(isFrozen(key))return leakStore(this).get(key);
        if(has(key, WEAK))return key[WEAK][this[UID]];
      }
    },
    // 23.3.3.5 WeakMap.prototype.set(key, value)
    set: function(key, value){
      return defWeak(this, key, value);
    }
  }, weakMethods, true, true);

  // IE11 WeakMap frozen keys fix
  if(framework && new WeakMap().set(Object.freeze(tmp), 7).get(tmp) != 7){
    forEach.call(array('delete,has,get,set'), function(key){
      var method = WeakMap[PROTOTYPE][key];
      WeakMap[PROTOTYPE][key] = function(a, b){
        // store frozen objects on leaky map
        if(isObject(a) && isFrozen(a)){
          var result = leakStore(this)[key](a, b);
          return key == 'set' ? this : result;
        // store all the rest on native weakmap
        } return method.call(this, a, b);
      };
    });
  }

  // 23.4 WeakSet Objects
  WeakSet = getCollection(WeakSet, WEAKSET, {
    // 23.4.3.1 WeakSet.prototype.add(value)
    add: function(value){
      return defWeak(this, value, true);
    }
  }, weakMethods, false, true);
}();<commit_msg>fix 6to5/6to5#713<commit_after>// ECMAScript 6 collections shim
!function(){
  var UID   = safeSymbol('uid')
    , O1    = safeSymbol('O1')
    , WEAK  = safeSymbol('weak')
    , LEAK  = safeSymbol('leak')
    , LAST  = safeSymbol('last')
    , FIRST = safeSymbol('first')
    , SIZE  = DESC ? safeSymbol('size') : 'size'
    , uid   = 0
    , tmp   = {};

  function getCollection(C, NAME, methods, commonMethods, isMap, isWeak){
    var ADDER = isMap ? 'set' : 'add'
      , proto = C && C[PROTOTYPE]
      , O     = {};
    function initFromIterable(that, iterable){
      if(iterable != undefined)forOf(iterable, isMap, that[ADDER], that);
      return that;
    }
    function fixSVZ(key, chain){
      var method = proto[key];
      if(framework)proto[key] = function(a, b){
        var result = method.call(this, a === 0 ? 0 : a, b);
        return chain ? this : result;
      };
    }
    if(!isNative(C) || !(isWeak || (!BUGGY_ITERATORS && has(proto, FOR_EACH) && has(proto, 'entries')))){
      // create collection constructor
      C = isWeak
        ? function(iterable){
            assertInstance(this, C, NAME);
            set(this, UID, uid++);
            initFromIterable(this, iterable);
          }
        : function(iterable){
            var that = this;
            assertInstance(that, C, NAME);
            set(that, O1, create(null));
            set(that, SIZE, 0);
            set(that, LAST, undefined);
            set(that, FIRST, undefined);
            initFromIterable(that, iterable);
          };
      assignHidden(assignHidden(C[PROTOTYPE], methods), commonMethods);
      isWeak || defineProperty(C[PROTOTYPE], 'size', {get: function(){
        return assertDefined(this[SIZE]);
      }});
    } else {
      var Native = C
        , inst   = new C
        , chain  = inst[ADDER](isWeak ? {} : -0, 1)
        , buggyZero;
      // wrap to init collections from iterable
      if(!NATIVE_ITERATORS || !C.length){
        C = function(iterable){
          assertInstance(this, C, NAME);
          return initFromIterable(new Native, iterable);
        }
        C[PROTOTYPE] = proto;
        if(framework)proto[CONSTRUCTOR] = C;
      }
      isWeak || inst[FOR_EACH](function(val, key){
        buggyZero = 1 / key === -Infinity;
      });
      // fix converting -0 key to +0
      if(buggyZero){
        fixSVZ('delete');
        fixSVZ('has');
        isMap && fixSVZ('get');
      }
      // + fix .add & .set for chaining
      if(buggyZero || chain !== inst)fixSVZ(ADDER, true);
    }
    setToStringTag(C, NAME);
    setSpecies(C);

    O[NAME] = C;
    $define(GLOBAL + WRAP + FORCED * !isNative(C), O);

    // add .keys, .values, .entries, [@@iterator]
    // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11
    isWeak || defineStdIterators(C, NAME, function(iterated, kind){
      set(this, ITER, {o: iterated, k: kind});
    }, function(){
      var iter  = this[ITER]
        , kind  = iter.k
        , entry = iter.l;
      // revert to the last existing entry
      while(entry && entry.r)entry = entry.p;
      // get next entry
      if(!iter.o || !(iter.l = entry = entry ? entry.n : iter.o[FIRST])){
        // or finish the iteration
        return iter.o = undefined, iterResult(1);
      }
      // return step by kind
      if(kind == KEY)  return iterResult(0, entry.k);
      if(kind == VALUE)return iterResult(0, entry.v);
                       return iterResult(0, [entry.k, entry.v]);
    }, isMap ? KEY+VALUE : VALUE, !isMap);

    return C;
  }

  function fastKey(it, create){
    // return primitive with prefix
    if(!isObject(it))return (typeof it == 'string' ? 'S' : 'P') + it;
    // can't set id to frozen object
    if(isFrozen(it))return 'F';
    if(!has(it, UID)){
      // not necessary to add id
      if(!create)return 'E';
      // add missing object id
      hidden(it, UID, ++uid);
    // return object id with prefix
    } return 'O' + it[UID];
  }
  function getEntry(that, key){
    // fast case
    var index = fastKey(key), entry;
    if(index != 'F')return that[O1][index];
    // frozen object case
    for(entry = that[FIRST]; entry; entry = entry.n){
      if(entry.k == key)return entry;
    }
  }
  function def(that, key, value){
    var entry = getEntry(that, key)
      , prev, index;
    // change existing entry
    if(entry)entry.v = value;
    // create new entry
    else {
      that[LAST] = entry = {
        i: index = fastKey(key, true), // <- index
        k: key,                        // <- key
        v: value,                      // <- value
        p: prev = that[LAST],          // <- previous entry
        n: undefined,                  // <- next entry
        r: false                       // <- removed
      };
      if(!that[FIRST])that[FIRST] = entry;
      if(prev)prev.n = entry;
      that[SIZE]++;
      // add to index
      if(index != 'F')that[O1][index] = entry;
    } return that;
  }

  var collectionMethods = {
    // 23.1.3.1 Map.prototype.clear()
    // 23.2.3.2 Set.prototype.clear()
    clear: function(){
      for(var that = this, data = that[O1], entry = that[FIRST]; entry; entry = entry.n){
        entry.r = true;
        if(entry.p)entry.p = entry.p.n = undefined;
        delete data[entry.i];
      }
      that[FIRST] = that[LAST] = undefined;
      that[SIZE] = 0;
    },
    // 23.1.3.3 Map.prototype.delete(key)
    // 23.2.3.4 Set.prototype.delete(value)
    'delete': function(key){
      var that  = this
        , entry = getEntry(that, key);
      if(entry){
        var next = entry.n
          , prev = entry.p;
        delete that[O1][entry.i];
        entry.r = true;
        if(prev)prev.n = next;
        if(next)next.p = prev;
        if(that[FIRST] == entry)that[FIRST] = next;
        if(that[LAST] == entry)that[LAST] = prev;
        that[SIZE]--;
      } return !!entry;
    },
    // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
    // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
    forEach: function(callbackfn /*, that = undefined */){
      var f = ctx(callbackfn, arguments[1], 3)
        , entry;
      while(entry = entry ? entry.n : this[FIRST]){
        f(entry.v, entry.k, this);
        // revert to the last existing entry
        while(entry && entry.r)entry = entry.p;
      }
    },
    // 23.1.3.7 Map.prototype.has(key)
    // 23.2.3.7 Set.prototype.has(value)
    has: function(key){
      return !!getEntry(this, key);
    }
  }

  // 23.1 Map Objects
  Map = getCollection(Map, MAP, {
    // 23.1.3.6 Map.prototype.get(key)
    get: function(key){
      var entry = getEntry(this, key);
      return entry && entry.v;
    },
    // 23.1.3.9 Map.prototype.set(key, value)
    set: function(key, value){
      return def(this, key === 0 ? 0 : key, value);
    }
  }, collectionMethods, true);

  // 23.2 Set Objects
  Set = getCollection(Set, SET, {
    // 23.2.3.1 Set.prototype.add(value)
    add: function(value){
      return def(this, value = value === 0 ? 0 : value, value);
    }
  }, collectionMethods);

  function defWeak(that, key, value){
    if(isFrozen(assertObject(key)))leakStore(that).set(key, value);
    else {
      has(key, WEAK) || hidden(key, WEAK, {});
      key[WEAK][that[UID]] = value;
    } return that;
  }
  function leakStore(that){
    return that[LEAK] || hidden(that, LEAK, new Map)[LEAK];
  }

  var weakMethods = {
    // 23.3.3.2 WeakMap.prototype.delete(key)
    // 23.4.3.3 WeakSet.prototype.delete(value)
    'delete': function(key){
      if(!isObject(key))return false;
      if(isFrozen(key))return leakStore(this)['delete'](key);
      return has(key, WEAK) && has(key[WEAK], this[UID]) && delete key[WEAK][this[UID]];
    },
    // 23.3.3.4 WeakMap.prototype.has(key)
    // 23.4.3.4 WeakSet.prototype.has(value)
    has: function(key){
      if(!isObject(key))return false;
      if(isFrozen(key))return leakStore(this).has(key);
      return has(key, WEAK) && has(key[WEAK], this[UID]);
    }
  };

  // 23.3 WeakMap Objects
  WeakMap = getCollection(WeakMap, WEAKMAP, {
    // 23.3.3.3 WeakMap.prototype.get(key)
    get: function(key){
      if(isObject(key)){
        if(isFrozen(key))return leakStore(this).get(key);
        if(has(key, WEAK))return key[WEAK][this[UID]];
      }
    },
    // 23.3.3.5 WeakMap.prototype.set(key, value)
    set: function(key, value){
      return defWeak(this, key, value);
    }
  }, weakMethods, true, true);

  // IE11 WeakMap frozen keys fix
  if(framework && new WeakMap().set(Object.freeze(tmp), 7).get(tmp) != 7){
    forEach.call(array('delete,has,get,set'), function(key){
      var method = WeakMap[PROTOTYPE][key];
      WeakMap[PROTOTYPE][key] = function(a, b){
        // store frozen objects on leaky map
        if(isObject(a) && isFrozen(a)){
          var result = leakStore(this)[key](a, b);
          return key == 'set' ? this : result;
        // store all the rest on native weakmap
        } return method.call(this, a, b);
      };
    });
  }

  // 23.4 WeakSet Objects
  WeakSet = getCollection(WeakSet, WEAKSET, {
    // 23.4.3.1 WeakSet.prototype.add(value)
    add: function(value){
      return defWeak(this, value, true);
    }
  }, weakMethods, false, true);
}();<|endoftext|>


<commit_before>/*
const defaultTracksState = {
  "0": {
    selected: false,
    title: "Llama Whipping Intro",
    artist: "DJ Mike Llama",
    duration: "5",
    url: ""
  },
  "1": {
    selected: false,
    title: "Rock Is Dead",
    artist: "Marilyn Manson",
    duration: "191", // 3:11
    url: ""
  },
  "2": {
    selected: true,
    title: "Spybreak! (Short One)",
    artist: "Propellerheads",
    duration: "240", // 4:00
    url: ""
  },
  "3": {
    selected: false,
    title: "Bad Blood",
    artist: "Ministry",
    duration: "300", // 5:00
    url: ""
  }
};
*/

const fs = require("fs");
const puppeteer = require("puppeteer");
const Filehound = require("filehound");
const JSZip = require("jszip");
const md5File = require("md5-file");

const validateZip = u =>
  new Promise((resolve, reject) => {
    fs.readFile(u, (err, buffer) => {
      JSZip.loadAsync(buffer).then(resolve, reject);
    });
  });

const config = {
  playlist: true,
  hideAbout: true,
  audioUrl: null,
  initialState: {
    equalizer: {
      sliders: {
        "60": 52,
        "170": 74,
        "310": 83,
        "600": 91,
        "1000": 74,
        "3000": 54,
        "6000": 23,
        "12000": 19,
        "14000": 34,
        "16000": 75,
        preamp: 56
      }
    },
    media: {
      status: "PLAYING",
      kbps: 128,
      khz: 44,
      length: 5,
      timeElapsed: 1,
      channels: 2,
      name: "1. DJ Mike Llama - Llama Whippin' Intro"
    },
    display: {
      working: false
    }
  }
};

(async () => {
  const files = await Filehound.create()
    .ext("wsz")
    .paths("skins/")
    .find();

  const browser = await puppeteer.launch();

  for (const skin of files) {
    const skinMd5 = md5File.sync(skin);
    const screenshotFile = `screenshots/${skin.replace(
      /\//g,
      "-"
    )}-${skinMd5}.png`;
    const skinUrl = `experiments/automatedScreenshots/${skin}`;
    console.log("Going to try", screenshotFile);
    try {
      await validateZip(`./${skin}`);
    } catch (e) {
      console.log("Error parsing", skinUrl, e);
      continue;
    }
    if (fs.existsSync(screenshotFile)) {
      console.log(screenshotFile, "exists already");
      continue;
    }
    const page = await browser.newPage();
    page.setViewport({ width: 275, height: 116 * 3 });
    page.on("console", (...args) => {
      console.log("PAGE LOG:", ...args);
    });
    config.skinUrl = skinUrl;
    const url = `http://localhost:8080/#${JSON.stringify(config)}`;
    console.log({ url });
    await page["goto"](url);
    await page.waitForSelector("#main-window", { timeout: 2000 });

    console.log("Writing screenshot to", screenshotFile);
    await page.screenshot({ path: screenshotFile });
    await page.close();
  }
  browser.close();
})();
<commit_msg>Improve screenshot tracks<commit_after>const defaultTracksState = {
  "0": {
    selected: false,
    title: "Llama Whipping Intro",
    artist: "DJ Mike Llama",
    duration: "5",
    url: ""
  },
  "1": {
    selected: false,
    title: "Rock Is Dead",
    artist: "Marilyn Manson",
    duration: "191", // 3:11
    url: ""
  },
  "2": {
    selected: true,
    title: "Spybreak! (Short One)",
    artist: "Propellerheads",
    duration: "240", // 4:00
    url: ""
  },
  "3": {
    selected: false,
    title: "Bad Blood",
    artist: "Ministry",
    duration: "300", // 5:00
    url: ""
  }
};

const fs = require("fs");
const puppeteer = require("puppeteer");
const Filehound = require("filehound");
const JSZip = require("jszip");
const md5File = require("md5-file");

const validateZip = u =>
  new Promise((resolve, reject) => {
    fs.readFile(u, (err, buffer) => {
      JSZip.loadAsync(buffer).then(resolve, reject);
    });
  });

const config = {
  playlist: true,
  hideAbout: true,
  audioUrl: null,
  initialState: {
    equalizer: {
      sliders: {
        "60": 52,
        "170": 74,
        "310": 83,
        "600": 91,
        "1000": 74,
        "3000": 54,
        "6000": 23,
        "12000": 19,
        "14000": 34,
        "16000": 75,
        preamp: 56
      }
    },
    media: {
      status: "PLAYING",
      kbps: 128,
      khz: 44,
      length: 5,
      timeElapsed: 1,
      channels: 2,
      name: "1. DJ Mike Llama - Llama Whippin' Intro"
    },
    playlist: {
      tracks: defaultTracksState,
      trackOrder: [0, 1, 2, 3],
      currentTrack: 0
    },
    display: {
      working: false
    }
  }
};

(async () => {
  const files = await Filehound.create()
    .ext("wsz")
    .paths("skins/")
    .find();

  const browser = await puppeteer.launch();

  for (const skin of files) {
    const skinMd5 = md5File.sync(skin);
    const screenshotFile = `screenshots/${skin.replace(
      /\//g,
      "-"
    )}-${skinMd5}.png`;
    const skinUrl = `experiments/automatedScreenshots/${skin}`;
    console.log("Going to try", screenshotFile);
    try {
      await validateZip(`./${skin}`);
    } catch (e) {
      console.log("Error parsing", skinUrl, e);
      continue;
    }
    if (fs.existsSync(screenshotFile)) {
      console.log(screenshotFile, "exists already");
      continue;
    }
    const page = await browser.newPage();
    page.setViewport({ width: 275, height: 116 * 3 });
    page.on("console", (...args) => {
      console.log("PAGE LOG:", ...args);
    });
    config.skinUrl = skinUrl;
    const url = `http://localhost:8080/#${JSON.stringify(config)}`;
    console.log({ url });
    await page["goto"](url);
    await page.waitForSelector("#main-window", { timeout: 2000 });

    console.log("Writing screenshot to", screenshotFile);
    await page.screenshot({ path: screenshotFile });
    await page.close();
  }
  browser.close();
})();
<|endoftext|>


<commit_before>/**
 * These function convert params captured from the URL by React Router into
 * an `endpoint` and `params` that will be used to make a call to the Meetup
 * API
 *
 * @module apiConfigCreators
 */

/**
 * For the home/Find page - always uses the self/home endpoint
 */
export function home(params) {
	params.fields = params.fields ? `${params.fields},photo_gradient` : 'photo_gradient';
	return {
		endpoint: 'self/home',
		params
	};
}

/**
 * all the group-related endpoints
 */
export function group(params) {
	params.fields = params.fields ? `${params.fields},photo_gradient` : 'photo_gradient';
	const endpoint = params.self ? 'self/groups' : params.urlname;
	return {
		endpoint,
		params
	};
}

/**
 * group communication endpoints
 *
 * accepts an `apiMethod` property in params:
 * 	`apiMethod: 'followers' - return followers for a given conversation id
 * 	`apiMethod: 'suggested_members' - return suggested_members for a given conversation id
 * 	`apiMethod: 'invite' - POST invitation
 * 	`apiMethod: 'follow' - POST follow
 * 	`apiMethod: 'unfollow' - POST unfollow
 */
export function mugcomm(params) {
	const { urlname, conversationId, apiMethod } = params;

	const endpoint = [
		urlname,
		'conversations',
		conversationId,
		apiMethod
	]
		.filter(urlFragment => urlFragment) // only inlcude populated fragments
		.join('/');

	return {
		endpoint,
		params
	}
}

/**
 * all the endpoints that return event objects
 */
export function event(params) {
	params.fields = ['rsvp_sample'];
	const pathExtension = params.id ? `/${params.id}` : '';
	return {
		endpoint: `${params.urlname}/events${pathExtension}`,
		params
	};
}

/**
 * member object endpoints
 *
 * Note, this is different than 'Profiles' which are used to represent the
 * group-specific profile informat for a member within a group context
 */
export function member(params) {
	return {
		endpoint: `2/member/${params.id}`,
		params
	};
}

/**
 * login endpoint - 'sessions/'
 */
export function login(params) {
	return {
		endpoint: 'sessions',
		params
	};
}

<commit_msg>update endpoint name; add comments for POST endpoints<commit_after>/**
 * These function convert params captured from the URL by React Router into
 * an `endpoint` and `params` that will be used to make a call to the Meetup
 * API
 *
 * @module apiConfigCreators
 */

/**
 * For the home/Find page - always uses the self/home endpoint
 */
export function home(params) {
	params.fields = params.fields ? `${params.fields},photo_gradient` : 'photo_gradient';
	return {
		endpoint: 'self/home',
		params
	};
}

/**
 * all the group-related endpoints
 */
export function group(params) {
	params.fields = params.fields ? `${params.fields},photo_gradient` : 'photo_gradient';
	const endpoint = params.self ? 'self/groups' : params.urlname;
	return {
		endpoint,
		params
	};
}

/**
 * group communication endpoints
 *
 * accepts an `apiMethod` property in params:
 * 	`apiMethod: 'followers' - return followers for a given conversation id
 * 	`apiMethod: 'suggested_members' - return suggested_members for a given conversation id
 * 	`apiMethod: 'invite' - POST invitation
 * 	`apiMethod: 'follow' - POST follow
 * 	`apiMethod: 'unfollow' - POST unfollow
 */
export function groupCommunication(params) {
	const { urlname, conversationId, apiMethod } = params;

	const endpoint = [
		urlname,
		'conversations',
		conversationId,
		apiMethod
	]
		.filter(urlFragment => urlFragment) // only inlcude populated fragments
		.join('/');

	return {
		endpoint,
		params
	}
}

/**
 * all the endpoints that return event objects
 */
export function event(params) {
	params.fields = ['rsvp_sample'];
	const pathExtension = params.id ? `/${params.id}` : '';
	return {
		endpoint: `${params.urlname}/events${pathExtension}`,
		params
	};
}

/**
 * member object endpoints
 *
 * Note, this is different than 'Profiles' which are used to represent the
 * group-specific profile informat for a member within a group context
 */
export function member(params) {
	return {
		endpoint: `2/member/${params.id}`,
		params
	};
}

/**
 * login endpoint - 'sessions/'
 */
export function login(params) {
	return {
		endpoint: 'sessions',
		params
	};
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

export default Ember.Route.extend(AuthenticatedRouteMixin, {
  controllerName: 'client/register',
  actions: {
    create: function(model) {
      return model.save().then(
        () =>
          this.controllerFor('client.register').set('registrationSuccess', true)
        );
    },
    cancel: function() {
      this.transitionTo('clients');
      return true;
    },
    registerDone: function () {
      this.transitionTo('clients');
      return true;
    }
  },
  setupController: function(controller, model) {
    controller.set('model', model);
  },
  model: function() {
    return this.store.createRecord('client', {});
  },
  deactivate: function() {
    var model = this.controllerFor('client.register').get('model');
    model.rollbackAttributes();
  },
  error: function(/*error , transition*/) {
    // if there is an error fetching the client list
    // then for now just invalidate the session
    this.get('session').invalidate();
  }
});
<commit_msg>fix(register): fix client registration<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

export default Ember.Route.extend(AuthenticatedRouteMixin, {
  controllerName: 'client/register',
  actions: {
    create: function(model) {
      return model.save().then(
        () =>
          this.controllerFor('client.register').set('registrationSuccess', true)
        );
    },
    cancel: function() {
      this.transitionTo('clients');
      return true;
    },
    registerDone: function () {
      this.transitionTo('clients');
      return true;
    }
  },
  setupController: function(controller, model) {
    controller.set('model', model);
  },
  model: function() {
    this.controllerFor('client.register').set('registrationSuccess', false);
    return this.store.createRecord('client', {});
  },
  deactivate: function() {
    var model = this.controllerFor('client.register').get('model');
    model.rollbackAttributes();
  },
  error: function(/*error , transition*/) {
    // if there is an error fetching the client list
    // then for now just invalidate the session
    this.get('session').invalidate();
  }
});
<|endoftext|>


<commit_before>/// <reference path="../base/base.js" />
/// <reference path="../base/app.js" />
/// <reference path="../base/util.js" />

FlashBuy.listaAnuncios = {
    init: function () {
        //método para fazer a listagem
        FlashBuy.listaAnuncios.carregarAnuncios(function () {
            FlashBuy.util.configurarRotasControllers();
        });
        console.log('listaAnuncios init');
    },
    ready: function () {
        console.log('listaAnuncios ready');
    },
    //metodo para comunicar com o web service
    carregarAnuncios: function (cb) {
        $.get('http://189.16.45.2/flashbuywebapi/api/Ofertas/GetOferta')
        .success(function (data) {
            console.info('proxy ok!');
            console.log(data);
            htmlTemplate = FlashBuy.util.getHtml('views/listaAnunciosTemplate.html');

            data.forEach(function (model) {
                //Valida se tem imagem
                if (model.imgMime === null) {
                    model.imgMime = "../img/semImagem.png";
                }

                var htmlRenderizado = FlashBuy.util.templateHtml(htmlTemplate, model);

                $('#divOferta').append(htmlRenderizado);
            });

            if (cb) {
                cb();
            }
        })
        .error(function () {
            console.error(arguments);
        });
    }
};<commit_msg>Troquei o parametro cb da listaAnuncios por configurarRotasControllers.<commit_after>/// <reference path="../base/base.js" />
/// <reference path="../base/app.js" />
/// <reference path="../base/util.js" />

FlashBuy.listaAnuncios = {
    init: function () {
        //método para fazer a listagem
        FlashBuy.listaAnuncios.carregarAnuncios(function () {
            FlashBuy.util.configurarRotasControllers();
        });
        console.log('listaAnuncios init');
    },
    ready: function () {
        console.log('listaAnuncios ready');
    },
    //metodo para comunicar com o web service
    carregarAnuncios: function (configurarRotasControllers) {
        $.get('http://189.16.45.2/flashbuywebapi/api/Ofertas/GetOferta')
        .success(function (data) {
            console.info('proxy ok!');
            console.log(data);
            htmlTemplate = FlashBuy.util.getHtml('views/listaAnunciosTemplate.html');

            data.forEach(function (model) {
                //Valida se tem imagem
                if (model.imgMime === null) {
                    model.imgMime = "../img/semImagem.png";
                }

                var htmlRenderizado = FlashBuy.util.templateHtml(htmlTemplate, model);

                $('#divOferta').append(htmlRenderizado);
            });

            if (configurarRotasControllers) {
                configurarRotasControllers();
            }
        })
        .error(function () {
            console.error(arguments);
        });
    }
};<|endoftext|>


<commit_before>var tl = require('vso-task-lib');
var fs = require('fs')

var wrapperScript = tl.getPathInput('wrapperScript', true, true);
fs.chmodSync(wrapperScript, "755"); //Make sure the wrapper script is executable
var gb = new tl.ToolRunner(wrapperScript);

var options = tl.getInput('options');
if (options) {
    gb.arg(options);
}

var tasks = tl.getInput('tasks', true);
if (tasks) {
    gb.arg(tasks);
}

// update JAVA_HOME if user selected specific JDK version
var jdkVersion = tl.getInput('jdkVersion');
var jdkArchitecture = tl.getInput('jdkArchitecture');
if(jdkVersion != 'default') {
  // jdkVersion should be in the form of 1.7, 1.8, or 1.10
  // jdkArchitecture is either x64 or x86
  // envName for version 1.7 and x64 would be "JAVA_HOME_7_X64"
  var envName = "JAVA_HOME_" + jdkVersion.slice(2) + "_" + jdkArchitecture.toUpperCase();
  var specifiedJavaHome = tl.getVariable(envName);
  if (!specifiedJavaHome) {
    tl.error('Failed to find specified JDK version.  Please make sure environment varialbe ' + envName + ' exists and is set to a valid JDK.');
    tl.exit(1);
   }

   tl.debug('Set JAVA_HOME to ' + specifiedJavaHome);
   process.env['JAVA_HOME'] = specifiedJavaHome;
}

var publishJUnitResults = tl.getInput('publishJUnitResults');
var testResultsFiles = tl.getInput('testResultsFiles', true);

function publishTestResults(publishJUnitResults, testResultsFiles) {
  if(publishJUnitResults == 'true') {
    //check for pattern in testResultsFiles
    if(testResultsFiles.indexOf('*') >= 0 || testResultsFiles.indexOf('?') >= 0) {
      tl.debug('Pattern found in testResultsFiles parameter');
      var buildFolder = tl.getVariable('agent.buildDirectory');
      var allFiles = tl.find(buildFolder);
      var matchingTestResultsFiles = tl.match(allFiles, testResultsFiles, { matchBase: true });
    }
    else {
      tl.debug('No pattern found in testResultsFiles parameter');
      var matchingTestResultsFiles = [testResultsFiles];
    }

    if(!matchingTestResultsFiles) {
      tl.warning('No test result files matching ' + testResultsFiles + ' were found, so publishing JUnit test results is being skipped.');
      return 0;
    }

    var tp = new tl.TestPublisher("JUnit");
    tp.publish(matchingTestResultsFiles, false, "", "");
  }
}

gb.exec()
.then(function(code) {
    publishTestResults(publishJUnitResults, testResultsFiles);
    tl.exit(code);
})
.fail(function(err) {
    publishTestResults(publishJUnitResults, testResultsFiles);
    tl.debug('taskRunner fail');
    tl.exit(1);
})
<commit_msg>handle cwd in gradle task<commit_after>var tl = require('vso-task-lib');
var fs = require('fs');
var path = require('path');

var wrapperScript = tl.getPathInput('wrapperScript', true, true);
fs.chmodSync(wrapperScript, "755"); //Make sure the wrapper script is executable

//working directory
var cwd = tl.getInput('cwd');
if(!cwd) {
  cwd = path.dirname(wrapperScript);
}
tl.cd(cwd);

var gb = new tl.ToolRunner(wrapperScript);

var options = tl.getInput('options');
if (options) {
    gb.arg(options);
}

var tasks = tl.getInput('tasks', true);
if (tasks) {
    gb.arg(tasks);
}

// update JAVA_HOME if user selected specific JDK version
var jdkVersion = tl.getInput('jdkVersion');
var jdkArchitecture = tl.getInput('jdkArchitecture');
if(jdkVersion != 'default') {
  // jdkVersion should be in the form of 1.7, 1.8, or 1.10
  // jdkArchitecture is either x64 or x86
  // envName for version 1.7 and x64 would be "JAVA_HOME_7_X64"
  var envName = "JAVA_HOME_" + jdkVersion.slice(2) + "_" + jdkArchitecture.toUpperCase();
  var specifiedJavaHome = tl.getVariable(envName);
  if (!specifiedJavaHome) {
    tl.error('Failed to find specified JDK version.  Please make sure environment varialbe ' + envName + ' exists and is set to a valid JDK.');
    tl.exit(1);
   }

   tl.debug('Set JAVA_HOME to ' + specifiedJavaHome);
   process.env['JAVA_HOME'] = specifiedJavaHome;
}

var publishJUnitResults = tl.getInput('publishJUnitResults');
var testResultsFiles = tl.getInput('testResultsFiles', true);

function publishTestResults(publishJUnitResults, testResultsFiles) {
  if(publishJUnitResults == 'true') {
    //check for pattern in testResultsFiles
    if(testResultsFiles.indexOf('*') >= 0 || testResultsFiles.indexOf('?') >= 0) {
      tl.debug('Pattern found in testResultsFiles parameter');
      var buildFolder = tl.getVariable('agent.buildDirectory');
      var allFiles = tl.find(buildFolder);
      var matchingTestResultsFiles = tl.match(allFiles, testResultsFiles, { matchBase: true });
    }
    else {
      tl.debug('No pattern found in testResultsFiles parameter');
      var matchingTestResultsFiles = [testResultsFiles];
    }

    if(!matchingTestResultsFiles) {
      tl.warning('No test result files matching ' + testResultsFiles + ' were found, so publishing JUnit test results is being skipped.');
      return 0;
    }

    var tp = new tl.TestPublisher("JUnit");
    tp.publish(matchingTestResultsFiles, false, "", "");
  }
}

gb.exec()
.then(function(code) {
    publishTestResults(publishJUnitResults, testResultsFiles);
    tl.exit(code);
})
.fail(function(err) {
    publishTestResults(publishJUnitResults, testResultsFiles);
    tl.debug('taskRunner fail');
    tl.exit(1);
})
<|endoftext|>


<commit_before>// Copyright 2009 the V8 project authors. 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 of Google Inc. 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
// OWNER OR CONTRIBUTORS 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.

var $JSON = global.JSON;

function ParseJSONUnfiltered(text) {
  var s = $String(text);
  var f = %CompileString(s, true);
  return f();
}

function Revive(holder, name, reviver) {
  var val = holder[name];
  if (IS_OBJECT(val)) {
    if (IS_ARRAY(val)) {
      var length = val.length;
      for (var i = 0; i < length; i++) {
        var newElement = Revive(val, $String(i), reviver);
        val[i] = newElement;
      }
    } else {
      for (var p in val) {
        if (ObjectHasOwnProperty.call(val, p)) {
          var newElement = Revive(val, p, reviver);
          if (IS_UNDEFINED(newElement)) {
            delete val[p];
          } else {
            val[p] = newElement;
          }
        }
      }
    }
  }
  return reviver.call(holder, name, val);
}

function JSONParse(text, reviver) {
  var unfiltered = ParseJSONUnfiltered(text);
  if (IS_FUNCTION(reviver)) {
    return Revive({'': unfiltered}, '', reviver);
  } else {
    return unfiltered;
  }
}

var characterQuoteCache = {
  '\b': '\\b',  // ASCII 8, Backspace
  '\t': '\\t',  // ASCII 9, Tab
  '\n': '\\n',  // ASCII 10, Newline
  '\f': '\\f',  // ASCII 12, Formfeed
  '\r': '\\r',  // ASCII 13, Carriage Return
  '\"': '\\"',
  '/': '\\/'
};

function QuoteSingleJSONCharacter(c) {
  if (c in characterQuoteCache) {
    return characterQuoteCache[c];
  }
  var charCode = c.charCodeAt(0);
  var result;
  if (charCode < 16) result = '\\u000';
  else if (charCode < 256) result = '\\u00';
  else if (charCode < 4096) result = '\\u0';
  else result = '\\u';
  result += charCode.toString(16);
  characterQuoteCache[c] = result;
  return result;
}

function QuoteJSONString(str) {
  var quotable = /[\\\"\x00-\x1f]/g;
  return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"';
}

function StackContains(stack, val) {
  var length = stack.length;
  for (var i = 0; i < length; i++) {
    if (stack[i] === val) {
      return true;
    }
  }
  return false;
}

function SerializeArray(value, replacer, stack, indent, gap) {
  if (StackContains(stack, value)) {
    throw MakeTypeError('circular_structure', []);
  }
  stack.push(value);
  var stepback = indent;
  indent += gap;
  var partial = [];
  var len = value.length;
  for (var i = 0; i < len; i++) {
    var strP = JSONSerialize($String(i), value, replacer, stack,
                             indent, gap);
    if (IS_UNDEFINED(strP)) {
      strP = "null";
    }
    partial.push(strP);
  }
  var final;
  if (gap == "") {
    final = "[" + partial.join(",") + "]";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "[\n" + indent + partial.join(separator) + "\n" +
        stepback + "]";
  } else {
    final = "[]";
  }
  stack.pop();
  return final;
}

function SerializeObject(value, replacer, stack, indent, gap) {
  if (StackContains(stack, value)) {
    throw MakeTypeError('circular_structure', []);
  }
  stack.push(value);
  var stepback = indent;
  indent += gap;
  var partial = [];
  if (IS_ARRAY(replacer)) {
    var length = replacer.length;
    for (var i = 0; i < length; i++) {
      if (ObjectHasOwnProperty.call(replacer, i)) {
        var p = replacer[i];
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  } else {
    for (var p in value) {
      if (ObjectHasOwnProperty.call(value, p)) {
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  }
  var final;
  if (gap == "") {
    final = "{" + partial.join(",") + "}";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "{\n" + indent + partial.join(separator) + "\n" +
        stepback + "}";
  } else {
    final = "{}";
  }
  stack.pop();
  return final;
}

function JSONSerialize(key, holder, replacer, stack, indent, gap) {
  var value = holder[key];
  if (IS_OBJECT(value) && value) {
    var toJSON = value.toJSON;
    if (IS_FUNCTION(toJSON)) {
      value = toJSON.call(value, key);
    }
  }
  if (IS_FUNCTION(replacer)) {
    value = replacer.call(holder, key, value);
  }
  // Unwrap value if necessary
  if (IS_OBJECT(value)) {
    if (IS_NUMBER_WRAPPER(value)) {
      value = $Number(value);
    } else if (IS_STRING_WRAPPER(value)) {
      value = $String(value);
    } else if (IS_BOOLEAN_WRAPPER(value)) {
      value =  %_ValueOf(value);
    }
  }
  switch (typeof value) {
    case "string":
      return QuoteJSONString(value);
    case "object":
      if (!value) {
        return "null";
      } else if (IS_ARRAY(value)) {
        return SerializeArray(value, replacer, stack, indent, gap);
      } else {
        return SerializeObject(value, replacer, stack, indent, gap);
      }
    case "number":
      return $isFinite(value) ? $String(value) : "null";
    case "boolean":
      return value ? "true" : "false";
  }
}

function JSONStringify(value, replacer, space) {
  var stack = [];
  var indent = "";
  if (IS_OBJECT(space)) {
    // Unwrap 'space' if it is wrapped
    if (IS_NUMBER_WRAPPER(space)) {
      space = $Number(space);
    } else if (IS_STRING_WRAPPER(space)) {
      space = $String(space);
    }
  }
  var gap;
  if (IS_NUMBER(space)) {
    space = $Math.min(ToInteger(space), 10);
    gap = "";
    for (var i = 0; i < space; i++) {
      gap += " ";
    }
  } else if (IS_STRING(space)) {
    if (space.length > 10) {
      gap = space.substring(0, 10);
    } else {
      gap = space;
    }
  } else {
    gap = "";
  }
  return JSONSerialize('', {'': value}, replacer, stack, indent, gap);
}

function SetupJSON() {
  InstallFunctions($JSON, DONT_ENUM, $Array(
    "parse", JSONParse,
    "stringify", JSONStringify
  ));
}

SetupJSON();
<commit_msg>Fix bug in JSON character quote table.<commit_after>// Copyright 2009 the V8 project authors. 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 of Google Inc. 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
// OWNER OR CONTRIBUTORS 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.

var $JSON = global.JSON;

function ParseJSONUnfiltered(text) {
  var s = $String(text);
  var f = %CompileString(s, true);
  return f();
}

function Revive(holder, name, reviver) {
  var val = holder[name];
  if (IS_OBJECT(val)) {
    if (IS_ARRAY(val)) {
      var length = val.length;
      for (var i = 0; i < length; i++) {
        var newElement = Revive(val, $String(i), reviver);
        val[i] = newElement;
      }
    } else {
      for (var p in val) {
        if (ObjectHasOwnProperty.call(val, p)) {
          var newElement = Revive(val, p, reviver);
          if (IS_UNDEFINED(newElement)) {
            delete val[p];
          } else {
            val[p] = newElement;
          }
        }
      }
    }
  }
  return reviver.call(holder, name, val);
}

function JSONParse(text, reviver) {
  var unfiltered = ParseJSONUnfiltered(text);
  if (IS_FUNCTION(reviver)) {
    return Revive({'': unfiltered}, '', reviver);
  } else {
    return unfiltered;
  }
}

var characterQuoteCache = {
  '\b': '\\b',  // ASCII 8, Backspace
  '\t': '\\t',  // ASCII 9, Tab
  '\n': '\\n',  // ASCII 10, Newline
  '\f': '\\f',  // ASCII 12, Formfeed
  '\r': '\\r',  // ASCII 13, Carriage Return
  '\"': '\\"',
  '\\': '\\\\'
};

function QuoteSingleJSONCharacter(c) {
  if (c in characterQuoteCache) {
    return characterQuoteCache[c];
  }
  var charCode = c.charCodeAt(0);
  var result;
  if (charCode < 16) result = '\\u000';
  else if (charCode < 256) result = '\\u00';
  else if (charCode < 4096) result = '\\u0';
  else result = '\\u';
  result += charCode.toString(16);
  characterQuoteCache[c] = result;
  return result;
}

function QuoteJSONString(str) {
  var quotable = /[\\\"\x00-\x1f]/g;
  return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"';
}

function StackContains(stack, val) {
  var length = stack.length;
  for (var i = 0; i < length; i++) {
    if (stack[i] === val) {
      return true;
    }
  }
  return false;
}

function SerializeArray(value, replacer, stack, indent, gap) {
  if (StackContains(stack, value)) {
    throw MakeTypeError('circular_structure', []);
  }
  stack.push(value);
  var stepback = indent;
  indent += gap;
  var partial = [];
  var len = value.length;
  for (var i = 0; i < len; i++) {
    var strP = JSONSerialize($String(i), value, replacer, stack,
                             indent, gap);
    if (IS_UNDEFINED(strP)) {
      strP = "null";
    }
    partial.push(strP);
  }
  var final;
  if (gap == "") {
    final = "[" + partial.join(",") + "]";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "[\n" + indent + partial.join(separator) + "\n" +
        stepback + "]";
  } else {
    final = "[]";
  }
  stack.pop();
  return final;
}

function SerializeObject(value, replacer, stack, indent, gap) {
  if (StackContains(stack, value)) {
    throw MakeTypeError('circular_structure', []);
  }
  stack.push(value);
  var stepback = indent;
  indent += gap;
  var partial = [];
  if (IS_ARRAY(replacer)) {
    var length = replacer.length;
    for (var i = 0; i < length; i++) {
      if (ObjectHasOwnProperty.call(replacer, i)) {
        var p = replacer[i];
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  } else {
    for (var p in value) {
      if (ObjectHasOwnProperty.call(value, p)) {
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  }
  var final;
  if (gap == "") {
    final = "{" + partial.join(",") + "}";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "{\n" + indent + partial.join(separator) + "\n" +
        stepback + "}";
  } else {
    final = "{}";
  }
  stack.pop();
  return final;
}

function JSONSerialize(key, holder, replacer, stack, indent, gap) {
  var value = holder[key];
  if (IS_OBJECT(value) && value) {
    var toJSON = value.toJSON;
    if (IS_FUNCTION(toJSON)) {
      value = toJSON.call(value, key);
    }
  }
  if (IS_FUNCTION(replacer)) {
    value = replacer.call(holder, key, value);
  }
  // Unwrap value if necessary
  if (IS_OBJECT(value)) {
    if (IS_NUMBER_WRAPPER(value)) {
      value = $Number(value);
    } else if (IS_STRING_WRAPPER(value)) {
      value = $String(value);
    } else if (IS_BOOLEAN_WRAPPER(value)) {
      value =  %_ValueOf(value);
    }
  }
  switch (typeof value) {
    case "string":
      return QuoteJSONString(value);
    case "object":
      if (!value) {
        return "null";
      } else if (IS_ARRAY(value)) {
        return SerializeArray(value, replacer, stack, indent, gap);
      } else {
        return SerializeObject(value, replacer, stack, indent, gap);
      }
    case "number":
      return $isFinite(value) ? $String(value) : "null";
    case "boolean":
      return value ? "true" : "false";
  }
}

function JSONStringify(value, replacer, space) {
  var stack = [];
  var indent = "";
  if (IS_OBJECT(space)) {
    // Unwrap 'space' if it is wrapped
    if (IS_NUMBER_WRAPPER(space)) {
      space = $Number(space);
    } else if (IS_STRING_WRAPPER(space)) {
      space = $String(space);
    }
  }
  var gap;
  if (IS_NUMBER(space)) {
    space = $Math.min(ToInteger(space), 10);
    gap = "";
    for (var i = 0; i < space; i++) {
      gap += " ";
    }
  } else if (IS_STRING(space)) {
    if (space.length > 10) {
      gap = space.substring(0, 10);
    } else {
      gap = space;
    }
  } else {
    gap = "";
  }
  return JSONSerialize('', {'': value}, replacer, stack, indent, gap);
}

function SetupJSON() {
  InstallFunctions($JSON, DONT_ENUM, $Array(
    "parse", JSONParse,
    "stringify", JSONStringify
  ));
}

SetupJSON();
<|endoftext|>


<commit_before>ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/strings.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/scratch.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/misc.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/local.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/jscript.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/browser.js');
$(".box-head > .buttons").append('
Scratch Boost
');
var inf = "";
function info() {
    if (inf === "") {
        inf = $("#info").html();
        $("#info").html('

Scratch Boost Info

Scratch Boost by: iwotastic

');
      }else{
        $("#info").html(inf);
        inf = "";
    }
}
<commit_msg>Update installer.js<commit_after>ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/strings.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/scratch.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/misc.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/local.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/jscript.js');
ScratchExtensions.loadExternalJS('https://raw.githubusercontent.com/Iwotastic/Scratch-Boost/master/src/browser.js');
$(".box-head > .buttons").append('
Scratch Boost
');
var inf = "";
function info() {
    if (inf === "") {
        inf = $("#info").html();
        $("#info").html('

Scratch Boost Info

Scratch Boost by: Iwotastic
View on GitHub
View Scratch discussion topic

');
      }else{
        $("#info").html(inf);
        inf = "";
    }
}
<|endoftext|>