<commit_before>// Native
const { resolve } = require('path')

// Packages
const flatten = require('arr-flatten')
const ignore = require('ignore')
const dockerignore = require('@zeit/dockerignore')
const _glob = require('glob')
const { stat, readdir, readFile } = require('fs-extra')

// Utilities
const IGNORED = require('./ignored')
const uniqueStrings = require('./unique-strings')
const getLocalConfigPath = require('../../../config/local-path')

const glob = async function(pattern, options) {
  return new Promise((resolve, reject) => {
    _glob(pattern, options, (error, files) => {
      if (error) {
        reject(error)
      } else {
        resolve(files)
      }
    })
  })
}

/**
 * Will recursivly walk through a directory and return an array of the files found within.
 * @param {string} dir the directory to walk
 * @param {string} path the path to this directory
 * @param {Array[string]} filelist a list of files so far identified
 * @param {Object} options
 *  - `output` {Object} "output" helper object
 * @returns {Array}
 */
const walkSync = async (dir, path, filelist = [], { output } = {}) => {
  const { debug } = output
  const dirc = await readdir(asAbsolute(dir, path))
  for (let file of dirc) {
    file = asAbsolute(file, dir)
    try {
      const file_stat = await stat(file)
      filelist = file_stat.isDirectory()
        ? await walkSync(file, path, filelist, { output })
        : filelist.concat(file)
    } catch (e) {
      debug(`Ignoring invalid file ${file}`)
    }
  }
  return filelist
}

/**
 * Will return an array containing the expaneded list of all files included in the whitelist.
 * @param {Array[string]} whitelist array of files and directories to include.
 * @param {string} path the path of the deployment.
 * @param {Object} options
 *  - `output` {Object} "output" helper object
 * @returns {Array} the expanded list of whitelisted files.
 */
const getFilesInWhitelist = async function(
  whitelist,
  path,
  { output } = {}
) {
  const { debug } = output
  let files = []

  await Promise.all(
    whitelist.map(async file => {
      file = asAbsolute(file, path)
      try {
        const file_stat = await stat(file)
        if (file_stat.isDirectory()) {
          const dir_files = await walkSync(file, path, [], { output })
          files.push(...dir_files)
        } else {
          files.push(file)
        }
      } catch (e) {
        debug(`Ignoring invalid file ${file}`)
      }
    })
  )
  return files
}

/**
 * Remove leading `./` from the beginning of ignores
 * because ignore doesn't like them :|
 */

const clearRelative = function(str) {
  return str.replace(/(\n|^)\.\//g, '$1')
}

/**
 * Returns the contents of a file if it exists.
 *
 * @return {String} results or `''`
 */

const maybeRead = async function(path, default_ = '') {
  try {
    return await readFile(path, 'utf8')
  } catch (err) {
    return default_
  }
}

/**
 * Transform relative paths into absolutes,
 * and maintains absolutes as such.
 *
 * @param {String} maybe relative path
 * @param {String} parent full path
 */

const asAbsolute = function(path, parent) {
  if (path[0] === '/') {
    return path
  }

  return resolve(parent, path)
}

/**
 * Returns a list of files in the given
 * directory that are subject to be
 * synchronized for static deployments.
 *
 * @param {String} full path to directory
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} comprehensive list of paths to sync
 */

async function staticFiles(
  path,
  nowConfig = {},
  { limit = null, output } = {}
) {
  const { debug, time } = output
  let files = []

  if (nowConfig.files && Array.isArray(nowConfig.files)) {
    files = await getFilesInWhitelist(nowConfig.files, path, { output })
  } else {
    // The package.json `files` whitelist still
    // honors ignores: https://docs.npmjs.com/files/package.json#files
    const search_ = ['.']
    // Convert all filenames into absolute paths
    const search = Array.prototype.concat.apply(
      [],
      await Promise.all(
        search_.map(file =>
          glob(file, { cwd: path, absolute: true, dot: true })
        )
      )
    )

    // Compile list of ignored patterns and files
    const gitIgnore = await maybeRead(resolve(path, '.gitignore'))

    const filter = ignore()
      .add(IGNORED + '\n' + clearRelative(gitIgnore))
      .add([ 'now.json', 'package.json', 'Dockerfile' ])
      .createFilter()

    const prefixLength = path.length + 1

    // The package.json `files` whitelist still
    // honors npmignores: https://docs.npmjs.com/files/package.json#files
    // but we don't ignore if the user is explicitly listing files
    // under the now namespace, or using files in combination with gitignore
    const accepts = file => {
      const relativePath = file.substr(prefixLength)

      if (relativePath === '') {
        return true
      }

      const accepted = filter(relativePath)

      if (!accepted) {
        debug(`Ignoring ${file}`)
      }

      return accepted
    }

    // Locate files
    files = await time(
      `Locating files ${path}`,
      explode(search, {
        accepts,
        limit,
        output
      })
    )
  }

  // Get files
  return uniqueStrings(files)
}

/**
 * Returns a list of files in the given
 * directory that are subject to be
 * synchronized for npm.
 *
 * @param {String} full path to directory
 * @param {String} contents of `package.json` to avoid lookup
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} comprehensive list of paths to sync
 */

async function npm(
  path,
  pkg = {},
  nowConfig = {},
  { limit = null, hasNowJson = false, output } = {}
) {
  const { debug, time } = output
  const whitelist = nowConfig.files || pkg.files || (pkg.now && pkg.now.files)
  let files = []

  if (whitelist) {
    files = await getFilesInWhitelist(whitelist, path, { output })
  } else {
    // The package.json `files` whitelist still
    // honors ignores: https://docs.npmjs.com/files/package.json#files
    const search_ = ['.']
    // Convert all filenames into absolute paths
    const search = Array.prototype.concat.apply(
      [],
      await Promise.all(
        search_.map(file =>
          glob(file, { cwd: path, absolute: true, dot: true })
        )
      )
    )

    // Compile list of ignored patterns and files
    const npmIgnore = await maybeRead(resolve(path, '.npmignore'), null)
    const gitIgnore =
      npmIgnore === null ? await maybeRead(resolve(path, '.gitignore')) : null

    const filter = ignore()
      .add(
        IGNORED +
          '\n' +
          clearRelative(npmIgnore === null ? gitIgnore : npmIgnore)
      )
      .createFilter()

    const prefixLength = path.length + 1

    // The package.json `files` whitelist still
    // honors npmignores: https://docs.npmjs.com/files/package.json#files
    // but we don't ignore if the user is explicitly listing files
    // under the now namespace, or using files in combination with gitignore
    const overrideIgnores =
      (pkg.now && pkg.now.files) ||
      nowConfig.files ||
      (gitIgnore !== null && pkg.files)
    const accepts = overrideIgnores
      ? () => true
      : file => {
          const relativePath = file.substr(prefixLength)

          if (relativePath === '') {
            return true
          }

          const accepted = filter(relativePath)
          if (!accepted) {
            debug(`Ignoring ${file}`)
          }
          return accepted
        }

    // Locate files
    files = await time(
      `Locating files ${path}`,
      explode(search, {
        accepts,
        limit,
        output
      })
    )
  }

  // Always include manifest as npm does not allow ignoring it
  // source: https://docs.npmjs.com/files/package.json#files
  files.push(asAbsolute('package.json', path))

  if (hasNowJson) {
    files.push(asAbsolute(getLocalConfigPath(path), path))
  }

  // Get files
  return uniqueStrings(files)
}

/**
 * Returns a list of files in the given
 * directory that are subject to be
 * sent to docker as build context.
 *
 * @param {String} full path to directory
 * @param {String} contents of `Dockerfile`
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} comprehensive list of paths to sync
 */

async function docker(
  path,
  nowConfig = {},
  { limit = null, hasNowJson = false, output } = {}
) {
  const { debug, time } = output
  let files = []

  if (nowConfig.files) {
    files = await getFilesInWhitelist(nowConfig.files, path, { output })
  } else {
    // Base search path
    // the now.json `files` whitelist still
    // honors ignores: https://docs.npmjs.com/files/package.json#files
    const search_ = ['.']

    // Convert all filenames into absolute paths
    const search = search_.map(file => asAbsolute(file, path))

    // Compile list of ignored patterns and files
    const dockerIgnore = await maybeRead(resolve(path, '.dockerignore'), null)

    const ignoredFiles = clearRelative(
      dockerIgnore === null
        ? await maybeRead(resolve(path, '.gitignore'))
        : dockerIgnore
    )

    const filter = (dockerIgnore === null ? ignore : dockerignore)()
      .add(IGNORED + '\n' + ignoredFiles)
      .createFilter()

    const prefixLength = path.length + 1
    const accepts = function(file) {
      const relativePath = file.substr(prefixLength)

      if (relativePath === '') {
        return true
      }

      const accepted = filter(relativePath)
      if (!accepted) {
        debug(`Ignoring ${file}`)
      }
      return accepted
    }

    // Locate files
    files = await time(
      `Locating files ${path}`,
      explode(search, { accepts, limit, output })
    )
  }

  if (hasNowJson) {
    files.push(asAbsolute(getLocalConfigPath(path), path))
  }

  // Always include manifest as npm does not allow ignoring it
  // source: https://docs.npmjs.com/files/package.json#files
  files.push(asAbsolute('Dockerfile', path))

  // Get files
  return uniqueStrings(files)
}

/**
 * Explodes directories into a full list of files.
 * Eg:
 *   in:  ['/a.js', '/b']
 *   out: ['/a.js', '/b/c.js', '/b/d.js']
 *
 * @param {Array} of {String}s representing paths
 * @param {Array} of ignored {String}s.
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} of {String}s of full paths
 */

async function explode(paths, { accepts, output }) {
  const { debug } = output
  const list = async file => {
    let path = file
    let s

    if (!accepts(file)) {
      return null
    }

    try {
      s = await stat(path)
    } catch (e) {
      // In case the file comes from `files`
      // and it wasn't specified with `.js` by the user
      path = file + '.js'

      try {
        s = await stat(path)
      } catch (e2) {
        debug(`Ignoring invalid file ${file}`)
        return null
      }
    }

    if (s.isDirectory()) {
      const all = await readdir(file)
      /* eslint-disable no-use-before-define */
      return many(all.map(subdir => asAbsolute(subdir, file)))
      /* eslint-enable no-use-before-define */
    } else if (!s.isFile()) {
      debug(`Ignoring special file ${file}`)
      return null
    }

    return path
  }

  const many = all => Promise.all(all.map(file => list(file)))
  return flatten(await many(paths)).filter(v => v !== null)
}

module.exports = {
  npm,
  docker,
  staticFiles
}
<commit_msg>Upload the Dockerfile if it's a static deployment. (#1437)<commit_after>// Native
const { resolve } = require('path')

// Packages
const flatten = require('arr-flatten')
const ignore = require('ignore')
const dockerignore = require('@zeit/dockerignore')
const _glob = require('glob')
const { stat, readdir, readFile } = require('fs-extra')

// Utilities
const IGNORED = require('./ignored')
const uniqueStrings = require('./unique-strings')
const getLocalConfigPath = require('../../../config/local-path')

const glob = async function(pattern, options) {
  return new Promise((resolve, reject) => {
    _glob(pattern, options, (error, files) => {
      if (error) {
        reject(error)
      } else {
        resolve(files)
      }
    })
  })
}

/**
 * Will recursivly walk through a directory and return an array of the files found within.
 * @param {string} dir the directory to walk
 * @param {string} path the path to this directory
 * @param {Array[string]} filelist a list of files so far identified
 * @param {Object} options
 *  - `output` {Object} "output" helper object
 * @returns {Array}
 */
const walkSync = async (dir, path, filelist = [], { output } = {}) => {
  const { debug } = output
  const dirc = await readdir(asAbsolute(dir, path))
  for (let file of dirc) {
    file = asAbsolute(file, dir)
    try {
      const file_stat = await stat(file)
      filelist = file_stat.isDirectory()
        ? await walkSync(file, path, filelist, { output })
        : filelist.concat(file)
    } catch (e) {
      debug(`Ignoring invalid file ${file}`)
    }
  }
  return filelist
}

/**
 * Will return an array containing the expaneded list of all files included in the whitelist.
 * @param {Array[string]} whitelist array of files and directories to include.
 * @param {string} path the path of the deployment.
 * @param {Object} options
 *  - `output` {Object} "output" helper object
 * @returns {Array} the expanded list of whitelisted files.
 */
const getFilesInWhitelist = async function(
  whitelist,
  path,
  { output } = {}
) {
  const { debug } = output
  let files = []

  await Promise.all(
    whitelist.map(async file => {
      file = asAbsolute(file, path)
      try {
        const file_stat = await stat(file)
        if (file_stat.isDirectory()) {
          const dir_files = await walkSync(file, path, [], { output })
          files.push(...dir_files)
        } else {
          files.push(file)
        }
      } catch (e) {
        debug(`Ignoring invalid file ${file}`)
      }
    })
  )
  return files
}

/**
 * Remove leading `./` from the beginning of ignores
 * because ignore doesn't like them :|
 */

const clearRelative = function(str) {
  return str.replace(/(\n|^)\.\//g, '$1')
}

/**
 * Returns the contents of a file if it exists.
 *
 * @return {String} results or `''`
 */

const maybeRead = async function(path, default_ = '') {
  try {
    return await readFile(path, 'utf8')
  } catch (err) {
    return default_
  }
}

/**
 * Transform relative paths into absolutes,
 * and maintains absolutes as such.
 *
 * @param {String} maybe relative path
 * @param {String} parent full path
 */

const asAbsolute = function(path, parent) {
  if (path[0] === '/') {
    return path
  }

  return resolve(parent, path)
}

/**
 * Returns a list of files in the given
 * directory that are subject to be
 * synchronized for static deployments.
 *
 * @param {String} full path to directory
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} comprehensive list of paths to sync
 */

async function staticFiles(
  path,
  nowConfig = {},
  { limit = null, output } = {}
) {
  const { debug, time } = output
  let files = []

  if (nowConfig.files && Array.isArray(nowConfig.files)) {
    files = await getFilesInWhitelist(nowConfig.files, path, { output })
  } else {
    // The package.json `files` whitelist still
    // honors ignores: https://docs.npmjs.com/files/package.json#files
    const search_ = ['.']
    // Convert all filenames into absolute paths
    const search = Array.prototype.concat.apply(
      [],
      await Promise.all(
        search_.map(file =>
          glob(file, { cwd: path, absolute: true, dot: true })
        )
      )
    )

    // Compile list of ignored patterns and files
    const gitIgnore = await maybeRead(resolve(path, '.gitignore'))

    const filter = ignore()
      .add(IGNORED + '\n' + clearRelative(gitIgnore))
      .add([ 'now.json' ])
      .createFilter()

    const prefixLength = path.length + 1

    // The package.json `files` whitelist still
    // honors npmignores: https://docs.npmjs.com/files/package.json#files
    // but we don't ignore if the user is explicitly listing files
    // under the now namespace, or using files in combination with gitignore
    const accepts = file => {
      const relativePath = file.substr(prefixLength)

      if (relativePath === '') {
        return true
      }

      const accepted = filter(relativePath)

      if (!accepted) {
        debug(`Ignoring ${file}`)
      }

      return accepted
    }

    // Locate files
    files = await time(
      `Locating files ${path}`,
      explode(search, {
        accepts,
        limit,
        output
      })
    )
  }

  // Get files
  return uniqueStrings(files)
}

/**
 * Returns a list of files in the given
 * directory that are subject to be
 * synchronized for npm.
 *
 * @param {String} full path to directory
 * @param {String} contents of `package.json` to avoid lookup
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} comprehensive list of paths to sync
 */

async function npm(
  path,
  pkg = {},
  nowConfig = {},
  { limit = null, hasNowJson = false, output } = {}
) {
  const { debug, time } = output
  const whitelist = nowConfig.files || pkg.files || (pkg.now && pkg.now.files)
  let files = []

  if (whitelist) {
    files = await getFilesInWhitelist(whitelist, path, { output })
  } else {
    // The package.json `files` whitelist still
    // honors ignores: https://docs.npmjs.com/files/package.json#files
    const search_ = ['.']
    // Convert all filenames into absolute paths
    const search = Array.prototype.concat.apply(
      [],
      await Promise.all(
        search_.map(file =>
          glob(file, { cwd: path, absolute: true, dot: true })
        )
      )
    )

    // Compile list of ignored patterns and files
    const npmIgnore = await maybeRead(resolve(path, '.npmignore'), null)
    const gitIgnore =
      npmIgnore === null ? await maybeRead(resolve(path, '.gitignore')) : null

    const filter = ignore()
      .add(
        IGNORED +
          '\n' +
          clearRelative(npmIgnore === null ? gitIgnore : npmIgnore)
      )
      .createFilter()

    const prefixLength = path.length + 1

    // The package.json `files` whitelist still
    // honors npmignores: https://docs.npmjs.com/files/package.json#files
    // but we don't ignore if the user is explicitly listing files
    // under the now namespace, or using files in combination with gitignore
    const overrideIgnores =
      (pkg.now && pkg.now.files) ||
      nowConfig.files ||
      (gitIgnore !== null && pkg.files)
    const accepts = overrideIgnores
      ? () => true
      : file => {
          const relativePath = file.substr(prefixLength)

          if (relativePath === '') {
            return true
          }

          const accepted = filter(relativePath)
          if (!accepted) {
            debug(`Ignoring ${file}`)
          }
          return accepted
        }

    // Locate files
    files = await time(
      `Locating files ${path}`,
      explode(search, {
        accepts,
        limit,
        output
      })
    )
  }

  // Always include manifest as npm does not allow ignoring it
  // source: https://docs.npmjs.com/files/package.json#files
  files.push(asAbsolute('package.json', path))

  if (hasNowJson) {
    files.push(asAbsolute(getLocalConfigPath(path), path))
  }

  // Get files
  return uniqueStrings(files)
}

/**
 * Returns a list of files in the given
 * directory that are subject to be
 * sent to docker as build context.
 *
 * @param {String} full path to directory
 * @param {String} contents of `Dockerfile`
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} comprehensive list of paths to sync
 */

async function docker(
  path,
  nowConfig = {},
  { limit = null, hasNowJson = false, output } = {}
) {
  const { debug, time } = output
  let files = []

  if (nowConfig.files) {
    files = await getFilesInWhitelist(nowConfig.files, path, { output })
  } else {
    // Base search path
    // the now.json `files` whitelist still
    // honors ignores: https://docs.npmjs.com/files/package.json#files
    const search_ = ['.']

    // Convert all filenames into absolute paths
    const search = search_.map(file => asAbsolute(file, path))

    // Compile list of ignored patterns and files
    const dockerIgnore = await maybeRead(resolve(path, '.dockerignore'), null)

    const ignoredFiles = clearRelative(
      dockerIgnore === null
        ? await maybeRead(resolve(path, '.gitignore'))
        : dockerIgnore
    )

    const filter = (dockerIgnore === null ? ignore : dockerignore)()
      .add(IGNORED + '\n' + ignoredFiles)
      .createFilter()

    const prefixLength = path.length + 1
    const accepts = function(file) {
      const relativePath = file.substr(prefixLength)

      if (relativePath === '') {
        return true
      }

      const accepted = filter(relativePath)
      if (!accepted) {
        debug(`Ignoring ${file}`)
      }
      return accepted
    }

    // Locate files
    files = await time(
      `Locating files ${path}`,
      explode(search, { accepts, limit, output })
    )
  }

  if (hasNowJson) {
    files.push(asAbsolute(getLocalConfigPath(path), path))
  }

  // Always include manifest as npm does not allow ignoring it
  // source: https://docs.npmjs.com/files/package.json#files
  files.push(asAbsolute('Dockerfile', path))

  // Get files
  return uniqueStrings(files)
}

/**
 * Explodes directories into a full list of files.
 * Eg:
 *   in:  ['/a.js', '/b']
 *   out: ['/a.js', '/b/c.js', '/b/d.js']
 *
 * @param {Array} of {String}s representing paths
 * @param {Array} of ignored {String}s.
 * @param {Object} options:
 *  - `limit` {Number|null} byte limit
 *  - `output` {Object} "output" helper object
 * @return {Array} of {String}s of full paths
 */

async function explode(paths, { accepts, output }) {
  const { debug } = output
  const list = async file => {
    let path = file
    let s

    if (!accepts(file)) {
      return null
    }

    try {
      s = await stat(path)
    } catch (e) {
      // In case the file comes from `files`
      // and it wasn't specified with `.js` by the user
      path = file + '.js'

      try {
        s = await stat(path)
      } catch (e2) {
        debug(`Ignoring invalid file ${file}`)
        return null
      }
    }

    if (s.isDirectory()) {
      const all = await readdir(file)
      /* eslint-disable no-use-before-define */
      return many(all.map(subdir => asAbsolute(subdir, file)))
      /* eslint-enable no-use-before-define */
    } else if (!s.isFile()) {
      debug(`Ignoring special file ${file}`)
      return null
    }

    return path
  }

  const many = all => Promise.all(all.map(file => list(file)))
  return flatten(await many(paths)).filter(v => v !== null)
}

module.exports = {
  npm,
  docker,
  staticFiles
}
<|endoftext|>


<commit_before>import Domify from 'react-domify';
import React from 'react';
import Markdown from 'react-markdown';

const Row = (props) => {
	const styles = {
		display: 'flex',
		flexWrap: 'wrap',
		marginLeft: -10,
		marginRight: -10,
		...props.style,
	};

	return (

	);
};

const Col = (props) => {
	const styles = {
		flex: props.width ? null : '1 1 0',
		minHeight: 1,
		paddingLeft: 10,
		paddingRight: 10,
		width: props.width || '100%',
		...props.style,
	};

	return (

	);
};

const ExplorerFieldType = React.createClass({
	getInitialState () {
		return {
			readmeIsVisible: !!this.props.readme,
			filter: this.props.FilterComponent.getDefaultValue(),
			value: this.props.value,
		};
	},
	componentWillReceiveProps (newProps) {
		if (this.props.params.type === newProps.params.type) return;

		this.setState({
			filter: newProps.FilterComponent.getDefaultValue(),
			readmeIsVisible: newProps.readme
				? this.state.readmeIsVisible
				: false,
			value: newProps.value,
		});
	},
	onFieldChange (e) {
		var logValue = typeof e.value === 'string' ? `"${e.value}"` : e.value;
		console.log(`${this.props.params.type} field value changed:`, logValue);
		this.setState({
			value: e.value,
		});
	},
	onFilterChange (value) {
		console.log(`${this.props.params.type} filter value changed:`, value);
		this.setState({
			filter: value,
		});
	},
	render () {
		const { FieldComponent, FilterComponent, readme, spec } = this.props;
		const { readmeIsVisible } = this.state;

		return (

{spec.label}

					{!!readme && (
						<button
							className="fx-page__header__button mega-octicon octicon-file-text"
							onClick={() => this.setState({ readmeIsVisible: !readmeIsVisible })}
							title={readmeIsVisible ? 'Hide Readme' : 'Show Readme'}
							type="button"
						/>
					)}

					<Row>
						<Col>

									<Row>
										<Col width={300}>
											<FieldComponent
												{...spec}
												onChange={this.onFieldChange}
												value={this.state.value}
											/>
										</Col>
										<Col>

												<Domify
													className="Domify"
													value={{ value: this.state.value }}
												/>

										</Col>
									</Row>

Filter

									<Row>
										<Col width={300}>
											<FilterComponent
												field={spec}
												filter={this.state.filter}
												onChange={this.onFilterChange}
											/>
										</Col>
										<Col>

												<Domify
													className="Domify"
													value={this.state.filter}
												/>

										</Col>
									</Row>

						</Col>
						{!!readmeIsVisible && (
							<Col width={380}>
								<Markdown
									className="Markdown"
									source={readme}
								/>
							</Col>
						)}
					</Row>

		);
	},
});

const STUB_README = `
# Boolean Field

Stores a \`Boolean\` in the model.

## Methods

### \`format\`

Returns the string \`"true"\` or \`"false"\`.

### \`updateItem\`

Because \`FormData\` can only submit \`String\` values, and HTML Forms won't submit fields at all when checkbox inputs are not checked, there are a few unusual behaviours when updating Boolean fields:

* The stored value is always updated, even when \`undefined\` is provided
* Any falsy value, including \`undefined\`, \`null\`, \`false\`, \`""\` and \`0\` will store \`false\`
* The string \`"false"\` will store \`false\`
* Any other truthy string will store \`true\`
* Any truthy number will store \`true\`
* The boolean \`true\` will store \`true\`

There is no way to use \`updateItem\` to remove Boolean field values from the item.

### \`validateInput\`

Ensures the value can be interpreted using the rules above. Other complex values (objects that aren't null, dates, arrays, etc) are not valid input.

### \`validateRequiredInput\`

Ensures the value matches one of the rules above that will store \`true\`
`;

module.exports = ExplorerFieldType;
<commit_msg>fix col widths<commit_after>import Domify from 'react-domify';
import React from 'react';
import Markdown from 'react-markdown';

const Row = (props) => {
	const styles = {
		display: 'flex',
		flexWrap: 'wrap',
		marginLeft: -10,
		marginRight: -10,
		...props.style,
	};

	return (

	);
};

const Col = (props) => {
	const styles = {
		flex: props.width ? null : '1 1 0',
		minHeight: 1,
		paddingLeft: 10,
		paddingRight: 10,
		width: props.width || '100%',
		...props.style,
	};

	return (

	);
};

const ExplorerFieldType = React.createClass({
	getInitialState () {
		return {
			readmeIsVisible: !!this.props.readme,
			filter: this.props.FilterComponent.getDefaultValue(),
			value: this.props.value,
		};
	},
	componentWillReceiveProps (newProps) {
		if (this.props.params.type === newProps.params.type) return;

		this.setState({
			filter: newProps.FilterComponent.getDefaultValue(),
			readmeIsVisible: newProps.readme
				? this.state.readmeIsVisible
				: false,
			value: newProps.value,
		});
	},
	onFieldChange (e) {
		var logValue = typeof e.value === 'string' ? `"${e.value}"` : e.value;
		console.log(`${this.props.params.type} field value changed:`, logValue);
		this.setState({
			value: e.value,
		});
	},
	onFilterChange (value) {
		console.log(`${this.props.params.type} filter value changed:`, value);
		this.setState({
			filter: value,
		});
	},
	render () {
		const { FieldComponent, FilterComponent, readme, spec } = this.props;
		const { readmeIsVisible } = this.state;

		return (

{spec.label}

					{!!readme && (
						<button
							className="fx-page__header__button mega-octicon octicon-file-text"
							onClick={() => this.setState({ readmeIsVisible: !readmeIsVisible })}
							title={readmeIsVisible ? 'Hide Readme' : 'Show Readme'}
							type="button"
						/>
					)}

					<Row>
						<Col>

									<Row>
										<Col width={readmeIsVisible ? 300 : null} style={{ minWidth: 300, maxWidth: 640 }}>
											<FieldComponent
												{...spec}
												onChange={this.onFieldChange}
												value={this.state.value}
											/>
										</Col>
										<Col>

												<Domify
													className="Domify"
													value={{ value: this.state.value }}
												/>

										</Col>
									</Row>

Filter

									<Row>
										<Col width={300}>
											<FilterComponent
												field={spec}
												filter={this.state.filter}
												onChange={this.onFilterChange}
											/>
										</Col>
										<Col>

												<Domify
													className="Domify"
													value={this.state.filter}
												/>

										</Col>
									</Row>

						</Col>
						{!!readmeIsVisible && (
							<Col width={380}>
								<Markdown
									className="Markdown"
									source={readme}
								/>
							</Col>
						)}
					</Row>

		);
	},
});

const STUB_README = `
# Boolean Field

Stores a \`Boolean\` in the model.

## Methods

### \`format\`

Returns the string \`"true"\` or \`"false"\`.

### \`updateItem\`

Because \`FormData\` can only submit \`String\` values, and HTML Forms won't submit fields at all when checkbox inputs are not checked, there are a few unusual behaviours when updating Boolean fields:

* The stored value is always updated, even when \`undefined\` is provided
* Any falsy value, including \`undefined\`, \`null\`, \`false\`, \`""\` and \`0\` will store \`false\`
* The string \`"false"\` will store \`false\`
* Any other truthy string will store \`true\`
* Any truthy number will store \`true\`
* The boolean \`true\` will store \`true\`

There is no way to use \`updateItem\` to remove Boolean field values from the item.

### \`validateInput\`

Ensures the value can be interpreted using the rules above. Other complex values (objects that aren't null, dates, arrays, etc) are not valid input.

### \`validateRequiredInput\`

Ensures the value matches one of the rules above that will store \`true\`
`;

module.exports = ExplorerFieldType;
<|endoftext|>


<commit_before>// Write a callback function and add it as a 'click' event listener on each image. The callback should change the image file that is rendered inside the <img> element. I.e., when the user clicks on an image, the image changes to a different image.

//Array of image names
var imageNames = ['chocolates.jpg',
              'coffee.jpg',
              'flowers.jpg',
              'scone.jpg',
              'bread.jpg',
              'caribou.jpg',
              'cookie.jpg',
              'grapefruit.jpg',
              'jam.jpg',
              'oats.jpg',
              'oven.jpg',
              'picnic.jpg',
              'store.jpg',
              'strawberry.jpg',
              'toast.jpg'];

//Create empty array to hold image objects
images = [];

//Construct objects using images array, push to new object array
function ImgObj(src) {
  this.iName = src.split('.')[0];
  this.src = 'images/' + src;
  this.clicks = 0;
  this.shown = 0;
  this.incrementClicks = function() {
    this.clicks++;
  };
  this.incrementShown = function() {
    this.shown++;
  };
}

//Loop through all file names, construct image object, push to images array
for (var xx = 0; xx < imageNames.length; xx++){
  var img = new ImgObj(imageNames[xx]);
  images.push(img);
}

console.log(images);

//Initialize variables to hold index of what's being shown
var currentIndex1 = 0;
var currentIndex2 = 0;
var currentIndex3 = 0;
var totClicks = 0;

// return a random integer between 0 and images.length - 1
function getRand(){
  return Math.floor(Math.random() * images.length);
}

//Add event listener for each image, image text, and button
var img1 = document.getElementById('img1');
var name1 = document.getElementById('name1');
img1.addEventListener('click',changeImage1);

var img2 = document.getElementById('img2');
var name2 = document.getElementById('name2');
img2.addEventListener('click',changeImage2);

var img3 = document.getElementById('img3');
var name3 = document.getElementById('name3');
img3.addEventListener('click',changeImage3);

var results = document.getElementById('results');
results.addEventListener('click',showResults);
var canvas1 = document.getElementById('canvas1');
var canvas2 = document.getElementById('canvas2');

var moreGuesses = document.getElementById('moreGuesses');
moreGuesses.addEventListener('click',guessAgain);

var refresh = document.getElementById('refresh');
refresh.addEventListener('click',function (){ window.location.reload(false);});

//Call show image the first time (without event) to populate website with random image
showImage1(getRand());
showImage2(getRand());
showImage3(getRand());

//Listen for click event, increment when clicked
function changeImage1(){
  console.log('CLICK');
  //Increment shown property
  images[currentIndex1].incrementClicks();
  console.log(currentIndex1 + ' was clicked ' + images[currentIndex1].clicks + ' times');
  totClicks++;
  click16(totClicks);
  showImage1(getRand());
}

//Display new image, increment that it was shown
function showImage1(index){
  //Store index of current image
  currentIndex1 = index;
  //Display current image
  img1.setAttribute('src', images[index].src);
  name1.textContent = images[index].iName;
  //Increment shown property
  images[index].incrementShown();
  console.log(index + ' was shown ' + images[index].shown + ' times');
}

//Listen for click event, increment when clicked
function changeImage2(){
  console.log('CLICK');
  //Increment shown property
  images[currentIndex2].incrementClicks();
  console.log(currentIndex2 + ' was clicked ' + images[currentIndex2].clicks + ' times');
  totClicks++;
  click16(totClicks);
  showImage2(getRand());
}

//Display new image, increment that it was shown
function showImage2(index){
  //Store index of current image
  currentIndex2 = index;
  //Display current image
  img2.setAttribute('src', images[index].src);
  name2.textContent = images[index].iName;
  //Increment shown property
  images[index].incrementShown();
  console.log(index + ' was shown ' + images[index].shown + ' times');
}

//Listen for click event, increment when clicked
function changeImage3(){
  console.log('CLICK');
  //Increment shown property
  images[currentIndex3].incrementClicks();
  console.log(currentIndex3 + ' was clicked ' + images[currentIndex3].clicks + ' times');
  totClicks++;
  click16(totClicks);
  showImage3(getRand());
}

//Display new image, increment that it was shown
function showImage3(index){
  //Store index of current image
  currentIndex3 = index;
  //Display current image
  img3.setAttribute('src', images[index].src);
  name3.textContent = images[index].iName;
  //Increment shown property
  images[index].incrementShown();
  console.log(index + ' was shown ' + images[index].shown + ' times');
}

function click16(clicks){
  if (clicks === 16){
    results.style.visibility = 'visible';
    moreGuesses.style.visibility = 'visible';
    img1.removeEventListener('click',changeImage1);
    img2.removeEventListener('click',changeImage2);
    img3.removeEventListener('click',changeImage3);
  }
  else if (clicks === 24){
    showResults();
    img1.removeEventListener('click',changeImage1);
    img2.removeEventListener('click',changeImage2);
    img3.removeEventListener('click',changeImage3);
  }
}

function draw(numArray, labelArray1, labelArray2) {
  // **Shamelessly** copied from mob coding, from Chart.js documentation
  var absoluteChart = new Chart(canvas1, {
    type: 'bar',
    data: {
      labels: labelArray1,
      datasets: [{
        label: '# of Votes',
        data: numArray,
        backgroundColor: 'rgba(255,99,132,0.2)',
        borderColor: 'rgba(255,99,132,1)',
        borderWidth: 1,
        hoverBackgroundColor: 'rgba(255,99,132,0.4)',
        hoverBorderColor: 'rgba(255,99,132,1)'
      }]},
        // {
        //   type: 'line',
        //   label: 'votes/shown %',
        //   data: labelArray2
        // }]
    options: {
      scales: {
        yAxes: [{
          ticks: { beginAtZero: true }
        }]
      }
    }
  });
  var percentChart = new Chart(canvas2, {
    type: 'bar',
    data: {
      labels: labelArray1,
      datasets: [{
        label: '% of Votes given # of times Shown',
        data: labelArray2,
        backgroundColor: 'rgba(255,99,132,0.2)',
        borderColor: 'rgba(255,99,132,1)',
        borderWidth: 1,
        hoverBackgroundColor: 'rgba(255,99,132,0.4)',
        hoverBorderColor: 'rgba(255,99,132,1)'
      }]},
    //     {
    //       type: 'line',
    //       label: 'votes/shown %',
    //       data:
    //     }]
    // },
    options: {
      scales: {
        yAxes: [{
          ticks: { beginAtZero: true }
        }]
      }
    }
  });
}

function showResults() {
  console.log('show results running!');
  //Hide results and try again buttons
  results.style.visibility = 'hidden';
  moreGuesses.style.visibility = 'hidden';
  var dataClicks = [];
  var chartLabels = [];
  var percLabels = [];
  for (var ii = 0; ii < images.length; ii++) {
    dataClicks.push(images[ii].clicks);
    chartLabels.push(images[ii].iName);
    var percent = Math.round((images[ii].clicks / images[ii].shown) * 100);
    if (isNaN(percent)){
      percent = 0;
    }
    percLabels.push(percent);
  }
  console.log('Data, clicks: ' + dataClicks);
  console.log('Labels: ' + chartLabels);
  console.log('Percent of times shown: ' + percLabels);
  draw(dataClicks, chartLabels, percLabels);
  refresh.style.visibility = 'visible';
}

// Implement a callback for the "8 More Votes" button; the callback should hide all buttons, then allow 8 more votes. After the 8th extra vote, hide buttons, plot the vote histogram and show the "New Round" button.
function guessAgain(){
  results.style.visibility = 'hidden';
  moreGuesses.style.visibility = 'hidden';
  img1.addEventListener('click',changeImage1);
  img2.addEventListener('click',changeImage2);
  img3.addEventListener('click',changeImage3);
}
<commit_msg>Changes during mob coding<commit_after>// Write a callback function and add it as a 'click' event listener on each image. The callback should change the image file that is rendered inside the <img> element. I.e., when the user clicks on an image, the image changes to a different image.

//Array of image names
var imageNames = ['chocolates.jpg',
              'coffee.jpg',
              'flowers.jpg',
              'scone.jpg',
              'bread.jpg',
              'caribou.jpg',
              'cookie.jpg',
              'grapefruit.jpg',
              'jam.jpg',
              'oats.jpg',
              'oven.jpg',
              'picnic.jpg',
              'store.jpg',
              'strawberry.jpg',
              'toast.jpg'];

//Create empty array to hold image objects
images = [];

//Construct objects using images array, push to new object array
function ImgObj(src) {
  this.iName = src.split('.')[0];
  this.src = 'images/' + src;
  this.clicks = 0;
  this.shown = 0;
  this.incrementClicks = function() {
    this.clicks++;
  };
  this.incrementShown = function() {
    this.shown++;
  };
}

//Loop through all file names, construct image object, push to images array
for (var xx = 0; xx < imageNames.length; xx++){
  var img = new ImgObj(imageNames[xx]);
  images.push(img);
}

console.log(images);

//Initialize variables to hold index of what's being shown
var currentIndex1 = 0;
var currentIndex2 = 0;
var currentIndex3 = 0;
var totClicks = 0;

// return a random integer between 0 and images.length - 1
function getRand(){
  return Math.floor(Math.random() * images.length);
}

//Add event listener for each image, image text, and button
var img1 = document.getElementById('img1');
var name1 = document.getElementById('name1');
img1.addEventListener('click',changeImage1);

var img2 = document.getElementById('img2');
var name2 = document.getElementById('name2');
img2.addEventListener('click',changeImage2);

var img3 = document.getElementById('img3');
var name3 = document.getElementById('name3');
img3.addEventListener('click',changeImage3);

var results = document.getElementById('results');
results.addEventListener('click',showResults);
var canvas1 = document.getElementById('canvas1');
var canvas2 = document.getElementById('canvas2');

var moreGuesses = document.getElementById('moreGuesses');
moreGuesses.addEventListener('click',guessAgain);

var refresh = document.getElementById('refresh');
refresh.addEventListener('click',function (){ window.location.reload(false);});

//Call show image the first time (without event) to populate website with random image. Sore that index in local storage
var ri1 = localStorage.currentIndex1;
if (ri1 = false) {
  ri1 = getRand();
}
showImage1(ri1);

var ri2 = localStorage.currentIndex2;
if (ri2 = false) {
  ri2 = getRand();
}
showImage2(ri2);

var ri3 = localStorage.currentIndex3;
if (ri3 = false) {
  ri3 = getRand();
}
showImage3(ri3);

// showImage2(getRand());
// showImage3(getRand());

//Listen for click event, increment when clicked
function changeImage1(){
  console.log('CLICK');
  //Increment shown property
  images[currentIndex1].incrementClicks();
  console.log(currentIndex1 + ' was clicked ' + images[currentIndex1].clicks + ' times');
  totClicks++;
  click16(totClicks);
  showImage1(getRand());
}

//Display new image, increment that it was shown
function showImage1(index){
  //Store index of current image
  currentIndex1 = index;
  //Display current image
  img1.setAttribute('src', images[index].src);
  name1.textContent = images[index].iName;
  //Increment shown property
  images[index].incrementShown();
  console.log(index + ' was shown ' + images[index].shown + ' times');
}

//Listen for click event, increment when clicked
function changeImage2(){
  console.log('CLICK');
  //Increment shown property
  images[currentIndex2].incrementClicks();
  console.log(currentIndex2 + ' was clicked ' + images[currentIndex2].clicks + ' times');
  totClicks++;
  click16(totClicks);
  showImage2(getRand());
}

//Display new image, increment that it was shown
function showImage2(index){
  //Store index of current image
  currentIndex2 = index;
  //Display current image
  img2.setAttribute('src', images[index].src);
  name2.textContent = images[index].iName;
  //Increment shown property
  images[index].incrementShown();
  console.log(index + ' was shown ' + images[index].shown + ' times');
}

//Listen for click event, increment when clicked
function changeImage3(){
  console.log('CLICK');
  //Increment shown property
  images[currentIndex3].incrementClicks();
  //Save to local storage
  localStorage.images = JSON.stringify(images);
  console.log(currentIndex3 + ' was clicked ' + images[currentIndex3].clicks + ' times');
  //Save to local storage
  totClicks++;
  click16(totClicks);
  showImage3(getRand());
}

//Display new image, increment that it was shown
function showImage3(index){
  //Store index of current image
  currentIndex3 = index;
  //Display current image
  img3.setAttribute('src', images[index].src);
  name3.textContent = images[index].iName;
  //Increment shown property
  images[index].incrementShown();
  //Save to local storage
  localStorage.images = JSON.stringify(images);
  console.log(index + ' was shown ' + images[index].shown + ' times');
}

function click16(clicks){
  if (clicks === 16){
    results.style.visibility = 'visible';
    moreGuesses.style.visibility = 'visible';
    img1.removeEventListener('click',changeImage1);
    img2.removeEventListener('click',changeImage2);
    img3.removeEventListener('click',changeImage3);
  }
  else if (clicks === 24){
    showResults();
    img1.removeEventListener('click',changeImage1);
    img2.removeEventListener('click',changeImage2);
    img3.removeEventListener('click',changeImage3);
  }
}

function draw(numArray, labelArray1, labelArray2) {
  // **Shamelessly** copied from mob coding, from Chart.js documentation
  var absoluteChart = new Chart(canvas1, {
    type: 'bar',
    data: {
      labels: labelArray1,
      datasets: [{
        label: '# of Votes',
        data: numArray,
        backgroundColor: 'rgba(255,99,132,0.2)',
        borderColor: 'rgba(255,99,132,1)',
        borderWidth: 1,
        hoverBackgroundColor: 'rgba(255,99,132,0.4)',
        hoverBorderColor: 'rgba(255,99,132,1)'
      }]},
        // {
        //   type: 'line',
        //   label: 'votes/shown %',
        //   data: labelArray2
        // }]
    options: {
      scales: {
        yAxes: [{
          ticks: { beginAtZero: true }
        }]
      }
    }
  });
  var percentChart = new Chart(canvas2, {
    type: 'bar',
    data: {
      labels: labelArray1,
      datasets: [{
        label: '% of Votes given # of times Shown',
        data: labelArray2,
        backgroundColor: 'rgba(255,99,132,0.2)',
        borderColor: 'rgba(255,99,132,1)',
        borderWidth: 1,
        hoverBackgroundColor: 'rgba(255,99,132,0.4)',
        hoverBorderColor: 'rgba(255,99,132,1)'
      }]},
    //     {
    //       type: 'line',
    //       label: 'votes/shown %',
    //       data:
    //     }]
    // },
    options: {
      scales: {
        yAxes: [{
          ticks: { beginAtZero: true }
        }]
      }
    }
  });
}

function showResults() {
  console.log('show results running!');
  //Hide results and try again buttons
  results.style.visibility = 'hidden';
  moreGuesses.style.visibility = 'hidden';
  var dataClicks = [];
  var chartLabels = [];
  var percLabels = [];
  for (var ii = 0; ii < images.length; ii++) {
    dataClicks.push(images[ii].clicks);
    chartLabels.push(images[ii].iName);
    var percent = Math.round((images[ii].clicks / images[ii].shown) * 100);
    if (isNaN(percent)){
      percent = 0;
    }
    percLabels.push(percent);
  }
  console.log('Data, clicks: ' + dataClicks);
  console.log('Labels: ' + chartLabels);
  console.log('Percent of times shown: ' + percLabels);
  draw(dataClicks, chartLabels, percLabels);
  refresh.style.visibility = 'visible';
}

// Implement a callback for the "8 More Votes" button; the callback should hide all buttons, then allow 8 more votes. After the 8th extra vote, hide buttons, plot the vote histogram and show the "New Round" button.
function guessAgain(){
  results.style.visibility = 'hidden';
  moreGuesses.style.visibility = 'hidden';
  img1.addEventListener('click',changeImage1);
  img2.addEventListener('click',changeImage2);
  img3.addEventListener('click',changeImage3);
}
<|endoftext|>


<commit_before>'use strict';
var shell = require('shelljs');
var chalk = require('chalk');
var lodash = require('lodash');
var gitUrlParser = require('git-url-parse');
var fs = require('fs');
var async = require('async');
var globule = require('globule');

var Utils = (function () {

  var logger = {
    info: function (msg) {
      console.log(chalk.cyan(msg));
    },
    error: function (msg) {
      console.log(chalk.bold.underline.red('Error'), '\n', chalk.red(msg));
    },
    success: function (msg) {
      console.log(chalk.green(msg));
    }
  };

  function checkForGit() {
    return shell.which('git');
  }

  function gotoRootDirectory(done) {
    shell.exec('git rev-parse --show-toplevel', {silent: true, async: true}, function(exitCode, output) {
      if(exitCode){
        return done(output);
      }
      output = output.trim();
      shell.cd(output, {silent:true});
      return done(null, output);
    });
  }

  function listPackageJsonFiles(branch, base, done) {
    var listArray;
    listArray = shell.exec('git ls-tree -r ' +
      '--name-only ' + branch +
      '  | grep \'package.json\'', {
      silent: true
    })
      .output
      .trim()
      .replace(/(\r\n|\n|\r)/gm, ',')
      .split(',')
      .map(function addBasePath(path) {
        return base + '/' + path.replace('package.json', ' ').trim();
      });

    return done(null, listArray);
  }

  function directoryWithPackageJSON(output, done) {
    var files = globule.find({
      src: ['**/package.json', '!**/node_modules/**/package.json'],
      prefixBase: true,
      srcBase: output
    }).map(function (file) {
      return file.replace('package.json', ' ').trim();
    });
    return done(null, files);
  }

  function getRepoName(repoUrl) {
    return gitUrlParser(repoUrl).name;
  }

  function isUnderGitRepo() {
    return shell.exec('git rev-parse --is-inside-work-tree', {silent: true}).output;
  }

  function getCurrentBranchName() {
    return shell.exec('git rev-parse --abbrev-ref HEAD', {silent: true}).output.trim();
  }

  function checkOutToBranch(branch) {
    console.log('checking out');
    shell.exec('git checkout ' + branch, {silent: true}).output.trim();
    return branch;
  }

  function isFileExists(fileWithPath, done) {
    return fs.exists(fileWithPath, done);
  }

  function prepareArguments(args) {

    var gitOptions = lodash.omit(args, [
      '$0',
      'h',
      'help',
      '_',
      'b',
      'branch',
      'repo',
      'repository'
    ]);

    return lodash.map(gitOptions, function (value, key) {
      if (typeof value === 'boolean') {
        return key.length > 1 ? '--' + key : '-' + key;
      } else {
        return key.length > 1 ? '--' + key + ' ' + value : '-' + key + ' ' + value;
      }
    }).join(' ');
  }

  function getPackageJSONPath(branchName, cb) {
    async.waterfall([
      gotoRootDirectory,
      function listingJSONFiles(basePath, cb) {
        return listPackageJsonFiles(branchName, basePath, cb);
      }
      //directoryWithPackageJSON
    ], function (err, paths) {
      if (err) {
        return cb(err);
      }
      return cb(null, paths);
    })
  }

  return {
    isGitInstalled: checkForGit,
    isGitRepo: isUnderGitRepo,
    prepareArguments: prepareArguments,
    getRepoName: getRepoName,
    isFileExists: isFileExists,
    log: logger,
    packagePaths: getPackageJSONPath,
    checkOutBranch: checkOutToBranch,
    currentBranchName: getCurrentBranchName
  };

})();

module.exports = Utils;
<commit_msg>removed unnecessary log from utils<commit_after>'use strict';
var shell = require('shelljs');
var chalk = require('chalk');
var lodash = require('lodash');
var gitUrlParser = require('git-url-parse');
var fs = require('fs');
var async = require('async');
var globule = require('globule');

var Utils = (function () {

  var logger = {
    info: function (msg) {
      console.log(chalk.cyan(msg));
    },
    error: function (msg) {
      console.log(chalk.bold.underline.red('Error'), '\n', chalk.red(msg));
    },
    success: function (msg) {
      console.log(chalk.green(msg));
    }
  };

  function checkForGit() {
    return shell.which('git');
  }

  function gotoRootDirectory(done) {
    shell.exec('git rev-parse --show-toplevel', {silent: true, async: true}, function(exitCode, output) {
      if(exitCode){
        return done(output);
      }
      output = output.trim();
      shell.cd(output, {silent:true});
      return done(null, output);
    });
  }

  function listPackageJsonFiles(branch, base, done) {
    var listArray;
    listArray = shell.exec('git ls-tree -r ' +
      '--name-only ' + branch +
      '  | grep \'package.json\'', {
      silent: true
    })
      .output
      .trim()
      .replace(/(\r\n|\n|\r)/gm, ',')
      .split(',')
      .map(function addBasePath(path) {
        return base + '/' + path.replace('package.json', ' ').trim();
      });

    return done(null, listArray);
  }

  function directoryWithPackageJSON(output, done) {
    var files = globule.find({
      src: ['**/package.json', '!**/node_modules/**/package.json'],
      prefixBase: true,
      srcBase: output
    }).map(function (file) {
      return file.replace('package.json', ' ').trim();
    });
    return done(null, files);
  }

  function getRepoName(repoUrl) {
    return gitUrlParser(repoUrl).name;
  }

  function isUnderGitRepo() {
    return shell.exec('git rev-parse --is-inside-work-tree', {silent: true}).output;
  }

  function getCurrentBranchName() {
    return shell.exec('git rev-parse --abbrev-ref HEAD', {silent: true}).output.trim();
  }

  function checkOutToBranch(branch) {
    shell.exec('git checkout ' + branch, {silent: true}).output.trim();
    return branch;
  }

  function isFileExists(fileWithPath, done) {
    return fs.exists(fileWithPath, done);
  }

  function prepareArguments(args) {

    var gitOptions = lodash.omit(args, [
      '$0',
      'h',
      'help',
      '_',
      'b',
      'branch',
      'repo',
      'repository'
    ]);

    return lodash.map(gitOptions, function (value, key) {
      if (typeof value === 'boolean') {
        return key.length > 1 ? '--' + key : '-' + key;
      } else {
        return key.length > 1 ? '--' + key + ' ' + value : '-' + key + ' ' + value;
      }
    }).join(' ');
  }

  function getPackageJSONPath(branchName, cb) {
    async.waterfall([
      gotoRootDirectory,
      function listingJSONFiles(basePath, cb) {
        return listPackageJsonFiles(branchName, basePath, cb);
      }
      //directoryWithPackageJSON
    ], function (err, paths) {
      if (err) {
        return cb(err);
      }
      return cb(null, paths);
    })
  }

  return {
    isGitInstalled: checkForGit,
    isGitRepo: isUnderGitRepo,
    prepareArguments: prepareArguments,
    getRepoName: getRepoName,
    isFileExists: isFileExists,
    log: logger,
    packagePaths: getPackageJSONPath,
    checkOutBranch: checkOutToBranch,
    currentBranchName: getCurrentBranchName
  };

})();

module.exports = Utils;
<|endoftext|>


<commit_before>(function ($) {
  // register namespace
  $.extend(true, window, {
    "Slick": {
      "CellExternalCopyManager": CellExternalCopyManager
    }
  });

  function CellExternalCopyManager(options) {
    /*
      This manager enables users to copy/paste data from/to an external Spreadsheet application
      such as MS-Excel® or OpenOffice-Spreadsheet.

      Since it is not possible to access directly the clipboard in javascript, the plugin uses
      a trick to do it's job. After detecting the keystroke, we dynamically create a textarea
      where the browser copies/pastes the serialized data.

      options:
        copiedCellStyle : sets the css className used for copied cells. default : "copied"
        copiedCellStyleLayerKey : sets the layer key for setting css values of copied cells. default : "copy-manager"
        dataItemColumnValueExtractor : option to specify a custom column value extractor function
        dataItemColumnValueSetter : option to specify a custom column value setter function
        clipboardCommandHandler : option to specify a custom handler for paste actions
        includeHeaderWhenCopying : set to true and the plugin will take the name property from each column (which is usually what appears in your header) and put that as the first row of the text that's copied to the clipboard
        bodyElement: option to specify a custom DOM element which to will be added the hidden textbox. It's useful if the grid is inside a modal dialog.
        onCopyInit: optional handler to run when copy action initializes
        onCopySuccess: optional handler to run when copy action is complete
    */
    var _grid;
    var _self = this;
    var _copiedRanges;
    var _options = options || {};
    var _copiedCellStyleLayerKey = _options.copiedCellStyleLayerKey || "copy-manager";
    var _copiedCellStyle = _options.copiedCellStyle || "copied";
    var _clearCopyTI = 0;
    var _bodyElement = _options.bodyElement || document.body;
    var _onCopyInit = _options.onCopyInit || null;
    var _onCopySuccess = _options.onCopySuccess || null;

    var keyCodes = {
      'C': 67,
      'V': 86,
      'ESC': 27,
      'INSERT': 45
    };

    function init(grid) {
      _grid = grid;
      _grid.onKeyDown.subscribe(handleKeyDown);

      // we need a cell selection model
      var cellSelectionModel = grid.getSelectionModel();
      if (!cellSelectionModel){
        throw new Error("Selection model is mandatory for this plugin. Please set a selection model on the grid before adding this plugin: grid.setSelectionModel(new Slick.CellSelectionModel())");
      }
      // we give focus on the grid when a selection is done on it.
      // without this, if the user selects a range of cell without giving focus on a particular cell, the grid doesn't get the focus and key stroke handles (ctrl+c) don't work
      cellSelectionModel.onSelectedRangesChanged.subscribe(function(e, args){
        _grid.focus();
      });
    }

    function destroy() {
      _grid.onKeyDown.unsubscribe(handleKeyDown);
    }

    function getDataItemValueForColumn(item, columnDef) {
      if (_options.dataItemColumnValueExtractor) {
        var dataItemColumnValueExtractorValue = _options.dataItemColumnValueExtractor(item, columnDef);

        if (dataItemColumnValueExtractorValue)
          return dataItemColumnValueExtractorValue;
      }

      var retVal = '';

      // if a custom getter is not defined, we call serializeValue of the editor to serialize
      if (columnDef.editor){
        var editorArgs = {
          'container':$("<p>"),  // a dummy container
          'column':columnDef,
          'position':{'top':0, 'left':0},  // a dummy position required by some editors
          'grid':_grid
        };
        var editor = new columnDef.editor(editorArgs);
        editor.loadValue(item);
        retVal = editor.serializeValue();
        editor.destroy();
      }
      else {
        retVal = item[columnDef.field];
      }

      return retVal;
    }

    function setDataItemValueForColumn(item, columnDef, value) {
      if (_options.dataItemColumnValueSetter) {
        return _options.dataItemColumnValueSetter(item, columnDef, value);
      }

      // if a custom setter is not defined, we call applyValue of the editor to unserialize
      if (columnDef.editor){
        var editorArgs = {
          'container':$("body"),  // a dummy container
          'column':columnDef,
          'position':{'top':0, 'left':0},  // a dummy position required by some editors
          'grid':_grid
        };
        var editor = new columnDef.editor(editorArgs);
        editor.loadValue(item);
        editor.applyValue(item, value);
        editor.destroy();
      }
    }

    function _createTextBox(innerText){
      var ta = document.createElement('textarea');
      ta.style.position = 'absolute';
      ta.style.left = '-1000px';
      ta.style.top = document.body.scrollTop + 'px';
      ta.value = innerText;
      _bodyElement.appendChild(ta);
      ta.select();

      return ta;
    }

    function _decodeTabularData(_grid, ta){
      var columns = _grid.getColumns();
      var clipText = ta.value;
      var clipRows = clipText.split(/[\n\f\r]/);
	  // trim trailing CR if present
	  if (clipRows[clipRows.length - 1]=="") { clipRows.pop(); }

      var clippedRange = [];
      var j = 0;

      _bodyElement.removeChild(ta);
      for (var i=0; i<clipRows.length; i++) {
        if (clipRows[i]!="")
          clippedRange[j++] = clipRows[i].split("\t");
          else
          clippedRange[i] = [""];
      }
      var selectedCell = _grid.getActiveCell();
      var ranges = _grid.getSelectionModel().getSelectedRanges();
      var selectedRange = ranges && ranges.length ? ranges[0] : null;   // pick only one selection
      var activeRow = null;
      var activeCell = null;

      if (selectedRange){
        activeRow = selectedRange.fromRow;
        activeCell = selectedRange.fromCell;
      } else if (selectedCell){
        activeRow = selectedCell.row;
        activeCell = selectedCell.cell;
      } else {
        // we don't know where to paste
        return;
      }

      var oneCellToMultiple = false;
      var destH = clippedRange.length;
      var destW = clippedRange.length ? clippedRange[0].length : 0;
      if (clippedRange.length == 1 && clippedRange[0].length == 1 && selectedRange){
        oneCellToMultiple = true;
        destH = selectedRange.toRow - selectedRange.fromRow +1;
        destW = selectedRange.toCell - selectedRange.fromCell +1;
      }
      var availableRows = _grid.getData().length - activeRow;
      var addRows = 0;
      if(availableRows < destH)
      {
        var d = _grid.getData();
        for(addRows = 1; addRows <= destH - availableRows; addRows++)
          d.push({});
        _grid.setData(d);
        _grid.render();
      }
      var clipCommand = {

        isClipboardCommand: true,
        clippedRange: clippedRange,
        oldValues: [],
        cellExternalCopyManager: _self,
        _options: _options,
        setDataItemValueForColumn: setDataItemValueForColumn,
        markCopySelection: markCopySelection,
        oneCellToMultiple: oneCellToMultiple,
        activeRow: activeRow,
        activeCell: activeCell,
        destH: destH,
        destW: destW,
        desty: activeRow,
        destx: activeCell,
        maxDestY: _grid.getDataLength(),
        maxDestX: _grid.getColumns().length,
        h: 0,
        w: 0,

        execute: function() {
          this.h=0;
          for (var y = 0; y < destH; y++){
            this.oldValues[y] = [];
            this.w=0;
            this.h++;
            for (var x = 0; x < destW; x++){
              this.w++;
              var desty = activeRow + y;
              var destx = activeCell + x;

              if (desty < this.maxDestY && destx < this.maxDestX ) {
                var nd = _grid.getCellNode(desty, destx);
                var dt = _grid.getDataItem(desty);
                this.oldValues[y][x] = dt[columns[destx]['field']];
                if (oneCellToMultiple)
                  this.setDataItemValueForColumn(dt, columns[destx], clippedRange[0][0]);
                else
                  this.setDataItemValueForColumn(dt, columns[destx], clippedRange[y] ? clippedRange[y][x] : '');
                _grid.updateCell(desty, destx);
                _grid.onCellChange.notify({
                    row: desty,
                    cell: destx,
                    item: dt,
                    grid: _grid
                });

              }
            }
          }

          var bRange = {
            'fromCell': activeCell,
            'fromRow': activeRow,
            'toCell': activeCell+this.w-1,
            'toRow': activeRow+this.h-1
          }

          this.markCopySelection([bRange]);
          _grid.getSelectionModel().setSelectedRanges([bRange]);
          this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});
        },

        undo: function() {
          for (var y = 0; y < destH; y++){
            for (var x = 0; x < destW; x++){
              var desty = activeRow + y;
              var destx = activeCell + x;

              if (desty < this.maxDestY && destx < this.maxDestX ) {
                var nd = _grid.getCellNode(desty, destx);
                var dt = _grid.getDataItem(desty);
                if (oneCellToMultiple)
                  this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[0][0]);
                else
                  this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[y][x]);
                _grid.updateCell(desty, destx);
                _grid.onCellChange.notify({
                    row: desty,
                    cell: destx,
                    item: dt,
                    grid: _grid
                });
              }
            }
          }

          var bRange = {
            'fromCell': activeCell,
            'fromRow': activeRow,
            'toCell': activeCell+this.w-1,
            'toRow': activeRow+this.h-1
          }

          this.markCopySelection([bRange]);
          _grid.getSelectionModel().setSelectedRanges([bRange]);
          this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});

          if(addRows > 1){
            var d = _grid.getData();
            for(; addRows > 1; addRows--)
              d.splice(d.length - 1, 1);
            _grid.setData(d);
            _grid.render();
          }
        }
      };

      if(_options.clipboardCommandHandler) {
        _options.clipboardCommandHandler(clipCommand);
      }
      else {
        clipCommand.execute();
      }
    }

    function handleKeyDown(e, args) {
      var ranges;
      if (!_grid.getEditorLock().isActive() || _grid.getOptions().autoEdit) {
        if (e.which == keyCodes.ESC) {
          if (_copiedRanges) {
            e.preventDefault();
            clearCopySelection();
            _self.onCopyCancelled.notify({ranges: _copiedRanges});
            _copiedRanges = null;
          }
        }

        if ((e.which === keyCodes.C || e.which === keyCodes.INSERT) && (e.ctrlKey || e.metaKey) && !e.shiftKey) {    // CTRL+C or CTRL+INS
          if (_onCopyInit) {
            _onCopyInit.call();
          }
          ranges = _grid.getSelectionModel().getSelectedRanges();
          if (ranges.length != 0) {
            _copiedRanges = ranges;
            markCopySelection(ranges);
            _self.onCopyCells.notify({ranges: ranges});

            var columns = _grid.getColumns();
            var clipText = "";

            for (var rg = 0; rg < ranges.length; rg++){
                var range = ranges[rg];
                var clipTextRows = [];
                for (var i=range.fromRow; i< range.toRow+1 ; i++){
                    var clipTextCells = [];
                    var dt = _grid.getDataItem(i);

                    if (clipTextRows == "" && _options.includeHeaderWhenCopying) {
                        var clipTextHeaders = [];
                        for (var j = range.fromCell; j < range.toCell + 1 ; j++) {
                            if (columns[j].name.length > 0)
                                clipTextHeaders.push(columns[j].name);
                        }
                        clipTextRows.push(clipTextHeaders.join("\t"));
                    }

                    for (var j=range.fromCell; j< range.toCell+1 ; j++){
                        clipTextCells.push(getDataItemValueForColumn(dt, columns[j]));
                    }
                    clipTextRows.push(clipTextCells.join("\t"));
                }
                clipText += clipTextRows.join("\r\n") + "\r\n";
            }

            if(window.clipboardData) {
                window.clipboardData.setData("Text", clipText);
                return true;
            }
            else {
                var $focus = $(_grid.getActiveCellNode());
                var ta = _createTextBox(clipText);

                ta.focus();

                setTimeout(function(){
                     _bodyElement.removeChild(ta);
                    // restore focus
                    if ($focus && $focus.length>0) {
                        $focus.attr('tabIndex', '-1');
                        $focus.focus();
                        $focus.removeAttr('tabIndex');
                    }
                }, 100);

                if (_onCopySuccess) {
                    var rowCount = 0;
                    // If it's cell selection, use the toRow/fromRow fields
                    if (ranges.length === 1) {
                        rowCount = (ranges[0].toRow + 1) - ranges[0].fromRow;
                    }
                    else {
                        rowCount = ranges.length;
                    }
                    _onCopySuccess.call(this, rowCount);
                }

                return false;
            }
          }
        }

        if ((e.which === keyCodes.V && (e.ctrlKey || e.metaKey) && !e.shiftKey || (e.which === keyCodes.INSERT && e.shiftKey && !e.ctrlKey))) {    // CTRL+V or Shift+INS
            var ta = _createTextBox('');

            setTimeout(function(){
                _decodeTabularData(_grid, ta);
            }, 100);

            return false;
        }
      }
    }

    function markCopySelection(ranges) {
      clearCopySelection();

      var columns = _grid.getColumns();
      var hash = {};
      for (var i = 0; i < ranges.length; i++) {
        for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
          hash[j] = {};
          for (var k = ranges[i].fromCell; k <= ranges[i].toCell && k<columns.length; k++) {
            hash[j][columns[k].id] = _copiedCellStyle;
          }
        }
      }
      _grid.setCellCssStyles(_copiedCellStyleLayerKey, hash);
      clearTimeout(_clearCopyTI);
      _clearCopyTI = setTimeout(function(){
        _self.clearCopySelection();
      }, 2000);
    }

    function clearCopySelection() {
      _grid.removeCellCssStyles(_copiedCellStyleLayerKey);
    }

    $.extend(this, {
      "init": init,
      "destroy": destroy,
      "clearCopySelection": clearCopySelection,
      "handleKeyDown":handleKeyDown,

      "onCopyCells": new Slick.Event(),
      "onCopyCancelled": new Slick.Event(),
      "onPasteCells": new Slick.Event()
    });
  }
})(jQuery);
<commit_msg>Add support for adding extra rows at bottom if paste overflows<commit_after>(function ($) {
  // register namespace
  $.extend(true, window, {
    "Slick": {
      "CellExternalCopyManager": CellExternalCopyManager
    }
  });

  function CellExternalCopyManager(options) {
    /*
      This manager enables users to copy/paste data from/to an external Spreadsheet application
      such as MS-Excel® or OpenOffice-Spreadsheet.

      Since it is not possible to access directly the clipboard in javascript, the plugin uses
      a trick to do it's job. After detecting the keystroke, we dynamically create a textarea
      where the browser copies/pastes the serialized data.

      options:
        copiedCellStyle : sets the css className used for copied cells. default : "copied"
        copiedCellStyleLayerKey : sets the layer key for setting css values of copied cells. default : "copy-manager"
        dataItemColumnValueExtractor : option to specify a custom column value extractor function
        dataItemColumnValueSetter : option to specify a custom column value setter function
        clipboardCommandHandler : option to specify a custom handler for paste actions
        includeHeaderWhenCopying : set to true and the plugin will take the name property from each column (which is usually what appears in your header) and put that as the first row of the text that's copied to the clipboard
        bodyElement: option to specify a custom DOM element which to will be added the hidden textbox. It's useful if the grid is inside a modal dialog.
        onCopyInit: optional handler to run when copy action initializes
        onCopySuccess: optional handler to run when copy action is complete
        newRowCreator: function to add rows to table if paste overflows bottom of table
    */
    var _grid;
    var _self = this;
    var _copiedRanges;
    var _options = options || {};
    var _copiedCellStyleLayerKey = _options.copiedCellStyleLayerKey || "copy-manager";
    var _copiedCellStyle = _options.copiedCellStyle || "copied";
    var _clearCopyTI = 0;
    var _bodyElement = _options.bodyElement || document.body;
    var _onCopyInit = _options.onCopyInit || null;
    var _onCopySuccess = _options.onCopySuccess || null;

    var keyCodes = {
      'C': 67,
      'V': 86,
      'ESC': 27,
      'INSERT': 45
    };

    function init(grid) {
      _grid = grid;
      _grid.onKeyDown.subscribe(handleKeyDown);

      // we need a cell selection model
      var cellSelectionModel = grid.getSelectionModel();
      if (!cellSelectionModel){
        throw new Error("Selection model is mandatory for this plugin. Please set a selection model on the grid before adding this plugin: grid.setSelectionModel(new Slick.CellSelectionModel())");
      }
      // we give focus on the grid when a selection is done on it.
      // without this, if the user selects a range of cell without giving focus on a particular cell, the grid doesn't get the focus and key stroke handles (ctrl+c) don't work
      cellSelectionModel.onSelectedRangesChanged.subscribe(function(e, args){
        _grid.focus();
      });
    }

    function destroy() {
      _grid.onKeyDown.unsubscribe(handleKeyDown);
    }

    function getDataItemValueForColumn(item, columnDef) {
      if (_options.dataItemColumnValueExtractor) {
        var dataItemColumnValueExtractorValue = _options.dataItemColumnValueExtractor(item, columnDef);

        if (dataItemColumnValueExtractorValue)
          return dataItemColumnValueExtractorValue;
      }

      var retVal = '';

      // if a custom getter is not defined, we call serializeValue of the editor to serialize
      if (columnDef.editor){
        var editorArgs = {
          'container':$("<p>"),  // a dummy container
          'column':columnDef,
          'position':{'top':0, 'left':0},  // a dummy position required by some editors
          'grid':_grid
        };
        var editor = new columnDef.editor(editorArgs);
        editor.loadValue(item);
        retVal = editor.serializeValue();
        editor.destroy();
      }
      else {
        retVal = item[columnDef.field];
      }

      return retVal;
    }

    function setDataItemValueForColumn(item, columnDef, value) {
      if (_options.dataItemColumnValueSetter) {
        return _options.dataItemColumnValueSetter(item, columnDef, value);
      }

      // if a custom setter is not defined, we call applyValue of the editor to unserialize
      if (columnDef.editor){
        var editorArgs = {
          'container':$("body"),  // a dummy container
          'column':columnDef,
          'position':{'top':0, 'left':0},  // a dummy position required by some editors
          'grid':_grid
        };
        var editor = new columnDef.editor(editorArgs);
        editor.loadValue(item);
        editor.applyValue(item, value);
        editor.destroy();
      }
    }

    function _createTextBox(innerText){
      var ta = document.createElement('textarea');
      ta.style.position = 'absolute';
      ta.style.left = '-1000px';
      ta.style.top = document.body.scrollTop + 'px';
      ta.value = innerText;
      _bodyElement.appendChild(ta);
      ta.select();

      return ta;
    }

    function _decodeTabularData(_grid, ta){
      var columns = _grid.getColumns();
      var clipText = ta.value;
      var clipRows = clipText.split(/[\n\f\r]/);
	  // trim trailing CR if present
	  if (clipRows[clipRows.length - 1]=="") { clipRows.pop(); }

      var clippedRange = [];
      var j = 0;

      _bodyElement.removeChild(ta);
      for (var i=0; i<clipRows.length; i++) {
        if (clipRows[i]!="")
          clippedRange[j++] = clipRows[i].split("\t");
          else
          clippedRange[i] = [""];
      }
      var selectedCell = _grid.getActiveCell();
      var ranges = _grid.getSelectionModel().getSelectedRanges();
      var selectedRange = ranges && ranges.length ? ranges[0] : null;   // pick only one selection
      var activeRow = null;
      var activeCell = null;

      if (selectedRange){
        activeRow = selectedRange.fromRow;
        activeCell = selectedRange.fromCell;
      } else if (selectedCell){
        activeRow = selectedCell.row;
        activeCell = selectedCell.cell;
      } else {
        // we don't know where to paste
        return;
      }

      var oneCellToMultiple = false;
      var destH = clippedRange.length;
      var destW = clippedRange.length ? clippedRange[0].length : 0;
      if (clippedRange.length == 1 && clippedRange[0].length == 1 && selectedRange){
        oneCellToMultiple = true;
        destH = selectedRange.toRow - selectedRange.fromRow +1;
        destW = selectedRange.toCell - selectedRange.fromCell +1;
      }
      var availableRows = _grid.getData().length - activeRow;
      var addRows = 0;
      if(availableRows < destH)
      {
        var d = _grid.getData();
        for(addRows = 1; addRows <= destH - availableRows; addRows++)
          d.push({});
        _grid.setData(d);
        _grid.render();
      }

      var overflowsBottomOfGrid = activeRow + destH > _grid.getDataLength();

      if (_options.newRowCreator && overflowsBottomOfGrid) {

        var newRowsNeeded = activeRow + destH - _grid.getDataLength();

        _options.newRowCreator(newRowsNeeded);

      }

      var clipCommand = {

        isClipboardCommand: true,
        clippedRange: clippedRange,
        oldValues: [],
        cellExternalCopyManager: _self,
        _options: _options,
        setDataItemValueForColumn: setDataItemValueForColumn,
        markCopySelection: markCopySelection,
        oneCellToMultiple: oneCellToMultiple,
        activeRow: activeRow,
        activeCell: activeCell,
        destH: destH,
        destW: destW,
        desty: activeRow,
        destx: activeCell,
        maxDestY: _grid.getDataLength(),
        maxDestX: _grid.getColumns().length,
        h: 0,
        w: 0,

        execute: function() {
          this.h=0;
          for (var y = 0; y < destH; y++){
            this.oldValues[y] = [];
            this.w=0;
            this.h++;
            for (var x = 0; x < destW; x++){
              this.w++;
              var desty = activeRow + y;
              var destx = activeCell + x;

              if (desty < this.maxDestY && destx < this.maxDestX ) {
                var nd = _grid.getCellNode(desty, destx);
                var dt = _grid.getDataItem(desty);
                this.oldValues[y][x] = dt[columns[destx]['field']];
                if (oneCellToMultiple)
                  this.setDataItemValueForColumn(dt, columns[destx], clippedRange[0][0]);
                else
                  this.setDataItemValueForColumn(dt, columns[destx], clippedRange[y] ? clippedRange[y][x] : '');
                _grid.updateCell(desty, destx);
                _grid.onCellChange.notify({
                    row: desty,
                    cell: destx,
                    item: dt,
                    grid: _grid
                });

              }
            }
          }

          var bRange = {
            'fromCell': activeCell,
            'fromRow': activeRow,
            'toCell': activeCell+this.w-1,
            'toRow': activeRow+this.h-1
          }

          this.markCopySelection([bRange]);
          _grid.getSelectionModel().setSelectedRanges([bRange]);
          this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});
        },

        undo: function() {
          for (var y = 0; y < destH; y++){
            for (var x = 0; x < destW; x++){
              var desty = activeRow + y;
              var destx = activeCell + x;

              if (desty < this.maxDestY && destx < this.maxDestX ) {
                var nd = _grid.getCellNode(desty, destx);
                var dt = _grid.getDataItem(desty);
                if (oneCellToMultiple)
                  this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[0][0]);
                else
                  this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[y][x]);
                _grid.updateCell(desty, destx);
                _grid.onCellChange.notify({
                    row: desty,
                    cell: destx,
                    item: dt,
                    grid: _grid
                });
              }
            }
          }

          var bRange = {
            'fromCell': activeCell,
            'fromRow': activeRow,
            'toCell': activeCell+this.w-1,
            'toRow': activeRow+this.h-1
          }

          this.markCopySelection([bRange]);
          _grid.getSelectionModel().setSelectedRanges([bRange]);
          this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});

          if(addRows > 1){
            var d = _grid.getData();
            for(; addRows > 1; addRows--)
              d.splice(d.length - 1, 1);
            _grid.setData(d);
            _grid.render();
          }
        }
      };

      if(_options.clipboardCommandHandler) {
        _options.clipboardCommandHandler(clipCommand);
      }
      else {
        clipCommand.execute();
      }
    }

    function handleKeyDown(e, args) {
      var ranges;
      if (!_grid.getEditorLock().isActive() || _grid.getOptions().autoEdit) {
        if (e.which == keyCodes.ESC) {
          if (_copiedRanges) {
            e.preventDefault();
            clearCopySelection();
            _self.onCopyCancelled.notify({ranges: _copiedRanges});
            _copiedRanges = null;
          }
        }

        if ((e.which === keyCodes.C || e.which === keyCodes.INSERT) && (e.ctrlKey || e.metaKey) && !e.shiftKey) {    // CTRL+C or CTRL+INS
          if (_onCopyInit) {
            _onCopyInit.call();
          }
          ranges = _grid.getSelectionModel().getSelectedRanges();
          if (ranges.length != 0) {
            _copiedRanges = ranges;
            markCopySelection(ranges);
            _self.onCopyCells.notify({ranges: ranges});

            var columns = _grid.getColumns();
            var clipText = "";

            for (var rg = 0; rg < ranges.length; rg++){
                var range = ranges[rg];
                var clipTextRows = [];
                for (var i=range.fromRow; i< range.toRow+1 ; i++){
                    var clipTextCells = [];
                    var dt = _grid.getDataItem(i);

                    if (clipTextRows == "" && _options.includeHeaderWhenCopying) {
                        var clipTextHeaders = [];
                        for (var j = range.fromCell; j < range.toCell + 1 ; j++) {
                            if (columns[j].name.length > 0)
                                clipTextHeaders.push(columns[j].name);
                        }
                        clipTextRows.push(clipTextHeaders.join("\t"));
                    }

                    for (var j=range.fromCell; j< range.toCell+1 ; j++){
                        clipTextCells.push(getDataItemValueForColumn(dt, columns[j]));
                    }
                    clipTextRows.push(clipTextCells.join("\t"));
                }
                clipText += clipTextRows.join("\r\n") + "\r\n";
            }

            if(window.clipboardData) {
                window.clipboardData.setData("Text", clipText);
                return true;
            }
            else {
                var $focus = $(_grid.getActiveCellNode());
                var ta = _createTextBox(clipText);

                ta.focus();

                setTimeout(function(){
                     _bodyElement.removeChild(ta);
                    // restore focus
                    if ($focus && $focus.length>0) {
                        $focus.attr('tabIndex', '-1');
                        $focus.focus();
                        $focus.removeAttr('tabIndex');
                    }
                }, 100);

                if (_onCopySuccess) {
                    var rowCount = 0;
                    // If it's cell selection, use the toRow/fromRow fields
                    if (ranges.length === 1) {
                        rowCount = (ranges[0].toRow + 1) - ranges[0].fromRow;
                    }
                    else {
                        rowCount = ranges.length;
                    }
                    _onCopySuccess.call(this, rowCount);
                }

                return false;
            }
          }
        }

        if ((e.which === keyCodes.V && (e.ctrlKey || e.metaKey) && !e.shiftKey || (e.which === keyCodes.INSERT && e.shiftKey && !e.ctrlKey))) {    // CTRL+V or Shift+INS
            var ta = _createTextBox('');

            setTimeout(function(){
                _decodeTabularData(_grid, ta);
            }, 100);

            return false;
        }
      }
    }

    function markCopySelection(ranges) {
      clearCopySelection();

      var columns = _grid.getColumns();
      var hash = {};
      for (var i = 0; i < ranges.length; i++) {
        for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
          hash[j] = {};
          for (var k = ranges[i].fromCell; k <= ranges[i].toCell && k<columns.length; k++) {
            hash[j][columns[k].id] = _copiedCellStyle;
          }
        }
      }
      _grid.setCellCssStyles(_copiedCellStyleLayerKey, hash);
      clearTimeout(_clearCopyTI);
      _clearCopyTI = setTimeout(function(){
        _self.clearCopySelection();
      }, 2000);
    }

    function clearCopySelection() {
      _grid.removeCellCssStyles(_copiedCellStyleLayerKey);
    }

    $.extend(this, {
      "init": init,
      "destroy": destroy,
      "clearCopySelection": clearCopySelection,
      "handleKeyDown":handleKeyDown,

      "onCopyCells": new Slick.Event(),
      "onCopyCancelled": new Slick.Event(),
      "onPasteCells": new Slick.Event()
    });
  }
})(jQuery);
<|endoftext|>


<commit_before>/**
 * Kaching initialization.
 *
 * Intializes Kaching for incoming requests
 *
 * Note that additional middleware is required to persist login state, so we
 * must use the `connect.session()` middleware _before_ `kaching.initialize()`.
 *
 * This middleware must be in use by the Connect/Express application for
 * Kaching to operate.
 *
 * Examples:
 *
 *     app.configure(function() {
 *       app.use(connect.cookieParser());
 *       app.use(connect.session({ secret: 'keyboard cat' }));
 *       app.use(kaching.initialize());
 *     });
 *
 * @return {Function}
 * @api public
 */
module.exports = function() {

  return function initialize(req, res, next) {
    var kaching = this;
    req._kaching = {};
    req._kaching.instance = kaching;

    if (req.session && req.session[kaching._key]) {
      // load data from existing session
      req._kaching.session = req.session[kaching._key];
    } else if (req.session) {
      // initialize new session
      req.session[kaching._key] = {};
      req._kaching.session = req.session[kaching._key];
    } else {
      // no session is available
      req._kaching.session = {};
    }

    next();
  };
};
<commit_msg>Mendatory session support.<commit_after>/**
 * Kaching initialization.
 *
 * Intializes Kaching for incoming requests
 *
 * Note that additional middleware is required to persist login state, so we
 * must use the `connect.session()` middleware _before_ `kaching.initialize()`.
 *
 * This middleware must be in use by the Connect/Express application for
 * Kaching to operate.
 *
 * Examples:
 *
 *     app.configure(function() {
 *       app.use(connect.cookieParser());
 *       app.use(connect.session({ secret: 'keyboard cat' }));
 *       app.use(kaching.initialize());
 *     });
 *
 * @return {Function}
 * @api public
 */
module.exports = function() {

  return function initialize(req, res, next) {
    var kaching = this;
    req._kaching = {};
    req._kaching.instance = kaching;

    if (req.session && req.session[kaching._key]) {
      // load data from existing session
      req._kaching.session = req.session[kaching._key];
    } else if (req.session) {
      // initialize new session
      req.session[kaching._key] = {};
      req._kaching.session = req.session[kaching._key];
    } else {
      // no session is available
      throw new Error('Kaching: Missing session support.');
    }

    next();
  };
};
<|endoftext|>


<commit_before>(function() {
  'use strict';

  angular.module('dimApp').controller('dimMaterialsExchangeCtrl', MaterialsController);

  MaterialsController.$inject = ['$scope', 'dimItemService', 'dimStoreService'];

  function MaterialsController($scope, dimItemService, dimStoreService) {
    var vm = this;

    var materialsHashes = [
      211861343,  // heavy ammo synth
      928169143,  // special ammo synth
      937555249,  // motes of light
      1542293174, // armor materials
      1898539128  // weapon parts
    ];

    var planataryMatsHashes = [
      1797491610, // Helium Filaments
      2882093969, // Spin Metal
      3242866270, // Relic Iron
      2254123540, // Spirit Bloom
      3164836592, // Wormspore
    ];

    var xurMatsHashes = [
      1738186005, // strange coins
      211861343  // heavy ammo synth
    ];

    var variksMatsHashes = [
      3783295803, // Ether Seeds
      211861343  // heavy ammo synth
    ];

    var erisMatsHashes = [
      1043138475, // black wax idol
      211861343  // heavy ammo synth
    ];

    var gunSmithMatsHashes = [
      1898539128  // weapon parts
    ];

    vm.glimmer = dimStoreService.getVault().glimmer;
    vm.xurMats = mapXurItems(xurMatsHashes);
    vm.planataryMats = mapItems(planataryMatsHashes);
    vm.materials = mapItems(materialsHashes);
    vm.variksMats = mapVariksItems(variksMatsHashes);
    vm.erisMats = mapErisItems(erisMatsHashes);
    vm.gunSmithMats = mapGunsmithItems(gunSmithMatsHashes);

    function mapItems(hashes) {
      return hashes.map(function(hash) {
        var ret = angular.copy(dimItemService.getItem({
          hash: hash
        }));
        if (ret) {
          ret.amount = 0;
          dimStoreService.getStores().forEach(function(s) {
            ret.amount += s.amountOfItem(ret);
          });
        }
        return ret;
      }).filter((item) => !_.isUndefined(item));
    }

    function mapXurItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[1].amount = mappedItems[0].amount * 3;
      return mappedItems;
    }

    function mapGunsmithItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[0].amount = Math.floor(vm.glimmer / 250) * 5;
      return mappedItems;
    }

    function mapVariksItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[1].amount = mappedItems[0].amount;
      return mappedItems;
    }

    function mapErisItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[1].amount = Math.floor(mappedItems[0].amount / 5);
      return mappedItems;
    }

    vm.calculateRep = function(item) {
      switch (item.hash) {
      case 211861343:
        return Math.floor(item.amount * 25);       // heavy ammo synth
      case 937555249:
        return Math.floor(item.amount / 5) * 100;  // motes of light
      case 928169143:
        return Math.floor(item.amount / 4) * 25;   // special ammo synth
      case 1542293174: // armor materials
      case 1898539128: // weapon parts
      case 1797491610: // Helium Filaments
      case 2882093969: // Spin Metal
      case 3242866270: // Relic Iron
      case 2254123540: // Spirit Bloom
      case 3164836592: // Wormspore
        return Math.floor(item.amount / 25) * 50;
      default:
        return '?';
      }
    };
  }
})();
<commit_msg>Updated Gunsmith calculation to account for needing 25 parts for 50 rep<commit_after>(function() {
  'use strict';

  angular.module('dimApp').controller('dimMaterialsExchangeCtrl', MaterialsController);

  MaterialsController.$inject = ['$scope', 'dimItemService', 'dimStoreService'];

  function MaterialsController($scope, dimItemService, dimStoreService) {
    var vm = this;

    var materialsHashes = [
      211861343,  // heavy ammo synth
      928169143,  // special ammo synth
      937555249,  // motes of light
      1542293174, // armor materials
      1898539128  // weapon parts
    ];

    var planataryMatsHashes = [
      1797491610, // Helium Filaments
      2882093969, // Spin Metal
      3242866270, // Relic Iron
      2254123540, // Spirit Bloom
      3164836592, // Wormspore
    ];

    var xurMatsHashes = [
      1738186005, // strange coins
      211861343  // heavy ammo synth
    ];

    var variksMatsHashes = [
      3783295803, // Ether Seeds
      211861343  // heavy ammo synth
    ];

    var erisMatsHashes = [
      1043138475, // black wax idol
      211861343  // heavy ammo synth
    ];

    var gunSmithMatsHashes = [
      1898539128  // weapon parts
    ];

    vm.glimmer = dimStoreService.getVault().glimmer;
    vm.xurMats = mapXurItems(xurMatsHashes);
    vm.planataryMats = mapItems(planataryMatsHashes);
    vm.materials = mapItems(materialsHashes);
    vm.variksMats = mapVariksItems(variksMatsHashes);
    vm.erisMats = mapErisItems(erisMatsHashes);
    vm.gunSmithMats = mapGunsmithItems(gunSmithMatsHashes);

    function mapItems(hashes) {
      return hashes.map(function(hash) {
        var ret = angular.copy(dimItemService.getItem({
          hash: hash
        }));
        if (ret) {
          ret.amount = 0;
          dimStoreService.getStores().forEach(function(s) {
            ret.amount += s.amountOfItem(ret);
          });
        }
        return ret;
      }).filter((item) => !_.isUndefined(item));
    }

    function mapXurItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[1].amount = mappedItems[0].amount * 3;
      return mappedItems;
    }

    function mapGunsmithItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[0].amount = Math.floor(vm.glimmer / 1250) * 25;
      return mappedItems;
    }

    function mapVariksItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[1].amount = mappedItems[0].amount;
      return mappedItems;
    }

    function mapErisItems(hashes) {
      var mappedItems = mapItems(hashes);
      mappedItems[1].amount = Math.floor(mappedItems[0].amount / 5);
      return mappedItems;
    }

    vm.calculateRep = function(item) {
      switch (item.hash) {
      case 211861343:
        return Math.floor(item.amount * 25);       // heavy ammo synth
      case 937555249:
        return Math.floor(item.amount / 5) * 100;  // motes of light
      case 928169143:
        return Math.floor(item.amount / 4) * 25;   // special ammo synth
      case 1542293174: // armor materials
      case 1898539128: // weapon parts
      case 1797491610: // Helium Filaments
      case 2882093969: // Spin Metal
      case 3242866270: // Relic Iron
      case 2254123540: // Spirit Bloom
      case 3164836592: // Wormspore
        return Math.floor(item.amount / 25) * 50;
      default:
        return '?';
      }
    };
  }
})();
<|endoftext|>